2 * QEMU OS X CoreAudio audio driver
4 * Copyright (c) 2005 Mike Kronenberg
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include <CoreAudio/CoreAudio.h>
26 #include <string.h> /* strerror */
27 #include <pthread.h> /* pthread_X */
29 #include "qemu-common.h"
32 #define AUDIO_CAP "coreaudio"
33 #include "audio_int.h"
45 typedef struct coreaudioVoiceOut {
47 pthread_mutex_t mutex;
49 AudioDeviceID outputDeviceID;
50 #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
51 AudioDeviceIOProcID ioProcID;
53 UInt32 audioDevicePropertyBufferFrameSize;
54 AudioStreamBasicDescription outputStreamBasicDescription;
60 static void coreaudio_logstatus (OSStatus status)
62 const char *str = "BUG";
65 case kAudioHardwareNoError:
66 str = "kAudioHardwareNoError";
69 case kAudioHardwareNotRunningError:
70 str = "kAudioHardwareNotRunningError";
73 case kAudioHardwareUnspecifiedError:
74 str = "kAudioHardwareUnspecifiedError";
77 case kAudioHardwareUnknownPropertyError:
78 str = "kAudioHardwareUnknownPropertyError";
81 case kAudioHardwareBadPropertySizeError:
82 str = "kAudioHardwareBadPropertySizeError";
85 case kAudioHardwareIllegalOperationError:
86 str = "kAudioHardwareIllegalOperationError";
89 case kAudioHardwareBadDeviceError:
90 str = "kAudioHardwareBadDeviceError";
93 case kAudioHardwareBadStreamError:
94 str = "kAudioHardwareBadStreamError";
97 case kAudioHardwareUnsupportedOperationError:
98 str = "kAudioHardwareUnsupportedOperationError";
101 case kAudioDeviceUnsupportedFormatError:
102 str = "kAudioDeviceUnsupportedFormatError";
105 case kAudioDevicePermissionsError:
106 str = "kAudioDevicePermissionsError";
110 AUD_log (AUDIO_CAP, "Reason: status code %d\n", status);
114 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
117 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
126 AUD_log (AUDIO_CAP, fmt, ap);
129 coreaudio_logstatus (status);
132 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
141 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
144 AUD_vlog (AUDIO_CAP, fmt, ap);
147 coreaudio_logstatus (status);
150 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
154 UInt32 propertySize = sizeof(outputDeviceID);
155 status = AudioDeviceGetProperty(
156 outputDeviceID, 0, 0,
157 kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
158 if (status != kAudioHardwareNoError) {
159 coreaudio_logerr(status,
160 "Could not determine whether Device is playing\n");
165 static void coreaudio_atexit (void)
170 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
174 err = pthread_mutex_lock (&core->mutex);
176 dolog ("Could not lock voice for %s\nReason: %s\n",
177 fn_name, strerror (err));
183 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
187 err = pthread_mutex_unlock (&core->mutex);
189 dolog ("Could not unlock voice for %s\nReason: %s\n",
190 fn_name, strerror (err));
196 static int coreaudio_run_out (HWVoiceOut *hw)
199 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
201 if (coreaudio_lock (core, "coreaudio_run_out")) {
205 live = audio_pcm_hw_get_live_out (hw);
207 if (core->decr > live) {
208 ldebug ("core->decr %d live %d core->live %d\n",
214 decr = audio_MIN (core->decr, live);
217 core->live = live - decr;
218 hw->rpos = core->rpos;
220 coreaudio_unlock (core, "coreaudio_run_out");
224 /* callback to feed audiooutput buffer */
225 static OSStatus audioDeviceIOProc(
226 AudioDeviceID inDevice,
227 const AudioTimeStamp* inNow,
228 const AudioBufferList* inInputData,
229 const AudioTimeStamp* inInputTime,
230 AudioBufferList* outOutputData,
231 const AudioTimeStamp* inOutputTime,
234 UInt32 frame, frameCount;
235 float *out = outOutputData->mBuffers[0].mData;
236 HWVoiceOut *hw = hwptr;
237 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
239 struct st_sample *src;
242 const float scale = 1.f / UINT_MAX;
244 const float scale = UINT_MAX;
248 if (coreaudio_lock (core, "audioDeviceIOProc")) {
253 frameCount = core->audioDevicePropertyBufferFrameSize;
256 /* if there are not enough samples, set signal and return */
257 if (live < frameCount) {
259 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
264 src = hw->mix_buf + rpos;
267 for (frame = 0; frame < frameCount; frame++) {
269 *out++ = src[frame].l; /* left channel */
270 *out++ = src[frame].r; /* right channel */
273 *out++ = src[frame].l * scale; /* left channel */
274 *out++ = src[frame].r * scale; /* right channel */
276 *out++ = src[frame].l / scale; /* left channel */
277 *out++ = src[frame].r / scale; /* right channel */
282 rpos = (rpos + frameCount) % hw->samples;
283 core->decr += frameCount;
286 coreaudio_unlock (core, "audioDeviceIOProc");
290 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
292 return audio_pcm_sw_write (sw, buf, len);
295 static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
298 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
301 const char *typ = "playback";
302 AudioValueRange frameRange;
305 err = pthread_mutex_init(&core->mutex, NULL);
307 dolog("Could not create mutex\nReason: %s\n", strerror (err));
311 audio_pcm_init_info (&hw->info, as);
313 /* open default output device */
314 propertySize = sizeof(core->outputDeviceID);
315 status = AudioHardwareGetProperty(
316 kAudioHardwarePropertyDefaultOutputDevice,
318 &core->outputDeviceID);
319 if (status != kAudioHardwareNoError) {
320 coreaudio_logerr2 (status, typ,
321 "Could not get default output Device\n");
324 if (core->outputDeviceID == kAudioDeviceUnknown) {
325 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
329 /* get minimum and maximum buffer frame sizes */
330 propertySize = sizeof(frameRange);
331 status = AudioDeviceGetProperty(
332 core->outputDeviceID,
335 kAudioDevicePropertyBufferFrameSizeRange,
338 if (status != kAudioHardwareNoError) {
339 coreaudio_logerr2 (status, typ,
340 "Could not get device buffer frame range\n");
344 if (frameRange.mMinimum > conf.buffer_frames) {
345 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
346 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
348 else if (frameRange.mMaximum < conf.buffer_frames) {
349 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
350 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
353 core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
356 /* set Buffer Frame Size */
357 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
358 status = AudioDeviceSetProperty(
359 core->outputDeviceID,
363 kAudioDevicePropertyBufferFrameSize,
365 &core->audioDevicePropertyBufferFrameSize);
366 if (status != kAudioHardwareNoError) {
367 coreaudio_logerr2 (status, typ,
368 "Could not set device buffer frame size %d\n",
369 core->audioDevicePropertyBufferFrameSize);
373 /* get Buffer Frame Size */
374 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
375 status = AudioDeviceGetProperty(
376 core->outputDeviceID,
379 kAudioDevicePropertyBufferFrameSize,
381 &core->audioDevicePropertyBufferFrameSize);
382 if (status != kAudioHardwareNoError) {
383 coreaudio_logerr2 (status, typ,
384 "Could not get device buffer frame size\n");
387 hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
389 /* get StreamFormat */
390 propertySize = sizeof(core->outputStreamBasicDescription);
391 status = AudioDeviceGetProperty(
392 core->outputDeviceID,
395 kAudioDevicePropertyStreamFormat,
397 &core->outputStreamBasicDescription);
398 if (status != kAudioHardwareNoError) {
399 coreaudio_logerr2 (status, typ,
400 "Could not get Device Stream properties\n");
401 core->outputDeviceID = kAudioDeviceUnknown;
406 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
407 propertySize = sizeof(core->outputStreamBasicDescription);
408 status = AudioDeviceSetProperty(
409 core->outputDeviceID,
413 kAudioDevicePropertyStreamFormat,
415 &core->outputStreamBasicDescription);
416 if (status != kAudioHardwareNoError) {
417 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
419 core->outputDeviceID = kAudioDeviceUnknown;
424 #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
425 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
430 status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
432 if (status != kAudioHardwareNoError) {
433 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
434 core->outputDeviceID = kAudioDeviceUnknown;
439 if (!isPlaying(core->outputDeviceID)) {
440 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
441 if (status != kAudioHardwareNoError) {
442 coreaudio_logerr2 (status, typ, "Could not start playback\n");
443 #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
444 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioProcID);
446 AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
448 core->outputDeviceID = kAudioDeviceUnknown;
456 static void coreaudio_fini_out (HWVoiceOut *hw)
460 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
462 if (!conf.isAtexit) {
464 if (isPlaying(core->outputDeviceID)) {
465 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
466 if (status != kAudioHardwareNoError) {
467 coreaudio_logerr (status, "Could not stop playback\n");
471 /* remove callback */
472 #if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MIN_REQUIRED>=MAC_OS_X_VERSION_10_5)
473 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
476 status = AudioDeviceRemoveIOProc(core->outputDeviceID,
479 if (status != kAudioHardwareNoError) {
480 coreaudio_logerr (status, "Could not remove IOProc\n");
483 core->outputDeviceID = kAudioDeviceUnknown;
486 err = pthread_mutex_destroy(&core->mutex);
488 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
492 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
495 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
500 if (!isPlaying(core->outputDeviceID)) {
501 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
502 if (status != kAudioHardwareNoError) {
503 coreaudio_logerr (status, "Could not resume playback\n");
510 if (!conf.isAtexit) {
511 if (isPlaying(core->outputDeviceID)) {
512 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
513 if (status != kAudioHardwareNoError) {
514 coreaudio_logerr (status, "Could not pause playback\n");
523 static void *coreaudio_audio_init (void)
525 atexit(coreaudio_atexit);
526 return &coreaudio_audio_init;
529 static void coreaudio_audio_fini (void *opaque)
534 static struct audio_option coreaudio_options[] = {
535 {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
536 "Size of the buffer in frames", NULL, 0},
537 {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
538 "Number of buffers", NULL, 0},
539 {NULL, 0, NULL, NULL, NULL, 0}
542 static struct audio_pcm_ops coreaudio_pcm_ops = {
556 struct audio_driver coreaudio_audio_driver = {
557 INIT_FIELD (name = ) "coreaudio",
558 INIT_FIELD (descr = )
559 "CoreAudio http://developer.apple.com/audio/coreaudio.html",
560 INIT_FIELD (options = ) coreaudio_options,
561 INIT_FIELD (init = ) coreaudio_audio_init,
562 INIT_FIELD (fini = ) coreaudio_audio_fini,
563 INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
564 INIT_FIELD (can_be_default = ) 1,
565 INIT_FIELD (max_voices_out = ) 1,
566 INIT_FIELD (max_voices_in = ) 0,
567 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
568 INIT_FIELD (voice_size_in = ) 0