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 <CoreAudio/CoreAudio.h>
26 #include <string.h> /* strerror */
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
46 typedef struct coreaudioVoiceOut
{
48 pthread_mutex_t mutex
;
49 AudioDeviceID outputDeviceID
;
50 UInt32 audioDevicePropertyBufferFrameSize
;
51 AudioStreamBasicDescription outputStreamBasicDescription
;
57 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
58 /* The APIs used here only become available from 10.6 */
60 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
62 UInt32 size
= sizeof(*id
);
63 AudioObjectPropertyAddress addr
= {
64 kAudioHardwarePropertyDefaultOutputDevice
,
65 kAudioObjectPropertyScopeGlobal
,
66 kAudioObjectPropertyElementMaster
69 return AudioObjectGetPropertyData(kAudioObjectSystemObject
,
77 /* Legacy versions of functions using deprecated APIs */
79 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
81 UInt32 size
= sizeof(*id
);
83 return AudioHardwareGetProperty(
84 kAudioHardwarePropertyDefaultOutputDevice
,
90 static void coreaudio_logstatus (OSStatus status
)
92 const char *str
= "BUG";
95 case kAudioHardwareNoError
:
96 str
= "kAudioHardwareNoError";
99 case kAudioHardwareNotRunningError
:
100 str
= "kAudioHardwareNotRunningError";
103 case kAudioHardwareUnspecifiedError
:
104 str
= "kAudioHardwareUnspecifiedError";
107 case kAudioHardwareUnknownPropertyError
:
108 str
= "kAudioHardwareUnknownPropertyError";
111 case kAudioHardwareBadPropertySizeError
:
112 str
= "kAudioHardwareBadPropertySizeError";
115 case kAudioHardwareIllegalOperationError
:
116 str
= "kAudioHardwareIllegalOperationError";
119 case kAudioHardwareBadDeviceError
:
120 str
= "kAudioHardwareBadDeviceError";
123 case kAudioHardwareBadStreamError
:
124 str
= "kAudioHardwareBadStreamError";
127 case kAudioHardwareUnsupportedOperationError
:
128 str
= "kAudioHardwareUnsupportedOperationError";
131 case kAudioDeviceUnsupportedFormatError
:
132 str
= "kAudioDeviceUnsupportedFormatError";
135 case kAudioDevicePermissionsError
:
136 str
= "kAudioDevicePermissionsError";
140 AUD_log (AUDIO_CAP
, "Reason: status code %" PRId32
"\n", (int32_t)status
);
144 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
147 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
156 AUD_log (AUDIO_CAP
, fmt
, ap
);
159 coreaudio_logstatus (status
);
162 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
171 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
174 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
177 coreaudio_logstatus (status
);
180 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
184 UInt32 propertySize
= sizeof(outputDeviceID
);
185 status
= AudioDeviceGetProperty(
186 outputDeviceID
, 0, 0,
187 kAudioDevicePropertyDeviceIsRunning
, &propertySize
, &result
);
188 if (status
!= kAudioHardwareNoError
) {
189 coreaudio_logerr(status
,
190 "Could not determine whether Device is playing\n");
195 static void coreaudio_atexit (void)
200 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
204 err
= pthread_mutex_lock (&core
->mutex
);
206 dolog ("Could not lock voice for %s\nReason: %s\n",
207 fn_name
, strerror (err
));
213 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
217 err
= pthread_mutex_unlock (&core
->mutex
);
219 dolog ("Could not unlock voice for %s\nReason: %s\n",
220 fn_name
, strerror (err
));
226 static int coreaudio_run_out (HWVoiceOut
*hw
, int live
)
229 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
231 if (coreaudio_lock (core
, "coreaudio_run_out")) {
235 if (core
->decr
> live
) {
236 ldebug ("core->decr %d live %d core->live %d\n",
242 decr
= audio_MIN (core
->decr
, live
);
245 core
->live
= live
- decr
;
246 hw
->rpos
= core
->rpos
;
248 coreaudio_unlock (core
, "coreaudio_run_out");
252 /* callback to feed audiooutput buffer */
253 static OSStatus
audioDeviceIOProc(
254 AudioDeviceID inDevice
,
255 const AudioTimeStamp
* inNow
,
256 const AudioBufferList
* inInputData
,
257 const AudioTimeStamp
* inInputTime
,
258 AudioBufferList
* outOutputData
,
259 const AudioTimeStamp
* inOutputTime
,
262 UInt32 frame
, frameCount
;
263 float *out
= outOutputData
->mBuffers
[0].mData
;
264 HWVoiceOut
*hw
= hwptr
;
265 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
267 struct st_sample
*src
;
270 const float scale
= 1.f
/ UINT_MAX
;
272 const float scale
= UINT_MAX
;
276 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
281 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
284 /* if there are not enough samples, set signal and return */
285 if (live
< frameCount
) {
287 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
292 src
= hw
->mix_buf
+ rpos
;
295 for (frame
= 0; frame
< frameCount
; frame
++) {
297 *out
++ = src
[frame
].l
; /* left channel */
298 *out
++ = src
[frame
].r
; /* right channel */
301 *out
++ = src
[frame
].l
* scale
; /* left channel */
302 *out
++ = src
[frame
].r
* scale
; /* right channel */
304 *out
++ = src
[frame
].l
/ scale
; /* left channel */
305 *out
++ = src
[frame
].r
/ scale
; /* right channel */
310 rpos
= (rpos
+ frameCount
) % hw
->samples
;
311 core
->decr
+= frameCount
;
314 coreaudio_unlock (core
, "audioDeviceIOProc");
318 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
320 return audio_pcm_sw_write (sw
, buf
, len
);
323 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
327 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
330 const char *typ
= "playback";
331 AudioValueRange frameRange
;
332 CoreaudioConf
*conf
= drv_opaque
;
335 err
= pthread_mutex_init(&core
->mutex
, NULL
);
337 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
341 audio_pcm_init_info (&hw
->info
, as
);
343 status
= coreaudio_get_voice(&core
->outputDeviceID
);
344 if (status
!= kAudioHardwareNoError
) {
345 coreaudio_logerr2 (status
, typ
,
346 "Could not get default output Device\n");
349 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
350 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
354 /* get minimum and maximum buffer frame sizes */
355 propertySize
= sizeof(frameRange
);
356 status
= AudioDeviceGetProperty(
357 core
->outputDeviceID
,
360 kAudioDevicePropertyBufferFrameSizeRange
,
363 if (status
!= kAudioHardwareNoError
) {
364 coreaudio_logerr2 (status
, typ
,
365 "Could not get device buffer frame range\n");
369 if (frameRange
.mMinimum
> conf
->buffer_frames
) {
370 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
371 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
373 else if (frameRange
.mMaximum
< conf
->buffer_frames
) {
374 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
375 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
378 core
->audioDevicePropertyBufferFrameSize
= conf
->buffer_frames
;
381 /* set Buffer Frame Size */
382 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
383 status
= AudioDeviceSetProperty(
384 core
->outputDeviceID
,
388 kAudioDevicePropertyBufferFrameSize
,
390 &core
->audioDevicePropertyBufferFrameSize
);
391 if (status
!= kAudioHardwareNoError
) {
392 coreaudio_logerr2 (status
, typ
,
393 "Could not set device buffer frame size %" PRIu32
"\n",
394 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
398 /* get Buffer Frame Size */
399 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
400 status
= AudioDeviceGetProperty(
401 core
->outputDeviceID
,
404 kAudioDevicePropertyBufferFrameSize
,
406 &core
->audioDevicePropertyBufferFrameSize
);
407 if (status
!= kAudioHardwareNoError
) {
408 coreaudio_logerr2 (status
, typ
,
409 "Could not get device buffer frame size\n");
412 hw
->samples
= conf
->nbuffers
* core
->audioDevicePropertyBufferFrameSize
;
414 /* get StreamFormat */
415 propertySize
= sizeof(core
->outputStreamBasicDescription
);
416 status
= AudioDeviceGetProperty(
417 core
->outputDeviceID
,
420 kAudioDevicePropertyStreamFormat
,
422 &core
->outputStreamBasicDescription
);
423 if (status
!= kAudioHardwareNoError
) {
424 coreaudio_logerr2 (status
, typ
,
425 "Could not get Device Stream properties\n");
426 core
->outputDeviceID
= kAudioDeviceUnknown
;
431 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
432 propertySize
= sizeof(core
->outputStreamBasicDescription
);
433 status
= AudioDeviceSetProperty(
434 core
->outputDeviceID
,
438 kAudioDevicePropertyStreamFormat
,
440 &core
->outputStreamBasicDescription
);
441 if (status
!= kAudioHardwareNoError
) {
442 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
444 core
->outputDeviceID
= kAudioDeviceUnknown
;
449 status
= AudioDeviceAddIOProc(core
->outputDeviceID
, audioDeviceIOProc
, hw
);
450 if (status
!= kAudioHardwareNoError
) {
451 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
452 core
->outputDeviceID
= kAudioDeviceUnknown
;
457 if (!isPlaying(core
->outputDeviceID
)) {
458 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
459 if (status
!= kAudioHardwareNoError
) {
460 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
461 AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
462 core
->outputDeviceID
= kAudioDeviceUnknown
;
470 static void coreaudio_fini_out (HWVoiceOut
*hw
)
474 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
478 if (isPlaying(core
->outputDeviceID
)) {
479 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
480 if (status
!= kAudioHardwareNoError
) {
481 coreaudio_logerr (status
, "Could not stop playback\n");
485 /* remove callback */
486 status
= AudioDeviceRemoveIOProc(core
->outputDeviceID
,
488 if (status
!= kAudioHardwareNoError
) {
489 coreaudio_logerr (status
, "Could not remove IOProc\n");
492 core
->outputDeviceID
= kAudioDeviceUnknown
;
495 err
= pthread_mutex_destroy(&core
->mutex
);
497 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
501 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
504 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
509 if (!isPlaying(core
->outputDeviceID
)) {
510 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
511 if (status
!= kAudioHardwareNoError
) {
512 coreaudio_logerr (status
, "Could not resume playback\n");
520 if (isPlaying(core
->outputDeviceID
)) {
521 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
522 if (status
!= kAudioHardwareNoError
) {
523 coreaudio_logerr (status
, "Could not pause playback\n");
532 static CoreaudioConf glob_conf
= {
533 .buffer_frames
= 512,
537 static void *coreaudio_audio_init (void)
539 CoreaudioConf
*conf
= g_malloc(sizeof(CoreaudioConf
));
542 atexit(coreaudio_atexit
);
546 static void coreaudio_audio_fini (void *opaque
)
551 static struct audio_option coreaudio_options
[] = {
553 .name
= "BUFFER_SIZE",
555 .valp
= &glob_conf
.buffer_frames
,
556 .descr
= "Size of the buffer in frames"
559 .name
= "BUFFER_COUNT",
561 .valp
= &glob_conf
.nbuffers
,
562 .descr
= "Number of buffers"
564 { /* End of list */ }
567 static struct audio_pcm_ops coreaudio_pcm_ops
= {
568 .init_out
= coreaudio_init_out
,
569 .fini_out
= coreaudio_fini_out
,
570 .run_out
= coreaudio_run_out
,
571 .write
= coreaudio_write
,
572 .ctl_out
= coreaudio_ctl_out
575 struct audio_driver coreaudio_audio_driver
= {
577 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
578 .options
= coreaudio_options
,
579 .init
= coreaudio_audio_init
,
580 .fini
= coreaudio_audio_fini
,
581 .pcm_ops
= &coreaudio_pcm_ops
,
585 .voice_size_out
= sizeof (coreaudioVoiceOut
),