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
;
52 AudioDeviceIOProcID ioprocid
;
58 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
59 /* The APIs used here only become available from 10.6 */
61 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
63 UInt32 size
= sizeof(*id
);
64 AudioObjectPropertyAddress addr
= {
65 kAudioHardwarePropertyDefaultOutputDevice
,
66 kAudioObjectPropertyScopeGlobal
,
67 kAudioObjectPropertyElementMaster
70 return AudioObjectGetPropertyData(kAudioObjectSystemObject
,
78 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
79 AudioValueRange
*framerange
)
81 UInt32 size
= sizeof(*framerange
);
82 AudioObjectPropertyAddress addr
= {
83 kAudioDevicePropertyBufferFrameSizeRange
,
84 kAudioDevicePropertyScopeOutput
,
85 kAudioObjectPropertyElementMaster
88 return AudioObjectGetPropertyData(id
,
96 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
98 UInt32 size
= sizeof(*framesize
);
99 AudioObjectPropertyAddress addr
= {
100 kAudioDevicePropertyBufferFrameSize
,
101 kAudioDevicePropertyScopeOutput
,
102 kAudioObjectPropertyElementMaster
105 return AudioObjectGetPropertyData(id
,
113 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
115 UInt32 size
= sizeof(*framesize
);
116 AudioObjectPropertyAddress addr
= {
117 kAudioDevicePropertyBufferFrameSize
,
118 kAudioDevicePropertyScopeOutput
,
119 kAudioObjectPropertyElementMaster
122 return AudioObjectSetPropertyData(id
,
130 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
131 AudioStreamBasicDescription
*d
)
133 UInt32 size
= sizeof(*d
);
134 AudioObjectPropertyAddress addr
= {
135 kAudioDevicePropertyStreamFormat
,
136 kAudioDevicePropertyScopeOutput
,
137 kAudioObjectPropertyElementMaster
140 return AudioObjectGetPropertyData(id
,
148 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
149 AudioStreamBasicDescription
*d
)
151 UInt32 size
= sizeof(*d
);
152 AudioObjectPropertyAddress addr
= {
153 kAudioDevicePropertyStreamFormat
,
154 kAudioDevicePropertyScopeOutput
,
155 kAudioObjectPropertyElementMaster
158 return AudioObjectSetPropertyData(id
,
166 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
168 UInt32 size
= sizeof(*result
);
169 AudioObjectPropertyAddress addr
= {
170 kAudioDevicePropertyDeviceIsRunning
,
171 kAudioDevicePropertyScopeOutput
,
172 kAudioObjectPropertyElementMaster
175 return AudioObjectGetPropertyData(id
,
183 /* Legacy versions of functions using deprecated APIs */
185 static OSStatus
coreaudio_get_voice(AudioDeviceID
*id
)
187 UInt32 size
= sizeof(*id
);
189 return AudioHardwareGetProperty(
190 kAudioHardwarePropertyDefaultOutputDevice
,
195 static OSStatus
coreaudio_get_framesizerange(AudioDeviceID id
,
196 AudioValueRange
*framerange
)
198 UInt32 size
= sizeof(*framerange
);
200 return AudioDeviceGetProperty(
204 kAudioDevicePropertyBufferFrameSizeRange
,
209 static OSStatus
coreaudio_get_framesize(AudioDeviceID id
, UInt32
*framesize
)
211 UInt32 size
= sizeof(*framesize
);
213 return AudioDeviceGetProperty(
217 kAudioDevicePropertyBufferFrameSize
,
222 static OSStatus
coreaudio_set_framesize(AudioDeviceID id
, UInt32
*framesize
)
224 UInt32 size
= sizeof(*framesize
);
226 return AudioDeviceSetProperty(
231 kAudioDevicePropertyBufferFrameSize
,
236 static OSStatus
coreaudio_get_streamformat(AudioDeviceID id
,
237 AudioStreamBasicDescription
*d
)
239 UInt32 size
= sizeof(*d
);
241 return AudioDeviceGetProperty(
245 kAudioDevicePropertyStreamFormat
,
250 static OSStatus
coreaudio_set_streamformat(AudioDeviceID id
,
251 AudioStreamBasicDescription
*d
)
253 UInt32 size
= sizeof(*d
);
255 return AudioDeviceSetProperty(
260 kAudioDevicePropertyStreamFormat
,
265 static OSStatus
coreaudio_get_isrunning(AudioDeviceID id
, UInt32
*result
)
267 UInt32 size
= sizeof(*result
);
269 return AudioDeviceGetProperty(
273 kAudioDevicePropertyDeviceIsRunning
,
279 static void coreaudio_logstatus (OSStatus status
)
281 const char *str
= "BUG";
284 case kAudioHardwareNoError
:
285 str
= "kAudioHardwareNoError";
288 case kAudioHardwareNotRunningError
:
289 str
= "kAudioHardwareNotRunningError";
292 case kAudioHardwareUnspecifiedError
:
293 str
= "kAudioHardwareUnspecifiedError";
296 case kAudioHardwareUnknownPropertyError
:
297 str
= "kAudioHardwareUnknownPropertyError";
300 case kAudioHardwareBadPropertySizeError
:
301 str
= "kAudioHardwareBadPropertySizeError";
304 case kAudioHardwareIllegalOperationError
:
305 str
= "kAudioHardwareIllegalOperationError";
308 case kAudioHardwareBadDeviceError
:
309 str
= "kAudioHardwareBadDeviceError";
312 case kAudioHardwareBadStreamError
:
313 str
= "kAudioHardwareBadStreamError";
316 case kAudioHardwareUnsupportedOperationError
:
317 str
= "kAudioHardwareUnsupportedOperationError";
320 case kAudioDeviceUnsupportedFormatError
:
321 str
= "kAudioDeviceUnsupportedFormatError";
324 case kAudioDevicePermissionsError
:
325 str
= "kAudioDevicePermissionsError";
329 AUD_log (AUDIO_CAP
, "Reason: status code %" PRId32
"\n", (int32_t)status
);
333 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
336 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
345 AUD_log (AUDIO_CAP
, fmt
, ap
);
348 coreaudio_logstatus (status
);
351 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
360 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
363 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
366 coreaudio_logstatus (status
);
369 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
373 status
= coreaudio_get_isrunning(outputDeviceID
, &result
);
374 if (status
!= kAudioHardwareNoError
) {
375 coreaudio_logerr(status
,
376 "Could not determine whether Device is playing\n");
381 static void coreaudio_atexit (void)
386 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
390 err
= pthread_mutex_lock (&core
->mutex
);
392 dolog ("Could not lock voice for %s\nReason: %s\n",
393 fn_name
, strerror (err
));
399 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
403 err
= pthread_mutex_unlock (&core
->mutex
);
405 dolog ("Could not unlock voice for %s\nReason: %s\n",
406 fn_name
, strerror (err
));
412 static int coreaudio_run_out (HWVoiceOut
*hw
, int live
)
415 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
417 if (coreaudio_lock (core
, "coreaudio_run_out")) {
421 if (core
->decr
> live
) {
422 ldebug ("core->decr %d live %d core->live %d\n",
428 decr
= audio_MIN (core
->decr
, live
);
431 core
->live
= live
- decr
;
432 hw
->rpos
= core
->rpos
;
434 coreaudio_unlock (core
, "coreaudio_run_out");
438 /* callback to feed audiooutput buffer */
439 static OSStatus
audioDeviceIOProc(
440 AudioDeviceID inDevice
,
441 const AudioTimeStamp
* inNow
,
442 const AudioBufferList
* inInputData
,
443 const AudioTimeStamp
* inInputTime
,
444 AudioBufferList
* outOutputData
,
445 const AudioTimeStamp
* inOutputTime
,
448 UInt32 frame
, frameCount
;
449 float *out
= outOutputData
->mBuffers
[0].mData
;
450 HWVoiceOut
*hw
= hwptr
;
451 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
453 struct st_sample
*src
;
456 const float scale
= 1.f
/ UINT_MAX
;
458 const float scale
= UINT_MAX
;
462 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
467 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
470 /* if there are not enough samples, set signal and return */
471 if (live
< frameCount
) {
473 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
478 src
= hw
->mix_buf
+ rpos
;
481 for (frame
= 0; frame
< frameCount
; frame
++) {
483 *out
++ = src
[frame
].l
; /* left channel */
484 *out
++ = src
[frame
].r
; /* right channel */
487 *out
++ = src
[frame
].l
* scale
; /* left channel */
488 *out
++ = src
[frame
].r
* scale
; /* right channel */
490 *out
++ = src
[frame
].l
/ scale
; /* left channel */
491 *out
++ = src
[frame
].r
/ scale
; /* right channel */
496 rpos
= (rpos
+ frameCount
) % hw
->samples
;
497 core
->decr
+= frameCount
;
500 coreaudio_unlock (core
, "audioDeviceIOProc");
504 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
506 return audio_pcm_sw_write (sw
, buf
, len
);
509 static int coreaudio_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
513 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
515 const char *typ
= "playback";
516 AudioValueRange frameRange
;
517 CoreaudioConf
*conf
= drv_opaque
;
520 err
= pthread_mutex_init(&core
->mutex
, NULL
);
522 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
526 audio_pcm_init_info (&hw
->info
, as
);
528 status
= coreaudio_get_voice(&core
->outputDeviceID
);
529 if (status
!= kAudioHardwareNoError
) {
530 coreaudio_logerr2 (status
, typ
,
531 "Could not get default output Device\n");
534 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
535 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
539 /* get minimum and maximum buffer frame sizes */
540 status
= coreaudio_get_framesizerange(core
->outputDeviceID
,
542 if (status
!= kAudioHardwareNoError
) {
543 coreaudio_logerr2 (status
, typ
,
544 "Could not get device buffer frame range\n");
548 if (frameRange
.mMinimum
> conf
->buffer_frames
) {
549 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
550 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
552 else if (frameRange
.mMaximum
< conf
->buffer_frames
) {
553 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
554 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
557 core
->audioDevicePropertyBufferFrameSize
= conf
->buffer_frames
;
560 /* set Buffer Frame Size */
561 status
= coreaudio_set_framesize(core
->outputDeviceID
,
562 &core
->audioDevicePropertyBufferFrameSize
);
563 if (status
!= kAudioHardwareNoError
) {
564 coreaudio_logerr2 (status
, typ
,
565 "Could not set device buffer frame size %" PRIu32
"\n",
566 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
570 /* get Buffer Frame Size */
571 status
= coreaudio_get_framesize(core
->outputDeviceID
,
572 &core
->audioDevicePropertyBufferFrameSize
);
573 if (status
!= kAudioHardwareNoError
) {
574 coreaudio_logerr2 (status
, typ
,
575 "Could not get device buffer frame size\n");
578 hw
->samples
= conf
->nbuffers
* core
->audioDevicePropertyBufferFrameSize
;
580 /* get StreamFormat */
581 status
= coreaudio_get_streamformat(core
->outputDeviceID
,
582 &core
->outputStreamBasicDescription
);
583 if (status
!= kAudioHardwareNoError
) {
584 coreaudio_logerr2 (status
, typ
,
585 "Could not get Device Stream properties\n");
586 core
->outputDeviceID
= kAudioDeviceUnknown
;
591 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
592 status
= coreaudio_set_streamformat(core
->outputDeviceID
,
593 &core
->outputStreamBasicDescription
);
594 if (status
!= kAudioHardwareNoError
) {
595 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
597 core
->outputDeviceID
= kAudioDeviceUnknown
;
602 core
->ioprocid
= NULL
;
603 status
= AudioDeviceCreateIOProcID(core
->outputDeviceID
,
607 if (status
!= kAudioHardwareNoError
|| core
->ioprocid
== NULL
) {
608 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
609 core
->outputDeviceID
= kAudioDeviceUnknown
;
614 if (!isPlaying(core
->outputDeviceID
)) {
615 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
616 if (status
!= kAudioHardwareNoError
) {
617 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
618 AudioDeviceDestroyIOProcID(core
->outputDeviceID
, core
->ioprocid
);
619 core
->outputDeviceID
= kAudioDeviceUnknown
;
627 static void coreaudio_fini_out (HWVoiceOut
*hw
)
631 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
635 if (isPlaying(core
->outputDeviceID
)) {
636 status
= AudioDeviceStop(core
->outputDeviceID
, core
->ioprocid
);
637 if (status
!= kAudioHardwareNoError
) {
638 coreaudio_logerr (status
, "Could not stop playback\n");
642 /* remove callback */
643 status
= AudioDeviceDestroyIOProcID(core
->outputDeviceID
,
645 if (status
!= kAudioHardwareNoError
) {
646 coreaudio_logerr (status
, "Could not remove IOProc\n");
649 core
->outputDeviceID
= kAudioDeviceUnknown
;
652 err
= pthread_mutex_destroy(&core
->mutex
);
654 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
658 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
661 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
666 if (!isPlaying(core
->outputDeviceID
)) {
667 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
668 if (status
!= kAudioHardwareNoError
) {
669 coreaudio_logerr (status
, "Could not resume playback\n");
677 if (isPlaying(core
->outputDeviceID
)) {
678 status
= AudioDeviceStop(core
->outputDeviceID
,
680 if (status
!= kAudioHardwareNoError
) {
681 coreaudio_logerr (status
, "Could not pause playback\n");
690 static CoreaudioConf glob_conf
= {
691 .buffer_frames
= 512,
695 static void *coreaudio_audio_init (void)
697 CoreaudioConf
*conf
= g_malloc(sizeof(CoreaudioConf
));
700 atexit(coreaudio_atexit
);
704 static void coreaudio_audio_fini (void *opaque
)
709 static struct audio_option coreaudio_options
[] = {
711 .name
= "BUFFER_SIZE",
713 .valp
= &glob_conf
.buffer_frames
,
714 .descr
= "Size of the buffer in frames"
717 .name
= "BUFFER_COUNT",
719 .valp
= &glob_conf
.nbuffers
,
720 .descr
= "Number of buffers"
722 { /* End of list */ }
725 static struct audio_pcm_ops coreaudio_pcm_ops
= {
726 .init_out
= coreaudio_init_out
,
727 .fini_out
= coreaudio_fini_out
,
728 .run_out
= coreaudio_run_out
,
729 .write
= coreaudio_write
,
730 .ctl_out
= coreaudio_ctl_out
733 struct audio_driver coreaudio_audio_driver
= {
735 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
736 .options
= coreaudio_options
,
737 .init
= coreaudio_audio_init
,
738 .fini
= coreaudio_audio_fini
,
739 .pcm_ops
= &coreaudio_pcm_ops
,
743 .voice_size_out
= sizeof (coreaudioVoiceOut
),