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
39 typedef struct coreaudioVoiceOut
{
41 pthread_mutex_t mutex
;
42 AudioDeviceID outputDeviceID
;
43 UInt32 audioDevicePropertyBufferFrameSize
;
44 AudioStreamBasicDescription outputStreamBasicDescription
;
45 AudioDeviceIOProcID ioprocid
;
51 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
52 /* The APIs used here only become available from 10.6 */
54 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
56 UInt32 size
= sizeof(*id
);
57 AudioObjectPropertyAddress addr
= {
58 kAudioHardwarePropertyDefaultOutputDevice
,
59 kAudioObjectPropertyScopeGlobal
,
60 kAudioObjectPropertyElementMaster
63 return AudioObjectGetPropertyData(kAudioObjectSystemObject
,
71 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
72 AudioValueRange
*framerange
)
74 UInt32 size
= sizeof(*framerange
);
75 AudioObjectPropertyAddress addr
= {
76 kAudioDevicePropertyBufferFrameSizeRange
,
77 kAudioDevicePropertyScopeOutput
,
78 kAudioObjectPropertyElementMaster
81 return AudioObjectGetPropertyData(id
,
89 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
91 UInt32 size
= sizeof(*framesize
);
92 AudioObjectPropertyAddress addr
= {
93 kAudioDevicePropertyBufferFrameSize
,
94 kAudioDevicePropertyScopeOutput
,
95 kAudioObjectPropertyElementMaster
98 return AudioObjectGetPropertyData(id
,
106 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
108 UInt32 size
= sizeof(*framesize
);
109 AudioObjectPropertyAddress addr
= {
110 kAudioDevicePropertyBufferFrameSize
,
111 kAudioDevicePropertyScopeOutput
,
112 kAudioObjectPropertyElementMaster
115 return AudioObjectSetPropertyData(id
,
123 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
124 AudioStreamBasicDescription
*d
)
126 UInt32 size
= sizeof(*d
);
127 AudioObjectPropertyAddress addr
= {
128 kAudioDevicePropertyStreamFormat
,
129 kAudioDevicePropertyScopeOutput
,
130 kAudioObjectPropertyElementMaster
133 return AudioObjectGetPropertyData(id
,
141 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
142 AudioStreamBasicDescription
*d
)
144 UInt32 size
= sizeof(*d
);
145 AudioObjectPropertyAddress addr
= {
146 kAudioDevicePropertyStreamFormat
,
147 kAudioDevicePropertyScopeOutput
,
148 kAudioObjectPropertyElementMaster
151 return AudioObjectSetPropertyData(id
,
159 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
161 UInt32 size
= sizeof(*result
);
162 AudioObjectPropertyAddress addr
= {
163 kAudioDevicePropertyDeviceIsRunning
,
164 kAudioDevicePropertyScopeOutput
,
165 kAudioObjectPropertyElementMaster
168 return AudioObjectGetPropertyData(id
,
176 /* Legacy versions of functions using deprecated APIs */
178 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
180 UInt32 size
= sizeof(*id
);
182 return AudioHardwareGetProperty(
183 kAudioHardwarePropertyDefaultOutputDevice
,
188 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
189 AudioValueRange
*framerange
)
191 UInt32 size
= sizeof(*framerange
);
193 return AudioDeviceGetProperty(
197 kAudioDevicePropertyBufferFrameSizeRange
,
202 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
204 UInt32 size
= sizeof(*framesize
);
206 return AudioDeviceGetProperty(
210 kAudioDevicePropertyBufferFrameSize
,
215 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
217 UInt32 size
= sizeof(*framesize
);
219 return AudioDeviceSetProperty(
224 kAudioDevicePropertyBufferFrameSize
,
229 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
230 AudioStreamBasicDescription
*d
)
232 UInt32 size
= sizeof(*d
);
234 return AudioDeviceGetProperty(
238 kAudioDevicePropertyStreamFormat
,
243 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
244 AudioStreamBasicDescription
*d
)
246 UInt32 size
= sizeof(*d
);
248 return AudioDeviceSetProperty(
253 kAudioDevicePropertyStreamFormat
,
258 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
260 UInt32 size
= sizeof(*result
);
262 return AudioDeviceGetProperty(
266 kAudioDevicePropertyDeviceIsRunning
,
272 static void coreaudio_logstatus (OSStatus status
)
274 const char *str
= "BUG";
277 case kAudioHardwareNoError
:
278 str
= "kAudioHardwareNoError";
281 case kAudioHardwareNotRunningError
:
282 str
= "kAudioHardwareNotRunningError";
285 case kAudioHardwareUnspecifiedError
:
286 str
= "kAudioHardwareUnspecifiedError";
289 case kAudioHardwareUnknownPropertyError
:
290 str
= "kAudioHardwareUnknownPropertyError";
293 case kAudioHardwareBadPropertySizeError
:
294 str
= "kAudioHardwareBadPropertySizeError";
297 case kAudioHardwareIllegalOperationError
:
298 str
= "kAudioHardwareIllegalOperationError";
301 case kAudioHardwareBadDeviceError
:
302 str
= "kAudioHardwareBadDeviceError";
305 case kAudioHardwareBadStreamError
:
306 str
= "kAudioHardwareBadStreamError";
309 case kAudioHardwareUnsupportedOperationError
:
310 str
= "kAudioHardwareUnsupportedOperationError";
313 case kAudioDeviceUnsupportedFormatError
:
314 str
= "kAudioDeviceUnsupportedFormatError";
317 case kAudioDevicePermissionsError
:
318 str
= "kAudioDevicePermissionsError";
322 AUD_log (AUDIO_CAP
, "Reason: status code %" PRId32
"\n", (int32_t)status
);
326 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
329 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
338 AUD_log (AUDIO_CAP
, fmt
, ap
);
341 coreaudio_logstatus (status
);
344 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
353 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
356 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
359 coreaudio_logstatus (status
);
362 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
366 status
= coreaudio_get_isrunning(outputDeviceID
, &result
);
367 if (status
!= kAudioHardwareNoError
) {
368 coreaudio_logerr(status
,
369 "Could not determine whether Device is playing\n");
374 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
378 err
= pthread_mutex_lock (&core
->mutex
);
380 dolog ("Could not lock voice for %s\nReason: %s\n",
381 fn_name
, strerror (err
));
387 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
391 err
= pthread_mutex_unlock (&core
->mutex
);
393 dolog ("Could not unlock voice for %s\nReason: %s\n",
394 fn_name
, strerror (err
));
400 static int coreaudio_run_out (HWVoiceOut
*hw
, int live
)
403 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
405 if (coreaudio_lock (core
, "coreaudio_run_out")) {
409 if (core
->decr
> live
) {
410 ldebug ("core->decr %d live %d core->live %d\n",
416 decr
= audio_MIN (core
->decr
, live
);
419 core
->live
= live
- decr
;
420 hw
->rpos
= core
->rpos
;
422 coreaudio_unlock (core
, "coreaudio_run_out");
426 /* callback to feed audiooutput buffer */
427 static OSStatus
audioDeviceIOProc(
428 AudioDeviceID inDevice
,
429 const AudioTimeStamp
* inNow
,
430 const AudioBufferList
* inInputData
,
431 const AudioTimeStamp
* inInputTime
,
432 AudioBufferList
* outOutputData
,
433 const AudioTimeStamp
* inOutputTime
,
436 UInt32 frame
, frameCount
;
437 float *out
= outOutputData
->mBuffers
[0].mData
;
438 HWVoiceOut
*hw
= hwptr
;
439 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
441 struct st_sample
*src
;
444 const float scale
= 1.f
/ UINT_MAX
;
446 const float scale
= UINT_MAX
;
450 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
455 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
458 /* if there are not enough samples, set signal and return */
459 if (live
< frameCount
) {
461 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
466 src
= hw
->mix_buf
+ rpos
;
469 for (frame
= 0; frame
< frameCount
; frame
++) {
471 *out
++ = src
[frame
].l
; /* left channel */
472 *out
++ = src
[frame
].r
; /* right channel */
475 *out
++ = src
[frame
].l
* scale
; /* left channel */
476 *out
++ = src
[frame
].r
* scale
; /* right channel */
478 *out
++ = src
[frame
].l
/ scale
; /* left channel */
479 *out
++ = src
[frame
].r
/ scale
; /* right channel */
484 rpos
= (rpos
+ frameCount
) % hw
->samples
;
485 core
->decr
+= frameCount
;
488 coreaudio_unlock (core
, "audioDeviceIOProc");
492 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
494 return audio_pcm_sw_write (sw
, buf
, len
);
497 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
501 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
503 const char *typ
= "playback";
504 AudioValueRange frameRange
;
505 Audiodev
*dev
= drv_opaque
;
506 AudiodevCoreaudioPerDirectionOptions
*cpdo
= dev
->u
.coreaudio
.out
;
510 err
= pthread_mutex_init(&core
->mutex
, NULL
);
512 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
516 audio_pcm_init_info (&hw
->info
, as
);
518 status
= coreaudio_get_voice(&core
->outputDeviceID
);
519 if (status
!= kAudioHardwareNoError
) {
520 coreaudio_logerr2 (status
, typ
,
521 "Could not get default output Device\n");
524 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
525 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
529 /* get minimum and maximum buffer frame sizes */
530 status
= coreaudio_get_framesizerange(core
->outputDeviceID
,
532 if (status
!= kAudioHardwareNoError
) {
533 coreaudio_logerr2 (status
, typ
,
534 "Could not get device buffer frame range\n");
538 frames
= audio_buffer_frames(
539 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo
), as
, 11610);
540 if (frameRange
.mMinimum
> frames
) {
541 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
542 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
543 } else if (frameRange
.mMaximum
< frames
) {
544 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
545 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
548 core
->audioDevicePropertyBufferFrameSize
= frames
;
551 /* set Buffer Frame Size */
552 status
= coreaudio_set_framesize(core
->outputDeviceID
,
553 &core
->audioDevicePropertyBufferFrameSize
);
554 if (status
!= kAudioHardwareNoError
) {
555 coreaudio_logerr2 (status
, typ
,
556 "Could not set device buffer frame size %" PRIu32
"\n",
557 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
561 /* get Buffer Frame Size */
562 status
= coreaudio_get_framesize(core
->outputDeviceID
,
563 &core
->audioDevicePropertyBufferFrameSize
);
564 if (status
!= kAudioHardwareNoError
) {
565 coreaudio_logerr2 (status
, typ
,
566 "Could not get device buffer frame size\n");
569 hw
->samples
= (cpdo
->has_buffer_count
? cpdo
->buffer_count
: 4) *
570 core
->audioDevicePropertyBufferFrameSize
;
572 /* get StreamFormat */
573 status
= coreaudio_get_streamformat(core
->outputDeviceID
,
574 &core
->outputStreamBasicDescription
);
575 if (status
!= kAudioHardwareNoError
) {
576 coreaudio_logerr2 (status
, typ
,
577 "Could not get Device Stream properties\n");
578 core
->outputDeviceID
= kAudioDeviceUnknown
;
583 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
584 status
= coreaudio_set_streamformat(core
->outputDeviceID
,
585 &core
->outputStreamBasicDescription
);
586 if (status
!= kAudioHardwareNoError
) {
587 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
589 core
->outputDeviceID
= kAudioDeviceUnknown
;
594 core
->ioprocid
= NULL
;
595 status
= AudioDeviceCreateIOProcID(core
->outputDeviceID
,
599 if (status
!= kAudioHardwareNoError
|| core
->ioprocid
== NULL
) {
600 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
601 core
->outputDeviceID
= kAudioDeviceUnknown
;
606 if (!isPlaying(core
->outputDeviceID
)) {
607 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
608 if (status
!= kAudioHardwareNoError
) {
609 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
610 AudioDeviceDestroyIOProcID(core
->outputDeviceID
, core
->ioprocid
);
611 core
->outputDeviceID
= kAudioDeviceUnknown
;
619 static void coreaudio_fini_out (HWVoiceOut
*hw
)
623 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
625 if (!audio_is_cleaning_up()) {
627 if (isPlaying(core
->outputDeviceID
)) {
628 status
= AudioDeviceStop(core
->outputDeviceID
, core
->ioprocid
);
629 if (status
!= kAudioHardwareNoError
) {
630 coreaudio_logerr (status
, "Could not stop playback\n");
634 /* remove callback */
635 status
= AudioDeviceDestroyIOProcID(core
->outputDeviceID
,
637 if (status
!= kAudioHardwareNoError
) {
638 coreaudio_logerr (status
, "Could not remove IOProc\n");
641 core
->outputDeviceID
= kAudioDeviceUnknown
;
644 err
= pthread_mutex_destroy(&core
->mutex
);
646 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
650 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
653 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");
668 if (!audio_is_cleaning_up()) {
669 if (isPlaying(core
->outputDeviceID
)) {
670 status
= AudioDeviceStop(core
->outputDeviceID
,
672 if (status
!= kAudioHardwareNoError
) {
673 coreaudio_logerr (status
, "Could not pause playback\n");
682 static void *coreaudio_audio_init(Audiodev
*dev
)
687 static void coreaudio_audio_fini (void *opaque
)
691 static struct audio_pcm_ops coreaudio_pcm_ops
= {
692 .init_out
= coreaudio_init_out
,
693 .fini_out
= coreaudio_fini_out
,
694 .run_out
= coreaudio_run_out
,
695 .write
= coreaudio_write
,
696 .ctl_out
= coreaudio_ctl_out
699 static struct audio_driver coreaudio_audio_driver
= {
701 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
702 .init
= coreaudio_audio_init
,
703 .fini
= coreaudio_audio_fini
,
704 .pcm_ops
= &coreaudio_pcm_ops
,
708 .voice_size_out
= sizeof (coreaudioVoiceOut
),
712 static void register_audio_coreaudio(void)
714 audio_driver_register(&coreaudio_audio_driver
);
716 type_init(register_audio_coreaudio
);