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
),