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
44 typedef struct coreaudioVoiceOut {
46 pthread_mutex_t mutex;
47 AudioDeviceID outputDeviceID;
48 UInt32 audioDevicePropertyBufferFrameSize;
49 AudioStreamBasicDescription outputStreamBasicDescription;
50 AudioDeviceIOProcID ioprocid;
56 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
57 /* The APIs used here only become available from 10.6 */
59 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
61 UInt32 size = sizeof(*id);
62 AudioObjectPropertyAddress addr = {
63 kAudioHardwarePropertyDefaultOutputDevice,
64 kAudioObjectPropertyScopeGlobal,
65 kAudioObjectPropertyElementMaster
68 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
76 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
77 AudioValueRange *framerange)
79 UInt32 size = sizeof(*framerange);
80 AudioObjectPropertyAddress addr = {
81 kAudioDevicePropertyBufferFrameSizeRange,
82 kAudioDevicePropertyScopeOutput,
83 kAudioObjectPropertyElementMaster
86 return AudioObjectGetPropertyData(id,
94 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
96 UInt32 size = sizeof(*framesize);
97 AudioObjectPropertyAddress addr = {
98 kAudioDevicePropertyBufferFrameSize,
99 kAudioDevicePropertyScopeOutput,
100 kAudioObjectPropertyElementMaster
103 return AudioObjectGetPropertyData(id,
111 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
113 UInt32 size = sizeof(*framesize);
114 AudioObjectPropertyAddress addr = {
115 kAudioDevicePropertyBufferFrameSize,
116 kAudioDevicePropertyScopeOutput,
117 kAudioObjectPropertyElementMaster
120 return AudioObjectSetPropertyData(id,
128 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
129 AudioStreamBasicDescription *d)
131 UInt32 size = sizeof(*d);
132 AudioObjectPropertyAddress addr = {
133 kAudioDevicePropertyStreamFormat,
134 kAudioDevicePropertyScopeOutput,
135 kAudioObjectPropertyElementMaster
138 return AudioObjectGetPropertyData(id,
146 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
147 AudioStreamBasicDescription *d)
149 UInt32 size = sizeof(*d);
150 AudioObjectPropertyAddress addr = {
151 kAudioDevicePropertyStreamFormat,
152 kAudioDevicePropertyScopeOutput,
153 kAudioObjectPropertyElementMaster
156 return AudioObjectSetPropertyData(id,
164 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
166 UInt32 size = sizeof(*result);
167 AudioObjectPropertyAddress addr = {
168 kAudioDevicePropertyDeviceIsRunning,
169 kAudioDevicePropertyScopeOutput,
170 kAudioObjectPropertyElementMaster
173 return AudioObjectGetPropertyData(id,
181 /* Legacy versions of functions using deprecated APIs */
183 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
185 UInt32 size = sizeof(*id);
187 return AudioHardwareGetProperty(
188 kAudioHardwarePropertyDefaultOutputDevice,
193 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
194 AudioValueRange *framerange)
196 UInt32 size = sizeof(*framerange);
198 return AudioDeviceGetProperty(
202 kAudioDevicePropertyBufferFrameSizeRange,
207 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
209 UInt32 size = sizeof(*framesize);
211 return AudioDeviceGetProperty(
215 kAudioDevicePropertyBufferFrameSize,
220 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
222 UInt32 size = sizeof(*framesize);
224 return AudioDeviceSetProperty(
229 kAudioDevicePropertyBufferFrameSize,
234 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
235 AudioStreamBasicDescription *d)
237 UInt32 size = sizeof(*d);
239 return AudioDeviceGetProperty(
243 kAudioDevicePropertyStreamFormat,
248 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
249 AudioStreamBasicDescription *d)
251 UInt32 size = sizeof(*d);
253 return AudioDeviceSetProperty(
258 kAudioDevicePropertyStreamFormat,
263 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
265 UInt32 size = sizeof(*result);
267 return AudioDeviceGetProperty(
271 kAudioDevicePropertyDeviceIsRunning,
277 static void coreaudio_logstatus (OSStatus status)
279 const char *str = "BUG";
282 case kAudioHardwareNoError:
283 str = "kAudioHardwareNoError";
286 case kAudioHardwareNotRunningError:
287 str = "kAudioHardwareNotRunningError";
290 case kAudioHardwareUnspecifiedError:
291 str = "kAudioHardwareUnspecifiedError";
294 case kAudioHardwareUnknownPropertyError:
295 str = "kAudioHardwareUnknownPropertyError";
298 case kAudioHardwareBadPropertySizeError:
299 str = "kAudioHardwareBadPropertySizeError";
302 case kAudioHardwareIllegalOperationError:
303 str = "kAudioHardwareIllegalOperationError";
306 case kAudioHardwareBadDeviceError:
307 str = "kAudioHardwareBadDeviceError";
310 case kAudioHardwareBadStreamError:
311 str = "kAudioHardwareBadStreamError";
314 case kAudioHardwareUnsupportedOperationError:
315 str = "kAudioHardwareUnsupportedOperationError";
318 case kAudioDeviceUnsupportedFormatError:
319 str = "kAudioDeviceUnsupportedFormatError";
322 case kAudioDevicePermissionsError:
323 str = "kAudioDevicePermissionsError";
327 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
331 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
334 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
343 AUD_log (AUDIO_CAP, fmt, ap);
346 coreaudio_logstatus (status);
349 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
358 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
361 AUD_vlog (AUDIO_CAP, fmt, ap);
364 coreaudio_logstatus (status);
367 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
371 status = coreaudio_get_isrunning(outputDeviceID, &result);
372 if (status != kAudioHardwareNoError) {
373 coreaudio_logerr(status,
374 "Could not determine whether Device is playing\n");
379 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
383 err = pthread_mutex_lock (&core->mutex);
385 dolog ("Could not lock voice for %s\nReason: %s\n",
386 fn_name, strerror (err));
392 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
396 err = pthread_mutex_unlock (&core->mutex);
398 dolog ("Could not unlock voice for %s\nReason: %s\n",
399 fn_name, strerror (err));
405 static int coreaudio_run_out (HWVoiceOut *hw, int live)
408 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
410 if (coreaudio_lock (core, "coreaudio_run_out")) {
414 if (core->decr > live) {
415 ldebug ("core->decr %d live %d core->live %d\n",
421 decr = audio_MIN (core->decr, live);
424 core->live = live - decr;
425 hw->rpos = core->rpos;
427 coreaudio_unlock (core, "coreaudio_run_out");
431 /* callback to feed audiooutput buffer */
432 static OSStatus audioDeviceIOProc(
433 AudioDeviceID inDevice,
434 const AudioTimeStamp* inNow,
435 const AudioBufferList* inInputData,
436 const AudioTimeStamp* inInputTime,
437 AudioBufferList* outOutputData,
438 const AudioTimeStamp* inOutputTime,
441 UInt32 frame, frameCount;
442 float *out = outOutputData->mBuffers[0].mData;
443 HWVoiceOut *hw = hwptr;
444 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
446 struct st_sample *src;
449 const float scale = 1.f / UINT_MAX;
451 const float scale = UINT_MAX;
455 if (coreaudio_lock (core, "audioDeviceIOProc")) {
460 frameCount = core->audioDevicePropertyBufferFrameSize;
463 /* if there are not enough samples, set signal and return */
464 if (live < frameCount) {
466 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
471 src = hw->mix_buf + rpos;
474 for (frame = 0; frame < frameCount; frame++) {
476 *out++ = src[frame].l; /* left channel */
477 *out++ = src[frame].r; /* right channel */
480 *out++ = src[frame].l * scale; /* left channel */
481 *out++ = src[frame].r * scale; /* right channel */
483 *out++ = src[frame].l / scale; /* left channel */
484 *out++ = src[frame].r / scale; /* right channel */
489 rpos = (rpos + frameCount) % hw->samples;
490 core->decr += frameCount;
493 coreaudio_unlock (core, "audioDeviceIOProc");
497 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
499 return audio_pcm_sw_write (sw, buf, len);
502 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
506 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
508 const char *typ = "playback";
509 AudioValueRange frameRange;
510 CoreaudioConf *conf = drv_opaque;
513 err = pthread_mutex_init(&core->mutex, NULL);
515 dolog("Could not create mutex\nReason: %s\n", strerror (err));
519 audio_pcm_init_info (&hw->info, as);
521 status = coreaudio_get_voice(&core->outputDeviceID);
522 if (status != kAudioHardwareNoError) {
523 coreaudio_logerr2 (status, typ,
524 "Could not get default output Device\n");
527 if (core->outputDeviceID == kAudioDeviceUnknown) {
528 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
532 /* get minimum and maximum buffer frame sizes */
533 status = coreaudio_get_framesizerange(core->outputDeviceID,
535 if (status != kAudioHardwareNoError) {
536 coreaudio_logerr2 (status, typ,
537 "Could not get device buffer frame range\n");
541 if (frameRange.mMinimum > conf->buffer_frames) {
542 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
543 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
545 else if (frameRange.mMaximum < conf->buffer_frames) {
546 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
547 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
550 core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
553 /* set Buffer Frame Size */
554 status = coreaudio_set_framesize(core->outputDeviceID,
555 &core->audioDevicePropertyBufferFrameSize);
556 if (status != kAudioHardwareNoError) {
557 coreaudio_logerr2 (status, typ,
558 "Could not set device buffer frame size %" PRIu32 "\n",
559 (uint32_t)core->audioDevicePropertyBufferFrameSize);
563 /* get Buffer Frame Size */
564 status = coreaudio_get_framesize(core->outputDeviceID,
565 &core->audioDevicePropertyBufferFrameSize);
566 if (status != kAudioHardwareNoError) {
567 coreaudio_logerr2 (status, typ,
568 "Could not get device buffer frame size\n");
571 hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
573 /* get StreamFormat */
574 status = coreaudio_get_streamformat(core->outputDeviceID,
575 &core->outputStreamBasicDescription);
576 if (status != kAudioHardwareNoError) {
577 coreaudio_logerr2 (status, typ,
578 "Could not get Device Stream properties\n");
579 core->outputDeviceID = kAudioDeviceUnknown;
584 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
585 status = coreaudio_set_streamformat(core->outputDeviceID,
586 &core->outputStreamBasicDescription);
587 if (status != kAudioHardwareNoError) {
588 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
590 core->outputDeviceID = kAudioDeviceUnknown;
595 core->ioprocid = NULL;
596 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
600 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
601 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
602 core->outputDeviceID = kAudioDeviceUnknown;
607 if (!isPlaying(core->outputDeviceID)) {
608 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
609 if (status != kAudioHardwareNoError) {
610 coreaudio_logerr2 (status, typ, "Could not start playback\n");
611 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
612 core->outputDeviceID = kAudioDeviceUnknown;
620 static void coreaudio_fini_out (HWVoiceOut *hw)
624 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
626 if (!audio_is_cleaning_up()) {
628 if (isPlaying(core->outputDeviceID)) {
629 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
630 if (status != kAudioHardwareNoError) {
631 coreaudio_logerr (status, "Could not stop playback\n");
635 /* remove callback */
636 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
638 if (status != kAudioHardwareNoError) {
639 coreaudio_logerr (status, "Could not remove IOProc\n");
642 core->outputDeviceID = kAudioDeviceUnknown;
645 err = pthread_mutex_destroy(&core->mutex);
647 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
651 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
654 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
659 if (!isPlaying(core->outputDeviceID)) {
660 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
661 if (status != kAudioHardwareNoError) {
662 coreaudio_logerr (status, "Could not resume playback\n");
669 if (!audio_is_cleaning_up()) {
670 if (isPlaying(core->outputDeviceID)) {
671 status = AudioDeviceStop(core->outputDeviceID,
673 if (status != kAudioHardwareNoError) {
674 coreaudio_logerr (status, "Could not pause playback\n");
683 static CoreaudioConf glob_conf = {
684 .buffer_frames = 512,
688 static void *coreaudio_audio_init (void)
690 CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
696 static void coreaudio_audio_fini (void *opaque)
701 static struct audio_option coreaudio_options[] = {
703 .name = "BUFFER_SIZE",
705 .valp = &glob_conf.buffer_frames,
706 .descr = "Size of the buffer in frames"
709 .name = "BUFFER_COUNT",
711 .valp = &glob_conf.nbuffers,
712 .descr = "Number of buffers"
714 { /* End of list */ }
717 static struct audio_pcm_ops coreaudio_pcm_ops = {
718 .init_out = coreaudio_init_out,
719 .fini_out = coreaudio_fini_out,
720 .run_out = coreaudio_run_out,
721 .write = coreaudio_write,
722 .ctl_out = coreaudio_ctl_out
725 struct audio_driver coreaudio_audio_driver = {
727 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
728 .options = coreaudio_options,
729 .init = coreaudio_audio_init,
730 .fini = coreaudio_audio_fini,
731 .pcm_ops = &coreaudio_pcm_ops,
735 .voice_size_out = sizeof (coreaudioVoiceOut),