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 GCC_FMT_ATTR (2, 3) coreaudio_logerr (
223 AUD_log (AUDIO_CAP
, fmt
, ap
);
226 coreaudio_logstatus (status
);
229 static void GCC_FMT_ATTR (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
)
549 coreaudioVoiceOut
*core
= in_client_data
;
551 qemu_mutex_lock_iothread();
553 if (core
->outputDeviceID
) {
554 fini_out_device(core
);
557 status
= init_out_device(core
);
559 update_device_playback_state(core
);
562 qemu_mutex_unlock_iothread();
566 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
570 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
572 Audiodev
*dev
= drv_opaque
;
573 AudiodevCoreaudioPerDirectionOptions
*cpdo
= dev
->u
.coreaudio
.out
;
574 struct audsettings obt_as
;
577 err
= pthread_mutex_init(&core
->buf_mutex
, NULL
);
579 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
585 as
->fmt
= AUDIO_FORMAT_F32
;
586 audio_pcm_init_info (&hw
->info
, as
);
588 core
->frameSizeSetting
= audio_buffer_frames(
589 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo
), as
, 11610);
591 core
->bufferCount
= cpdo
->has_buffer_count
? cpdo
->buffer_count
: 4;
593 status
= AudioObjectAddPropertyListener(kAudioObjectSystemObject
,
594 &voice_addr
, handle_voice_change
,
596 if (status
!= kAudioHardwareNoError
) {
597 coreaudio_playback_logerr (status
,
598 "Could not listen to voice property change\n");
602 if (init_out_device(core
)) {
603 status
= AudioObjectRemovePropertyListener(kAudioObjectSystemObject
,
607 if (status
!= kAudioHardwareNoError
) {
608 coreaudio_playback_logerr(status
,
609 "Could not remove voice property change listener\n");
618 static void coreaudio_fini_out (HWVoiceOut
*hw
)
622 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
624 status
= AudioObjectRemovePropertyListener(kAudioObjectSystemObject
,
628 if (status
!= kAudioHardwareNoError
) {
629 coreaudio_logerr(status
, "Could not remove voice property change listener\n");
632 fini_out_device(core
);
635 err
= pthread_mutex_destroy(&core
->buf_mutex
);
637 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
641 static void coreaudio_enable_out(HWVoiceOut
*hw
, bool enable
)
643 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
645 core
->enabled
= enable
;
646 update_device_playback_state(core
);
649 static void *coreaudio_audio_init(Audiodev
*dev
)
654 static void coreaudio_audio_fini (void *opaque
)
658 static struct audio_pcm_ops coreaudio_pcm_ops
= {
659 .init_out
= coreaudio_init_out
,
660 .fini_out
= coreaudio_fini_out
,
661 /* wrapper for audio_generic_write */
662 .write
= coreaudio_write
,
663 /* wrapper for audio_generic_buffer_get_free */
664 .buffer_get_free
= coreaudio_buffer_get_free
,
665 /* wrapper for audio_generic_get_buffer_out */
666 .get_buffer_out
= coreaudio_get_buffer_out
,
667 /* wrapper for audio_generic_put_buffer_out */
668 .put_buffer_out
= coreaudio_put_buffer_out
,
669 .enable_out
= coreaudio_enable_out
672 static struct audio_driver coreaudio_audio_driver
= {
674 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
675 .init
= coreaudio_audio_init
,
676 .fini
= coreaudio_audio_fini
,
677 .pcm_ops
= &coreaudio_pcm_ops
,
681 .voice_size_out
= sizeof (coreaudioVoiceOut
),
685 static void register_audio_coreaudio(void)
687 audio_driver_register(&coreaudio_audio_driver
);
689 type_init(register_audio_coreaudio
);