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/module.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 size_t coreaudio_run_out(HWVoiceOut
*hw
, size_t 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
= 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_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
496 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
498 const char *typ
= "playback";
499 AudioValueRange frameRange
;
500 Audiodev
*dev
= drv_opaque
;
501 AudiodevCoreaudioPerDirectionOptions
*cpdo
= dev
->u
.coreaudio
.out
;
505 err
= pthread_mutex_init(&core
->mutex
, NULL
);
507 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
511 audio_pcm_init_info (&hw
->info
, as
);
513 status
= coreaudio_get_voice(&core
->outputDeviceID
);
514 if (status
!= kAudioHardwareNoError
) {
515 coreaudio_logerr2 (status
, typ
,
516 "Could not get default output Device\n");
519 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
520 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
524 /* get minimum and maximum buffer frame sizes */
525 status
= coreaudio_get_framesizerange(core
->outputDeviceID
,
527 if (status
!= kAudioHardwareNoError
) {
528 coreaudio_logerr2 (status
, typ
,
529 "Could not get device buffer frame range\n");
533 frames
= audio_buffer_frames(
534 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo
), as
, 11610);
535 if (frameRange
.mMinimum
> frames
) {
536 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
537 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
538 } else if (frameRange
.mMaximum
< frames
) {
539 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
540 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
543 core
->audioDevicePropertyBufferFrameSize
= frames
;
546 /* set Buffer Frame Size */
547 status
= coreaudio_set_framesize(core
->outputDeviceID
,
548 &core
->audioDevicePropertyBufferFrameSize
);
549 if (status
!= kAudioHardwareNoError
) {
550 coreaudio_logerr2 (status
, typ
,
551 "Could not set device buffer frame size %" PRIu32
"\n",
552 (uint32_t)core
->audioDevicePropertyBufferFrameSize
);
556 /* get Buffer Frame Size */
557 status
= coreaudio_get_framesize(core
->outputDeviceID
,
558 &core
->audioDevicePropertyBufferFrameSize
);
559 if (status
!= kAudioHardwareNoError
) {
560 coreaudio_logerr2 (status
, typ
,
561 "Could not get device buffer frame size\n");
564 hw
->samples
= (cpdo
->has_buffer_count
? cpdo
->buffer_count
: 4) *
565 core
->audioDevicePropertyBufferFrameSize
;
567 /* get StreamFormat */
568 status
= coreaudio_get_streamformat(core
->outputDeviceID
,
569 &core
->outputStreamBasicDescription
);
570 if (status
!= kAudioHardwareNoError
) {
571 coreaudio_logerr2 (status
, typ
,
572 "Could not get Device Stream properties\n");
573 core
->outputDeviceID
= kAudioDeviceUnknown
;
578 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
579 status
= coreaudio_set_streamformat(core
->outputDeviceID
,
580 &core
->outputStreamBasicDescription
);
581 if (status
!= kAudioHardwareNoError
) {
582 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
584 core
->outputDeviceID
= kAudioDeviceUnknown
;
589 core
->ioprocid
= NULL
;
590 status
= AudioDeviceCreateIOProcID(core
->outputDeviceID
,
594 if (status
!= kAudioHardwareNoError
|| core
->ioprocid
== NULL
) {
595 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
596 core
->outputDeviceID
= kAudioDeviceUnknown
;
601 if (!isPlaying(core
->outputDeviceID
)) {
602 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
603 if (status
!= kAudioHardwareNoError
) {
604 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
605 AudioDeviceDestroyIOProcID(core
->outputDeviceID
, core
->ioprocid
);
606 core
->outputDeviceID
= kAudioDeviceUnknown
;
614 static void coreaudio_fini_out (HWVoiceOut
*hw
)
618 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
620 if (!audio_is_cleaning_up()) {
622 if (isPlaying(core
->outputDeviceID
)) {
623 status
= AudioDeviceStop(core
->outputDeviceID
, core
->ioprocid
);
624 if (status
!= kAudioHardwareNoError
) {
625 coreaudio_logerr (status
, "Could not stop playback\n");
629 /* remove callback */
630 status
= AudioDeviceDestroyIOProcID(core
->outputDeviceID
,
632 if (status
!= kAudioHardwareNoError
) {
633 coreaudio_logerr (status
, "Could not remove IOProc\n");
636 core
->outputDeviceID
= kAudioDeviceUnknown
;
639 err
= pthread_mutex_destroy(&core
->mutex
);
641 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
645 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
648 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
653 if (!isPlaying(core
->outputDeviceID
)) {
654 status
= AudioDeviceStart(core
->outputDeviceID
, core
->ioprocid
);
655 if (status
!= kAudioHardwareNoError
) {
656 coreaudio_logerr (status
, "Could not resume playback\n");
663 if (!audio_is_cleaning_up()) {
664 if (isPlaying(core
->outputDeviceID
)) {
665 status
= AudioDeviceStop(core
->outputDeviceID
,
667 if (status
!= kAudioHardwareNoError
) {
668 coreaudio_logerr (status
, "Could not pause playback\n");
677 static void *coreaudio_audio_init(Audiodev
*dev
)
682 static void coreaudio_audio_fini (void *opaque
)
686 static struct audio_pcm_ops coreaudio_pcm_ops
= {
687 .init_out
= coreaudio_init_out
,
688 .fini_out
= coreaudio_fini_out
,
689 .run_out
= coreaudio_run_out
,
690 .ctl_out
= coreaudio_ctl_out
693 static struct audio_driver coreaudio_audio_driver
= {
695 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
696 .init
= coreaudio_audio_init
,
697 .fini
= coreaudio_audio_fini
,
698 .pcm_ops
= &coreaudio_pcm_ops
,
702 .voice_size_out
= sizeof (coreaudioVoiceOut
),
706 static void register_audio_coreaudio(void)
708 audio_driver_register(&coreaudio_audio_driver
);
710 type_init(register_audio_coreaudio
);