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 OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
91 AudioValueRange
*framerange
)
93 UInt32 size
= sizeof(*framerange
);
95 return AudioDeviceGetProperty(
99 kAudioDevicePropertyBufferFrameSizeRange
,
104 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
106 UInt32 size
= sizeof(*framesize
);
108 return AudioDeviceGetProperty(
112 kAudioDevicePropertyBufferFrameSize
,
117 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
119 UInt32 size
= sizeof(*framesize
);
121 return AudioDeviceSetProperty(
126 kAudioDevicePropertyBufferFrameSize
,
131 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
132 AudioStreamBasicDescription
*d
)
134 UInt32 size
= sizeof(*d
);
136 return AudioDeviceGetProperty(
140 kAudioDevicePropertyStreamFormat
,
145 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
146 AudioStreamBasicDescription
*d
)
148 UInt32 size
= sizeof(*d
);
150 return AudioDeviceSetProperty(
155 kAudioDevicePropertyStreamFormat
,
160 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
162 UInt32 size
= sizeof(*result
);
164 return AudioDeviceGetProperty(
168 kAudioDevicePropertyDeviceIsRunning
,
173 static void coreaudio_logstatus (OSStatus status
)
175 const char *str
= "BUG";
178 case kAudioHardwareNoError
:
179 str
= "kAudioHardwareNoError";
182 case kAudioHardwareNotRunningError
:
183 str
= "kAudioHardwareNotRunningError";
186 case kAudioHardwareUnspecifiedError
:
187 str
= "kAudioHardwareUnspecifiedError";
190 case kAudioHardwareUnknownPropertyError
:
191 str
= "kAudioHardwareUnknownPropertyError";
194 case kAudioHardwareBadPropertySizeError
:
195 str
= "kAudioHardwareBadPropertySizeError";
198 case kAudioHardwareIllegalOperationError
:
199 str
= "kAudioHardwareIllegalOperationError";
202 case kAudioHardwareBadDeviceError
:
203 str
= "kAudioHardwareBadDeviceError";
206 case kAudioHardwareBadStreamError
:
207 str
= "kAudioHardwareBadStreamError";
210 case kAudioHardwareUnsupportedOperationError
:
211 str
= "kAudioHardwareUnsupportedOperationError";
214 case kAudioDeviceUnsupportedFormatError
:
215 str
= "kAudioDeviceUnsupportedFormatError";
218 case kAudioDevicePermissionsError
:
219 str
= "kAudioDevicePermissionsError";
223 AUD_log (AUDIO_CAP
, "Reason: status code %" PRId32
"\n", (int32_t)status
);
227 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
230 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
239 AUD_log (AUDIO_CAP
, fmt
, ap
);
242 coreaudio_logstatus (status
);
245 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
254 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
257 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
260 coreaudio_logstatus (status
);
263 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
267 status
= coreaudio_get_isrunning(outputDeviceID
, &result
);
268 if (status
!= kAudioHardwareNoError
) {
269 coreaudio_logerr(status
,
270 "Could not determine whether Device is playing\n");
275 static void coreaudio_atexit (void)
280 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
284 err
= pthread_mutex_lock (&core
->mutex
);
286 dolog ("Could not lock voice for %s\nReason: %s\n",
287 fn_name
, strerror (err
));
293 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
297 err
= pthread_mutex_unlock (&core
->mutex
);
299 dolog ("Could not unlock voice for %s\nReason: %s\n",
300 fn_name
, strerror (err
));
306 static int coreaudio_run_out (HWVoiceOut
*hw
, int live
)
309 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
311 if (coreaudio_lock (core
, "coreaudio_run_out")) {
315 if (core
->decr
> live
) {
316 ldebug ("core->decr %d live %d core->live %d\n",
322 decr
= audio_MIN (core
->decr
, live
);
325 core
->live
= live
- decr
;
326 hw
->rpos
= core
->rpos
;
328 coreaudio_unlock (core
, "coreaudio_run_out");
332 /* callback to feed audiooutput buffer */
333 static OSStatus
audioDeviceIOProc(
334 AudioDeviceID inDevice
,
335 const AudioTimeStamp
* inNow
,
336 const AudioBufferList
* inInputData
,
337 const AudioTimeStamp
* inInputTime
,
338 AudioBufferList
* outOutputData
,
339 const AudioTimeStamp
* inOutputTime
,
342 UInt32 frame
, frameCount
;
343 float *out
= outOutputData
->mBuffers
[0].mData
;
344 HWVoiceOut
*hw
= hwptr
;
345 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
347 struct st_sample
*src
;
350 const float scale
= 1.f
/ UINT_MAX
;
352 const float scale
= UINT_MAX
;
356 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
361 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
364 /* if there are not enough samples, set signal and return */
365 if (live
< frameCount
) {
367 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
372 src
= hw
->mix_buf
+ rpos
;
375 for (frame
= 0; frame
< frameCount
; frame
++) {
377 *out
++ = src
[frame
].l
; /* left channel */
378 *out
++ = src
[frame
].r
; /* right channel */
381 *out
++ = src
[frame
].l
* scale
; /* left channel */
382 *out
++ = src
[frame
].r
* scale
; /* right channel */
384 *out
++ = src
[frame
].l
/ scale
; /* left channel */
385 *out
++ = src
[frame
].r
/ scale
; /* right channel */
390 rpos
= (rpos
+ frameCount
) % hw
->samples
;
391 core
->decr
+= frameCount
;
394 coreaudio_unlock (core
, "audioDeviceIOProc");
398 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
400 return audio_pcm_sw_write (sw
, buf
, len
);
403 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
407 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
409 const char *typ
= "playback";
410 AudioValueRange frameRange
;
411 CoreaudioConf
*conf
= drv_opaque
;
414 err
= pthread_mutex_init(&core
->mutex
, NULL
);
416 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
420 audio_pcm_init_info (&hw
->info
, as
);
422 status
= coreaudio_get_voice(&core
->outputDeviceID
);
423 if (status
!= kAudioHardwareNoError
) {
424 coreaudio_logerr2 (status
, typ
,
425 "Could not get default output Device\n");
428 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
429 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
433 /* get minimum and maximum buffer frame sizes */
434 status
= coreaudio_get_framesizerange(core
->outputDeviceID
,
436 if (status
!= kAudioHardwareNoError
) {
437 coreaudio_logerr2 (status
, typ
,
438 "Could not get device buffer frame range\n");
442 if (frameRange
.mMinimum
> conf
->buffer_frames
) {
443 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
444 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
446 else if (frameRange
.mMaximum
< conf
->buffer_frames
) {
447 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
448 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
451 core
->audioDevicePropertyBufferFrameSize
= conf
->buffer_frames
;
454 /* set Buffer Frame Size */
455 status
= coreaudio_set_framesize(core
->outputDeviceID
,
456 &core
->audioDevicePropertyBufferFrameSize
);
457 if (status
!= kAudioHardwareNoError
) {
458 coreaudio_logerr2 (status
, typ
,
459 "Could not set device buffer frame size %" PRIu32
"\n",
460 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
464 /* get Buffer Frame Size */
465 status
= coreaudio_get_framesize(core
->outputDeviceID
,
466 &core
->audioDevicePropertyBufferFrameSize
);
467 if (status
!= kAudioHardwareNoError
) {
468 coreaudio_logerr2 (status
, typ
,
469 "Could not get device buffer frame size\n");
472 hw
->samples
= conf
->nbuffers
* core
->audioDevicePropertyBufferFrameSize
;
474 /* get StreamFormat */
475 status
= coreaudio_get_streamformat(core
->outputDeviceID
,
476 &core
->outputStreamBasicDescription
);
477 if (status
!= kAudioHardwareNoError
) {
478 coreaudio_logerr2 (status
, typ
,
479 "Could not get Device Stream properties\n");
480 core
->outputDeviceID
= kAudioDeviceUnknown
;
485 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
486 status
= coreaudio_set_streamformat(core
->outputDeviceID
,
487 &core
->outputStreamBasicDescription
);
488 if (status
!= kAudioHardwareNoError
) {
489 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
491 core
->outputDeviceID
= kAudioDeviceUnknown
;
496 status
= AudioDeviceAddIOProc(core
->outputDeviceID
, audioDeviceIOProc
, hw
);
497 if (status
!= kAudioHardwareNoError
) {
498 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
499 core
->outputDeviceID
= kAudioDeviceUnknown
;
504 if (!isPlaying(core
->outputDeviceID
)) {
505 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
506 if (status
!= kAudioHardwareNoError
) {
507 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
508 AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
509 core
->outputDeviceID
= kAudioDeviceUnknown
;
517 static void coreaudio_fini_out (HWVoiceOut
*hw
)
521 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
525 if (isPlaying(core
->outputDeviceID
)) {
526 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
527 if (status
!= kAudioHardwareNoError
) {
528 coreaudio_logerr (status
, "Could not stop playback\n");
532 /* remove callback */
533 status
= AudioDeviceRemoveIOProc(core
->outputDeviceID
,
535 if (status
!= kAudioHardwareNoError
) {
536 coreaudio_logerr (status
, "Could not remove IOProc\n");
539 core
->outputDeviceID
= kAudioDeviceUnknown
;
542 err
= pthread_mutex_destroy(&core
->mutex
);
544 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
548 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
551 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
556 if (!isPlaying(core
->outputDeviceID
)) {
557 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
558 if (status
!= kAudioHardwareNoError
) {
559 coreaudio_logerr (status
, "Could not resume playback\n");
567 if (isPlaying(core
->outputDeviceID
)) {
568 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
569 if (status
!= kAudioHardwareNoError
) {
570 coreaudio_logerr (status
, "Could not pause playback\n");
579 static CoreaudioConf glob_conf
= {
580 .buffer_frames
= 512,
584 static void *coreaudio_audio_init (void)
586 CoreaudioConf
*conf
= g_malloc(sizeof(CoreaudioConf
));
589 atexit(coreaudio_atexit
);
593 static void coreaudio_audio_fini (void *opaque
)
598 static struct audio_option coreaudio_options
[] = {
600 .name
= "BUFFER_SIZE",
602 .valp
= &glob_conf
.buffer_frames
,
603 .descr
= "Size of the buffer in frames"
606 .name
= "BUFFER_COUNT",
608 .valp
= &glob_conf
.nbuffers
,
609 .descr
= "Number of buffers"
611 { /* End of list */ }
614 static struct audio_pcm_ops coreaudio_pcm_ops
= {
615 .init_out
= coreaudio_init_out
,
616 .fini_out
= coreaudio_fini_out
,
617 .run_out
= coreaudio_run_out
,
618 .write
= coreaudio_write
,
619 .ctl_out
= coreaudio_ctl_out
622 struct audio_driver coreaudio_audio_driver
= {
624 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
625 .options
= coreaudio_options
,
626 .init
= coreaudio_audio_init
,
627 .fini
= coreaudio_audio_fini
,
628 .pcm_ops
= &coreaudio_pcm_ops
,
632 .voice_size_out
= sizeof (coreaudioVoiceOut
),