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 "qemu/osdep.h"
26 #include <CoreAudio/CoreAudio.h>
27 #include <pthread.h> /* pthread_X */
29 #include "qemu-common.h"
32 #define AUDIO_CAP "coreaudio"
33 #include "audio_int.h"
35 #ifndef MAC_OS_X_VERSION_10_6
36 #define MAC_OS_X_VERSION_10_6 1060
46 typedef struct coreaudioVoiceOut {
48 pthread_mutex_t mutex;
49 AudioDeviceID outputDeviceID;
50 UInt32 audioDevicePropertyBufferFrameSize;
51 AudioStreamBasicDescription outputStreamBasicDescription;
52 AudioDeviceIOProcID ioprocid;
58 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
59 /* The APIs used here only become available from 10.6 */
61 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
63 UInt32 size = sizeof(*id);
64 AudioObjectPropertyAddress addr = {
65 kAudioHardwarePropertyDefaultOutputDevice,
66 kAudioObjectPropertyScopeGlobal,
67 kAudioObjectPropertyElementMaster
70 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
78 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
79 AudioValueRange *framerange)
81 UInt32 size = sizeof(*framerange);
82 AudioObjectPropertyAddress addr = {
83 kAudioDevicePropertyBufferFrameSizeRange,
84 kAudioDevicePropertyScopeOutput,
85 kAudioObjectPropertyElementMaster
88 return AudioObjectGetPropertyData(id,
96 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
98 UInt32 size = sizeof(*framesize);
99 AudioObjectPropertyAddress addr = {
100 kAudioDevicePropertyBufferFrameSize,
101 kAudioDevicePropertyScopeOutput,
102 kAudioObjectPropertyElementMaster
105 return AudioObjectGetPropertyData(id,
113 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
115 UInt32 size = sizeof(*framesize);
116 AudioObjectPropertyAddress addr = {
117 kAudioDevicePropertyBufferFrameSize,
118 kAudioDevicePropertyScopeOutput,
119 kAudioObjectPropertyElementMaster
122 return AudioObjectSetPropertyData(id,
130 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
131 AudioStreamBasicDescription *d)
133 UInt32 size = sizeof(*d);
134 AudioObjectPropertyAddress addr = {
135 kAudioDevicePropertyStreamFormat,
136 kAudioDevicePropertyScopeOutput,
137 kAudioObjectPropertyElementMaster
140 return AudioObjectGetPropertyData(id,
148 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
149 AudioStreamBasicDescription *d)
151 UInt32 size = sizeof(*d);
152 AudioObjectPropertyAddress addr = {
153 kAudioDevicePropertyStreamFormat,
154 kAudioDevicePropertyScopeOutput,
155 kAudioObjectPropertyElementMaster
158 return AudioObjectSetPropertyData(id,
166 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
168 UInt32 size = sizeof(*result);
169 AudioObjectPropertyAddress addr = {
170 kAudioDevicePropertyDeviceIsRunning,
171 kAudioDevicePropertyScopeOutput,
172 kAudioObjectPropertyElementMaster
175 return AudioObjectGetPropertyData(id,
183 /* Legacy versions of functions using deprecated APIs */
185 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
187 UInt32 size = sizeof(*id);
189 return AudioHardwareGetProperty(
190 kAudioHardwarePropertyDefaultOutputDevice,
195 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
196 AudioValueRange *framerange)
198 UInt32 size = sizeof(*framerange);
200 return AudioDeviceGetProperty(
204 kAudioDevicePropertyBufferFrameSizeRange,
209 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
211 UInt32 size = sizeof(*framesize);
213 return AudioDeviceGetProperty(
217 kAudioDevicePropertyBufferFrameSize,
222 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
224 UInt32 size = sizeof(*framesize);
226 return AudioDeviceSetProperty(
231 kAudioDevicePropertyBufferFrameSize,
236 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
237 AudioStreamBasicDescription *d)
239 UInt32 size = sizeof(*d);
241 return AudioDeviceGetProperty(
245 kAudioDevicePropertyStreamFormat,
250 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
251 AudioStreamBasicDescription *d)
253 UInt32 size = sizeof(*d);
255 return AudioDeviceSetProperty(
260 kAudioDevicePropertyStreamFormat,
265 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
267 UInt32 size = sizeof(*result);
269 return AudioDeviceGetProperty(
273 kAudioDevicePropertyDeviceIsRunning,
279 static void coreaudio_logstatus (OSStatus status)
281 const char *str = "BUG";
284 case kAudioHardwareNoError:
285 str = "kAudioHardwareNoError";
288 case kAudioHardwareNotRunningError:
289 str = "kAudioHardwareNotRunningError";
292 case kAudioHardwareUnspecifiedError:
293 str = "kAudioHardwareUnspecifiedError";
296 case kAudioHardwareUnknownPropertyError:
297 str = "kAudioHardwareUnknownPropertyError";
300 case kAudioHardwareBadPropertySizeError:
301 str = "kAudioHardwareBadPropertySizeError";
304 case kAudioHardwareIllegalOperationError:
305 str = "kAudioHardwareIllegalOperationError";
308 case kAudioHardwareBadDeviceError:
309 str = "kAudioHardwareBadDeviceError";
312 case kAudioHardwareBadStreamError:
313 str = "kAudioHardwareBadStreamError";
316 case kAudioHardwareUnsupportedOperationError:
317 str = "kAudioHardwareUnsupportedOperationError";
320 case kAudioDeviceUnsupportedFormatError:
321 str = "kAudioDeviceUnsupportedFormatError";
324 case kAudioDevicePermissionsError:
325 str = "kAudioDevicePermissionsError";
329 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
333 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
336 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
345 AUD_log (AUDIO_CAP, fmt, ap);
348 coreaudio_logstatus (status);
351 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
360 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
363 AUD_vlog (AUDIO_CAP, fmt, ap);
366 coreaudio_logstatus (status);
369 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
373 status = coreaudio_get_isrunning(outputDeviceID, &result);
374 if (status != kAudioHardwareNoError) {
375 coreaudio_logerr(status,
376 "Could not determine whether Device is playing\n");
381 static void coreaudio_atexit (void)
386 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
390 err = pthread_mutex_lock (&core->mutex);
392 dolog ("Could not lock voice for %s\nReason: %s\n",
393 fn_name, strerror (err));
399 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
403 err = pthread_mutex_unlock (&core->mutex);
405 dolog ("Could not unlock voice for %s\nReason: %s\n",
406 fn_name, strerror (err));
412 static int coreaudio_run_out (HWVoiceOut *hw, int live)
415 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
417 if (coreaudio_lock (core, "coreaudio_run_out")) {
421 if (core->decr > live) {
422 ldebug ("core->decr %d live %d core->live %d\n",
428 decr = audio_MIN (core->decr, live);
431 core->live = live - decr;
432 hw->rpos = core->rpos;
434 coreaudio_unlock (core, "coreaudio_run_out");
438 /* callback to feed audiooutput buffer */
439 static OSStatus audioDeviceIOProc(
440 AudioDeviceID inDevice,
441 const AudioTimeStamp* inNow,
442 const AudioBufferList* inInputData,
443 const AudioTimeStamp* inInputTime,
444 AudioBufferList* outOutputData,
445 const AudioTimeStamp* inOutputTime,
448 UInt32 frame, frameCount;
449 float *out = outOutputData->mBuffers[0].mData;
450 HWVoiceOut *hw = hwptr;
451 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
453 struct st_sample *src;
456 const float scale = 1.f / UINT_MAX;
458 const float scale = UINT_MAX;
462 if (coreaudio_lock (core, "audioDeviceIOProc")) {
467 frameCount = core->audioDevicePropertyBufferFrameSize;
470 /* if there are not enough samples, set signal and return */
471 if (live < frameCount) {
473 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
478 src = hw->mix_buf + rpos;
481 for (frame = 0; frame < frameCount; frame++) {
483 *out++ = src[frame].l; /* left channel */
484 *out++ = src[frame].r; /* right channel */
487 *out++ = src[frame].l * scale; /* left channel */
488 *out++ = src[frame].r * scale; /* right channel */
490 *out++ = src[frame].l / scale; /* left channel */
491 *out++ = src[frame].r / scale; /* right channel */
496 rpos = (rpos + frameCount) % hw->samples;
497 core->decr += frameCount;
500 coreaudio_unlock (core, "audioDeviceIOProc");
504 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
506 return audio_pcm_sw_write (sw, buf, len);
509 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
513 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
515 const char *typ = "playback";
516 AudioValueRange frameRange;
517 CoreaudioConf *conf = drv_opaque;
520 err = pthread_mutex_init(&core->mutex, NULL);
522 dolog("Could not create mutex\nReason: %s\n", strerror (err));
526 audio_pcm_init_info (&hw->info, as);
528 status = coreaudio_get_voice(&core->outputDeviceID);
529 if (status != kAudioHardwareNoError) {
530 coreaudio_logerr2 (status, typ,
531 "Could not get default output Device\n");
534 if (core->outputDeviceID == kAudioDeviceUnknown) {
535 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
539 /* get minimum and maximum buffer frame sizes */
540 status = coreaudio_get_framesizerange(core->outputDeviceID,
542 if (status != kAudioHardwareNoError) {
543 coreaudio_logerr2 (status, typ,
544 "Could not get device buffer frame range\n");
548 if (frameRange.mMinimum > conf->buffer_frames) {
549 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
550 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
552 else if (frameRange.mMaximum < conf->buffer_frames) {
553 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
554 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
557 core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
560 /* set Buffer Frame Size */
561 status = coreaudio_set_framesize(core->outputDeviceID,
562 &core->audioDevicePropertyBufferFrameSize);
563 if (status != kAudioHardwareNoError) {
564 coreaudio_logerr2 (status, typ,
565 "Could not set device buffer frame size %" PRIu32 "\n",
566 (uint32_t)core->audioDevicePropertyBufferFrameSize);
570 /* get Buffer Frame Size */
571 status = coreaudio_get_framesize(core->outputDeviceID,
572 &core->audioDevicePropertyBufferFrameSize);
573 if (status != kAudioHardwareNoError) {
574 coreaudio_logerr2 (status, typ,
575 "Could not get device buffer frame size\n");
578 hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
580 /* get StreamFormat */
581 status = coreaudio_get_streamformat(core->outputDeviceID,
582 &core->outputStreamBasicDescription);
583 if (status != kAudioHardwareNoError) {
584 coreaudio_logerr2 (status, typ,
585 "Could not get Device Stream properties\n");
586 core->outputDeviceID = kAudioDeviceUnknown;
591 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
592 status = coreaudio_set_streamformat(core->outputDeviceID,
593 &core->outputStreamBasicDescription);
594 if (status != kAudioHardwareNoError) {
595 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
597 core->outputDeviceID = kAudioDeviceUnknown;
602 core->ioprocid = NULL;
603 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
607 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
608 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
609 core->outputDeviceID = kAudioDeviceUnknown;
614 if (!isPlaying(core->outputDeviceID)) {
615 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
616 if (status != kAudioHardwareNoError) {
617 coreaudio_logerr2 (status, typ, "Could not start playback\n");
618 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
619 core->outputDeviceID = kAudioDeviceUnknown;
627 static void coreaudio_fini_out (HWVoiceOut *hw)
631 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
635 if (isPlaying(core->outputDeviceID)) {
636 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
637 if (status != kAudioHardwareNoError) {
638 coreaudio_logerr (status, "Could not stop playback\n");
642 /* remove callback */
643 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
645 if (status != kAudioHardwareNoError) {
646 coreaudio_logerr (status, "Could not remove IOProc\n");
649 core->outputDeviceID = kAudioDeviceUnknown;
652 err = pthread_mutex_destroy(&core->mutex);
654 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
658 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
661 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
666 if (!isPlaying(core->outputDeviceID)) {
667 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
668 if (status != kAudioHardwareNoError) {
669 coreaudio_logerr (status, "Could not resume playback\n");
677 if (isPlaying(core->outputDeviceID)) {
678 status = AudioDeviceStop(core->outputDeviceID,
680 if (status != kAudioHardwareNoError) {
681 coreaudio_logerr (status, "Could not pause playback\n");
690 static CoreaudioConf glob_conf = {
691 .buffer_frames = 512,
695 static void *coreaudio_audio_init (void)
697 CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
700 atexit(coreaudio_atexit);
704 static void coreaudio_audio_fini (void *opaque)
709 static struct audio_option coreaudio_options[] = {
711 .name = "BUFFER_SIZE",
713 .valp = &glob_conf.buffer_frames,
714 .descr = "Size of the buffer in frames"
717 .name = "BUFFER_COUNT",
719 .valp = &glob_conf.nbuffers,
720 .descr = "Number of buffers"
722 { /* End of list */ }
725 static struct audio_pcm_ops coreaudio_pcm_ops = {
726 .init_out = coreaudio_init_out,
727 .fini_out = coreaudio_fini_out,
728 .run_out = coreaudio_run_out,
729 .write = coreaudio_write,
730 .ctl_out = coreaudio_ctl_out
733 struct audio_driver coreaudio_audio_driver = {
735 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
736 .options = coreaudio_options,
737 .init = coreaudio_audio_init,
738 .fini = coreaudio_audio_fini,
739 .pcm_ops = &coreaudio_pcm_ops,
743 .voice_size_out = sizeof (coreaudioVoiceOut),