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/module.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
39 typedef struct coreaudioVoiceOut
{
41 pthread_mutex_t mutex
;
42 AudioDeviceID outputDeviceID
;
43 UInt32 audioDevicePropertyBufferFrameSize
;
44 AudioStreamBasicDescription outputStreamBasicDescription
;
45 AudioDeviceIOProcID ioprocid
;
48 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
49 /* The APIs used here only become available from 10.6 */
51 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
53 UInt32 size
= sizeof(*id
);
54 AudioObjectPropertyAddress addr
= {
55 kAudioHardwarePropertyDefaultOutputDevice
,
56 kAudioObjectPropertyScopeGlobal
,
57 kAudioObjectPropertyElementMaster
60 return AudioObjectGetPropertyData(kAudioObjectSystemObject
,
68 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
69 AudioValueRange
*framerange
)
71 UInt32 size
= sizeof(*framerange
);
72 AudioObjectPropertyAddress addr
= {
73 kAudioDevicePropertyBufferFrameSizeRange
,
74 kAudioDevicePropertyScopeOutput
,
75 kAudioObjectPropertyElementMaster
78 return AudioObjectGetPropertyData(id
,
86 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
88 UInt32 size
= sizeof(*framesize
);
89 AudioObjectPropertyAddress addr
= {
90 kAudioDevicePropertyBufferFrameSize
,
91 kAudioDevicePropertyScopeOutput
,
92 kAudioObjectPropertyElementMaster
95 return AudioObjectGetPropertyData(id
,
103 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
105 UInt32 size
= sizeof(*framesize
);
106 AudioObjectPropertyAddress addr
= {
107 kAudioDevicePropertyBufferFrameSize
,
108 kAudioDevicePropertyScopeOutput
,
109 kAudioObjectPropertyElementMaster
112 return AudioObjectSetPropertyData(id
,
120 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
121 AudioStreamBasicDescription
*d
)
123 UInt32 size
= sizeof(*d
);
124 AudioObjectPropertyAddress addr
= {
125 kAudioDevicePropertyStreamFormat
,
126 kAudioDevicePropertyScopeOutput
,
127 kAudioObjectPropertyElementMaster
130 return AudioObjectGetPropertyData(id
,
138 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
139 AudioStreamBasicDescription
*d
)
141 UInt32 size
= sizeof(*d
);
142 AudioObjectPropertyAddress addr
= {
143 kAudioDevicePropertyStreamFormat
,
144 kAudioDevicePropertyScopeOutput
,
145 kAudioObjectPropertyElementMaster
148 return AudioObjectSetPropertyData(id
,
156 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
158 UInt32 size
= sizeof(*result
);
159 AudioObjectPropertyAddress addr
= {
160 kAudioDevicePropertyDeviceIsRunning
,
161 kAudioDevicePropertyScopeOutput
,
162 kAudioObjectPropertyElementMaster
165 return AudioObjectGetPropertyData(id
,
173 /* Legacy versions of functions using deprecated APIs */
175 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
177 UInt32 size
= sizeof(*id
);
179 return AudioHardwareGetProperty(
180 kAudioHardwarePropertyDefaultOutputDevice
,
185 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
186 AudioValueRange
*framerange
)
188 UInt32 size
= sizeof(*framerange
);
190 return AudioDeviceGetProperty(
194 kAudioDevicePropertyBufferFrameSizeRange
,
199 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
201 UInt32 size
= sizeof(*framesize
);
203 return AudioDeviceGetProperty(
207 kAudioDevicePropertyBufferFrameSize
,
212 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
214 UInt32 size
= sizeof(*framesize
);
216 return AudioDeviceSetProperty(
221 kAudioDevicePropertyBufferFrameSize
,
226 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
227 AudioStreamBasicDescription
*d
)
229 UInt32 size
= sizeof(*d
);
231 return AudioDeviceGetProperty(
235 kAudioDevicePropertyStreamFormat
,
240 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
241 AudioStreamBasicDescription
*d
)
243 UInt32 size
= sizeof(*d
);
245 return AudioDeviceSetProperty(
250 kAudioDevicePropertyStreamFormat
,
255 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
257 UInt32 size
= sizeof(*result
);
259 return AudioDeviceGetProperty(
263 kAudioDevicePropertyDeviceIsRunning
,
269 static void coreaudio_logstatus (OSStatus status
)
271 const char *str
= "BUG";
274 case kAudioHardwareNoError
:
275 str
= "kAudioHardwareNoError";
278 case kAudioHardwareNotRunningError
:
279 str
= "kAudioHardwareNotRunningError";
282 case kAudioHardwareUnspecifiedError
:
283 str
= "kAudioHardwareUnspecifiedError";
286 case kAudioHardwareUnknownPropertyError
:
287 str
= "kAudioHardwareUnknownPropertyError";
290 case kAudioHardwareBadPropertySizeError
:
291 str
= "kAudioHardwareBadPropertySizeError";
294 case kAudioHardwareIllegalOperationError
:
295 str
= "kAudioHardwareIllegalOperationError";
298 case kAudioHardwareBadDeviceError
:
299 str
= "kAudioHardwareBadDeviceError";
302 case kAudioHardwareBadStreamError
:
303 str
= "kAudioHardwareBadStreamError";
306 case kAudioHardwareUnsupportedOperationError
:
307 str
= "kAudioHardwareUnsupportedOperationError";
310 case kAudioDeviceUnsupportedFormatError
:
311 str
= "kAudioDeviceUnsupportedFormatError";
314 case kAudioDevicePermissionsError
:
315 str
= "kAudioDevicePermissionsError";
319 AUD_log (AUDIO_CAP
, "Reason: status code %" PRId32
"\n", (int32_t)status
);
323 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
326 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
335 AUD_log (AUDIO_CAP
, fmt
, ap
);
338 coreaudio_logstatus (status
);
341 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
350 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
353 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
356 coreaudio_logstatus (status
);
359 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
363 status
= coreaudio_get_isrunning(outputDeviceID
, &result
);
364 if (status
!= kAudioHardwareNoError
) {
365 coreaudio_logerr(status
,
366 "Could not determine whether Device is playing\n");
371 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
375 err
= pthread_mutex_lock (&core
->mutex
);
377 dolog ("Could not lock voice for %s\nReason: %s\n",
378 fn_name
, strerror (err
));
384 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
388 err
= pthread_mutex_unlock (&core
->mutex
);
390 dolog ("Could not unlock voice for %s\nReason: %s\n",
391 fn_name
, strerror (err
));
397 #define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
398 static ret_type glue(coreaudio_, name)args_decl \
400 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
403 if (coreaudio_lock(core, "coreaudio_" #name)) { \
407 ret = glue(audio_generic_, name)args; \
409 coreaudio_unlock(core, "coreaudio_" #name); \
412 COREAUDIO_WRAPPER_FUNC(get_buffer_out
, void *, (HWVoiceOut
*hw
, size_t *size
),
414 COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite
, size_t,
415 (HWVoiceOut
*hw
, void *buf
, size_t size
),
417 COREAUDIO_WRAPPER_FUNC(write
, size_t, (HWVoiceOut
*hw
, void *buf
, size_t size
),
419 #undef COREAUDIO_WRAPPER_FUNC
421 /* callback to feed audiooutput buffer */
422 static OSStatus
audioDeviceIOProc(
423 AudioDeviceID inDevice
,
424 const AudioTimeStamp
* inNow
,
425 const AudioBufferList
* inInputData
,
426 const AudioTimeStamp
* inInputTime
,
427 AudioBufferList
* outOutputData
,
428 const AudioTimeStamp
* inOutputTime
,
431 UInt32 frameCount
, pending_frames
;
432 void *out
= outOutputData
->mBuffers
[0].mData
;
433 HWVoiceOut
*hw
= hwptr
;
434 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
437 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
442 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
443 pending_frames
= hw
->pending_emul
>> hw
->info
.shift
;
445 /* if there are not enough samples, set signal and return */
446 if (pending_frames
< frameCount
) {
448 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
452 len
= frameCount
<< hw
->info
.shift
;
455 ssize_t start
= ((ssize_t
) hw
->pos_emul
) - hw
->pending_emul
;
457 start
+= hw
->size_emul
;
459 assert(start
>= 0 && start
< hw
->size_emul
);
461 write_len
= MIN(MIN(hw
->pending_emul
, len
),
462 hw
->size_emul
- start
);
464 memcpy(out
, hw
->buf_emul
+ start
, write_len
);
465 hw
->pending_emul
-= write_len
;
470 coreaudio_unlock (core
, "audioDeviceIOProc");
474 static UInt32
coreaudio_get_flags(struct audio_pcm_info
*info
,
475 struct audsettings
*as
)
477 UInt32 flags
= info
->sign
? kAudioFormatFlagIsSignedInteger
: 0;
478 if (as
->endianness
) { /* 0 = little, 1 = big */
479 flags
|= kAudioFormatFlagIsBigEndian
;
482 if (flags
== 0) { /* must not be 0 */
483 flags
= kAudioFormatFlagsAreAllClear
;
488 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
492 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
494 const char *typ
= "playback";
495 AudioValueRange frameRange
;
496 Audiodev
*dev
= drv_opaque
;
497 AudiodevCoreaudioPerDirectionOptions
*cpdo
= dev
->u
.coreaudio
.out
;
501 err
= pthread_mutex_init(&core
->mutex
, NULL
);
503 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
507 audio_pcm_init_info (&hw
->info
, as
);
509 status
= coreaudio_get_voice(&core
->outputDeviceID
);
510 if (status
!= kAudioHardwareNoError
) {
511 coreaudio_logerr2 (status
, typ
,
512 "Could not get default output Device\n");
515 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
516 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
520 /* get minimum and maximum buffer frame sizes */
521 status
= coreaudio_get_framesizerange(core
->outputDeviceID
,
523 if (status
!= kAudioHardwareNoError
) {
524 coreaudio_logerr2 (status
, typ
,
525 "Could not get device buffer frame range\n");
529 frames
= audio_buffer_frames(
530 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo
), as
, 11610);
531 if (frameRange
.mMinimum
> frames
) {
532 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
533 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
534 } else if (frameRange
.mMaximum
< frames
) {
535 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
536 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
539 core
->audioDevicePropertyBufferFrameSize
= frames
;
542 /* set Buffer Frame Size */
543 status
= coreaudio_set_framesize(core
->outputDeviceID
,
544 &core
->audioDevicePropertyBufferFrameSize
);
545 if (status
!= kAudioHardwareNoError
) {
546 coreaudio_logerr2 (status
, typ
,
547 "Could not set device buffer frame size %" PRIu32
"\n",
548 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
552 /* get Buffer Frame Size */
553 status
= coreaudio_get_framesize(core
->outputDeviceID
,
554 &core
->audioDevicePropertyBufferFrameSize
);
555 if (status
!= kAudioHardwareNoError
) {
556 coreaudio_logerr2 (status
, typ
,
557 "Could not get device buffer frame size\n");
560 hw
->samples
= (cpdo
->has_buffer_count
? cpdo
->buffer_count
: 4) *
561 core
->audioDevicePropertyBufferFrameSize
;
563 /* get StreamFormat */
564 status
= coreaudio_get_streamformat(core
->outputDeviceID
,
565 &core
->outputStreamBasicDescription
);
566 if (status
!= kAudioHardwareNoError
) {
567 coreaudio_logerr2 (status
, typ
,
568 "Could not get Device Stream properties\n");
569 core
->outputDeviceID
= kAudioDeviceUnknown
;
574 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
575 core
->outputStreamBasicDescription
.mFormatID
= kAudioFormatLinearPCM
;
576 core
->outputStreamBasicDescription
.mFormatFlags
=
577 coreaudio_get_flags(&hw
->info
, as
);
578 core
->outputStreamBasicDescription
.mBytesPerPacket
=
579 core
->outputStreamBasicDescription
.mBytesPerFrame
=
580 hw
->info
.nchannels
* hw
->info
.bits
/ 8;
581 core
->outputStreamBasicDescription
.mFramesPerPacket
= 1;
582 core
->outputStreamBasicDescription
.mChannelsPerFrame
= hw
->info
.nchannels
;
583 core
->outputStreamBasicDescription
.mBitsPerChannel
= hw
->info
.bits
;
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 void coreaudio_enable_out(HWVoiceOut
*hw
, bool enable
)
654 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
658 if (!isPlaying(core
->outputDeviceID
)) {
659 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
660 if (status
!= kAudioHardwareNoError
) {
661 coreaudio_logerr (status
, "Could not resume playback\n");
666 if (!audio_is_cleaning_up()) {
667 if (isPlaying(core
->outputDeviceID
)) {
668 status
= AudioDeviceStop(core
->outputDeviceID
,
670 if (status
!= kAudioHardwareNoError
) {
671 coreaudio_logerr (status
, "Could not pause playback\n");
678 static void *coreaudio_audio_init(Audiodev
*dev
)
683 static void coreaudio_audio_fini (void *opaque
)
687 static struct audio_pcm_ops coreaudio_pcm_ops
= {
688 .init_out
= coreaudio_init_out
,
689 .fini_out
= coreaudio_fini_out
,
690 .write
= coreaudio_write
,
691 .get_buffer_out
= coreaudio_get_buffer_out
,
692 .put_buffer_out
= coreaudio_put_buffer_out_nowrite
,
693 .enable_out
= coreaudio_enable_out
696 static struct audio_driver coreaudio_audio_driver
= {
698 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
699 .init
= coreaudio_audio_init
,
700 .fini
= coreaudio_audio_fini
,
701 .pcm_ops
= &coreaudio_pcm_ops
,
705 .voice_size_out
= sizeof (coreaudioVoiceOut
),
709 static void register_audio_coreaudio(void)
711 audio_driver_register(&coreaudio_audio_driver
);
713 type_init(register_audio_coreaudio
);