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/main-loop.h"
30 #include "qemu/module.h"
33 #define AUDIO_CAP "coreaudio"
34 #include "audio_int.h"
36 typedef struct coreaudioVoiceOut {
38 pthread_mutex_t buf_mutex;
39 AudioDeviceID outputDeviceID;
42 UInt32 audioDevicePropertyBufferFrameSize;
43 AudioDeviceIOProcID ioprocid;
47 #if !defined(MAC_OS_VERSION_12_0) \
48 || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0)
49 #define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
52 static const AudioObjectPropertyAddress voice_addr = {
53 kAudioHardwarePropertyDefaultOutputDevice,
54 kAudioObjectPropertyScopeGlobal,
55 kAudioObjectPropertyElementMain
58 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
60 UInt32 size = sizeof(*id);
62 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
70 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
71 AudioValueRange *framerange)
73 UInt32 size = sizeof(*framerange);
74 AudioObjectPropertyAddress addr = {
75 kAudioDevicePropertyBufferFrameSizeRange,
76 kAudioDevicePropertyScopeOutput,
77 kAudioObjectPropertyElementMain
80 return AudioObjectGetPropertyData(id,
88 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
90 UInt32 size = sizeof(*framesize);
91 AudioObjectPropertyAddress addr = {
92 kAudioDevicePropertyBufferFrameSize,
93 kAudioDevicePropertyScopeOutput,
94 kAudioObjectPropertyElementMain
97 return AudioObjectGetPropertyData(id,
105 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
107 UInt32 size = sizeof(*framesize);
108 AudioObjectPropertyAddress addr = {
109 kAudioDevicePropertyBufferFrameSize,
110 kAudioDevicePropertyScopeOutput,
111 kAudioObjectPropertyElementMain
114 return AudioObjectSetPropertyData(id,
122 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
123 AudioStreamBasicDescription *d)
125 UInt32 size = sizeof(*d);
126 AudioObjectPropertyAddress addr = {
127 kAudioDevicePropertyStreamFormat,
128 kAudioDevicePropertyScopeOutput,
129 kAudioObjectPropertyElementMain
132 return AudioObjectSetPropertyData(id,
140 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
142 UInt32 size = sizeof(*result);
143 AudioObjectPropertyAddress addr = {
144 kAudioDevicePropertyDeviceIsRunning,
145 kAudioDevicePropertyScopeOutput,
146 kAudioObjectPropertyElementMain
149 return AudioObjectGetPropertyData(id,
157 static void coreaudio_logstatus (OSStatus status)
159 const char *str = "BUG";
162 case kAudioHardwareNoError:
163 str = "kAudioHardwareNoError";
166 case kAudioHardwareNotRunningError:
167 str = "kAudioHardwareNotRunningError";
170 case kAudioHardwareUnspecifiedError:
171 str = "kAudioHardwareUnspecifiedError";
174 case kAudioHardwareUnknownPropertyError:
175 str = "kAudioHardwareUnknownPropertyError";
178 case kAudioHardwareBadPropertySizeError:
179 str = "kAudioHardwareBadPropertySizeError";
182 case kAudioHardwareIllegalOperationError:
183 str = "kAudioHardwareIllegalOperationError";
186 case kAudioHardwareBadDeviceError:
187 str = "kAudioHardwareBadDeviceError";
190 case kAudioHardwareBadStreamError:
191 str = "kAudioHardwareBadStreamError";
194 case kAudioHardwareUnsupportedOperationError:
195 str = "kAudioHardwareUnsupportedOperationError";
198 case kAudioDeviceUnsupportedFormatError:
199 str = "kAudioDeviceUnsupportedFormatError";
202 case kAudioDevicePermissionsError:
203 str = "kAudioDevicePermissionsError";
207 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
211 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
214 static void G_GNUC_PRINTF (2, 3) coreaudio_logerr (
223 AUD_log (AUDIO_CAP, fmt, ap);
226 coreaudio_logstatus (status);
229 static void G_GNUC_PRINTF (3, 4) coreaudio_logerr2 (
238 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
241 AUD_vlog (AUDIO_CAP, fmt, ap);
244 coreaudio_logstatus (status);
247 #define coreaudio_playback_logerr(status, ...) \
248 coreaudio_logerr2(status, "playback", __VA_ARGS__)
250 static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
254 err = pthread_mutex_lock (&core->buf_mutex);
256 dolog ("Could not lock voice for %s\nReason: %s\n",
257 fn_name, strerror (err));
263 static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
267 err = pthread_mutex_unlock (&core->buf_mutex);
269 dolog ("Could not unlock voice for %s\nReason: %s\n",
270 fn_name, strerror (err));
276 #define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
277 static ret_type glue(coreaudio_, name)args_decl \
279 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
282 if (coreaudio_buf_lock(core, "coreaudio_" #name)) { \
286 ret = glue(audio_generic_, name)args; \
288 coreaudio_buf_unlock(core, "coreaudio_" #name); \
291 COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
292 COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
294 COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
295 (HWVoiceOut *hw, void *buf, size_t size),
297 COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
299 #undef COREAUDIO_WRAPPER_FUNC
302 * callback to feed audiooutput buffer. called without iothread lock.
303 * allowed to lock "buf_mutex", but disallowed to have any other locks.
305 static OSStatus audioDeviceIOProc(
306 AudioDeviceID inDevice,
307 const AudioTimeStamp *inNow,
308 const AudioBufferList *inInputData,
309 const AudioTimeStamp *inInputTime,
310 AudioBufferList *outOutputData,
311 const AudioTimeStamp *inOutputTime,
314 UInt32 frameCount, pending_frames;
315 void *out = outOutputData->mBuffers[0].mData;
316 HWVoiceOut *hw = hwptr;
317 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
320 if (coreaudio_buf_lock (core, "audioDeviceIOProc")) {
325 if (inDevice != core->outputDeviceID) {
326 coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)");
330 frameCount = core->audioDevicePropertyBufferFrameSize;
331 pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
333 /* if there are not enough samples, set signal and return */
334 if (pending_frames < frameCount) {
336 coreaudio_buf_unlock (core, "audioDeviceIOProc(empty)");
340 len = frameCount * hw->info.bytes_per_frame;
342 size_t write_len, start;
344 start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
345 assert(start < hw->size_emul);
347 write_len = MIN(MIN(hw->pending_emul, len),
348 hw->size_emul - start);
350 memcpy(out, hw->buf_emul + start, write_len);
351 hw->pending_emul -= write_len;
356 coreaudio_buf_unlock (core, "audioDeviceIOProc");
360 static OSStatus init_out_device(coreaudioVoiceOut *core)
363 AudioValueRange frameRange;
365 AudioStreamBasicDescription streamBasicDescription = {
366 .mBitsPerChannel = core->hw.info.bits,
367 .mBytesPerFrame = core->hw.info.bytes_per_frame,
368 .mBytesPerPacket = core->hw.info.bytes_per_frame,
369 .mChannelsPerFrame = core->hw.info.nchannels,
370 .mFormatFlags = kLinearPCMFormatFlagIsFloat,
371 .mFormatID = kAudioFormatLinearPCM,
372 .mFramesPerPacket = 1,
373 .mSampleRate = core->hw.info.freq
376 status = coreaudio_get_voice(&core->outputDeviceID);
377 if (status != kAudioHardwareNoError) {
378 coreaudio_playback_logerr (status,
379 "Could not get default output Device\n");
382 if (core->outputDeviceID == kAudioDeviceUnknown) {
383 dolog ("Could not initialize playback - Unknown Audiodevice\n");
387 /* get minimum and maximum buffer frame sizes */
388 status = coreaudio_get_framesizerange(core->outputDeviceID,
390 if (status == kAudioHardwareBadObjectError) {
393 if (status != kAudioHardwareNoError) {
394 coreaudio_playback_logerr (status,
395 "Could not get device buffer frame range\n");
399 if (frameRange.mMinimum > core->frameSizeSetting) {
400 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
401 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
402 } else if (frameRange.mMaximum < core->frameSizeSetting) {
403 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
404 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
406 core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
409 /* set Buffer Frame Size */
410 status = coreaudio_set_framesize(core->outputDeviceID,
411 &core->audioDevicePropertyBufferFrameSize);
412 if (status == kAudioHardwareBadObjectError) {
415 if (status != kAudioHardwareNoError) {
416 coreaudio_playback_logerr (status,
417 "Could not set device buffer frame size %" PRIu32 "\n",
418 (uint32_t)core->audioDevicePropertyBufferFrameSize);
422 /* get Buffer Frame Size */
423 status = coreaudio_get_framesize(core->outputDeviceID,
424 &core->audioDevicePropertyBufferFrameSize);
425 if (status == kAudioHardwareBadObjectError) {
428 if (status != kAudioHardwareNoError) {
429 coreaudio_playback_logerr (status,
430 "Could not get device buffer frame size\n");
433 core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
436 status = coreaudio_set_streamformat(core->outputDeviceID,
437 &streamBasicDescription);
438 if (status == kAudioHardwareBadObjectError) {
441 if (status != kAudioHardwareNoError) {
442 coreaudio_playback_logerr (status,
443 "Could not set samplerate %lf\n",
444 streamBasicDescription.mSampleRate);
445 core->outputDeviceID = kAudioDeviceUnknown;
452 * On macOS 11.3.1, Core Audio calls AudioDeviceIOProc after calling an
453 * internal function named HALB_Mutex::Lock(), which locks a mutex in
454 * HALB_IOThread::Entry(void*). HALB_Mutex::Lock() is also called in
455 * AudioObjectGetPropertyData, which is called by coreaudio driver.
456 * Therefore, the specified callback must be designed to avoid a deadlock
457 * with the callers of AudioObjectGetPropertyData.
459 core->ioprocid = NULL;
460 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
464 if (status == kAudioHardwareBadDeviceError) {
467 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
468 coreaudio_playback_logerr (status, "Could not set IOProc\n");
469 core->outputDeviceID = kAudioDeviceUnknown;
476 static void fini_out_device(coreaudioVoiceOut *core)
482 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
483 if (status != kAudioHardwareBadObjectError) {
484 if (status != kAudioHardwareNoError) {
485 coreaudio_logerr(status,
486 "Could not determine whether Device is playing\n");
490 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
491 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
492 coreaudio_logerr(status, "Could not stop playback\n");
497 /* remove callback */
498 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
500 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
501 coreaudio_logerr(status, "Could not remove IOProc\n");
503 core->outputDeviceID = kAudioDeviceUnknown;
506 static void update_device_playback_state(coreaudioVoiceOut *core)
511 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
512 if (status != kAudioHardwareNoError) {
513 if (status != kAudioHardwareBadObjectError) {
514 coreaudio_logerr(status,
515 "Could not determine whether Device is playing\n");
524 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
525 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
526 coreaudio_logerr (status, "Could not resume playback\n");
532 status = AudioDeviceStop(core->outputDeviceID,
534 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
535 coreaudio_logerr(status, "Could not pause playback\n");
541 /* called without iothread lock. */
542 static OSStatus handle_voice_change(
543 AudioObjectID in_object_id,
544 UInt32 in_number_addresses,
545 const AudioObjectPropertyAddress *in_addresses,
546 void *in_client_data)
548 coreaudioVoiceOut *core = in_client_data;
550 qemu_mutex_lock_iothread();
552 if (core->outputDeviceID) {
553 fini_out_device(core);
556 if (!init_out_device(core)) {
557 update_device_playback_state(core);
560 qemu_mutex_unlock_iothread();
564 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
568 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
570 Audiodev *dev = drv_opaque;
571 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
572 struct audsettings obt_as;
575 err = pthread_mutex_init(&core->buf_mutex, NULL);
577 dolog("Could not create mutex\nReason: %s\n", strerror (err));
583 as->fmt = AUDIO_FORMAT_F32;
584 audio_pcm_init_info (&hw->info, as);
586 core->frameSizeSetting = audio_buffer_frames(
587 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
589 core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
591 status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
592 &voice_addr, handle_voice_change,
594 if (status != kAudioHardwareNoError) {
595 coreaudio_playback_logerr (status,
596 "Could not listen to voice property change\n");
600 if (init_out_device(core)) {
601 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
605 if (status != kAudioHardwareNoError) {
606 coreaudio_playback_logerr(status,
607 "Could not remove voice property change listener\n");
616 static void coreaudio_fini_out (HWVoiceOut *hw)
620 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
622 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
626 if (status != kAudioHardwareNoError) {
627 coreaudio_logerr(status, "Could not remove voice property change listener\n");
630 fini_out_device(core);
633 err = pthread_mutex_destroy(&core->buf_mutex);
635 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
639 static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
641 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
643 core->enabled = enable;
644 update_device_playback_state(core);
647 static void *coreaudio_audio_init(Audiodev *dev)
652 static void coreaudio_audio_fini (void *opaque)
656 static struct audio_pcm_ops coreaudio_pcm_ops = {
657 .init_out = coreaudio_init_out,
658 .fini_out = coreaudio_fini_out,
659 /* wrapper for audio_generic_write */
660 .write = coreaudio_write,
661 /* wrapper for audio_generic_buffer_get_free */
662 .buffer_get_free = coreaudio_buffer_get_free,
663 /* wrapper for audio_generic_get_buffer_out */
664 .get_buffer_out = coreaudio_get_buffer_out,
665 /* wrapper for audio_generic_put_buffer_out */
666 .put_buffer_out = coreaudio_put_buffer_out,
667 .enable_out = coreaudio_enable_out
670 static struct audio_driver coreaudio_audio_driver = {
672 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
673 .init = coreaudio_audio_init,
674 .fini = coreaudio_audio_fini,
675 .pcm_ops = &coreaudio_pcm_ops,
679 .voice_size_out = sizeof (coreaudioVoiceOut),
683 static void register_audio_coreaudio(void)
685 audio_driver_register(&coreaudio_audio_driver);
687 type_init(register_audio_coreaudio);