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 */
31 #define AUDIO_CAP "coreaudio"
32 #include "audio_int.h"
44 typedef struct coreaudioVoiceOut
{
46 pthread_mutex_t mutex
;
48 AudioDeviceID outputDeviceID
;
49 UInt32 audioDevicePropertyBufferFrameSize
;
50 AudioStreamBasicDescription outputStreamBasicDescription
;
56 static void coreaudio_logstatus (OSStatus status
)
61 case kAudioHardwareNoError
:
62 str
= "kAudioHardwareNoError";
65 case kAudioHardwareNotRunningError
:
66 str
= "kAudioHardwareNotRunningError";
69 case kAudioHardwareUnspecifiedError
:
70 str
= "kAudioHardwareUnspecifiedError";
73 case kAudioHardwareUnknownPropertyError
:
74 str
= "kAudioHardwareUnknownPropertyError";
77 case kAudioHardwareBadPropertySizeError
:
78 str
= "kAudioHardwareBadPropertySizeError";
81 case kAudioHardwareIllegalOperationError
:
82 str
= "kAudioHardwareIllegalOperationError";
85 case kAudioHardwareBadDeviceError
:
86 str
= "kAudioHardwareBadDeviceError";
89 case kAudioHardwareBadStreamError
:
90 str
= "kAudioHardwareBadStreamError";
93 case kAudioHardwareUnsupportedOperationError
:
94 str
= "kAudioHardwareUnsupportedOperationError";
97 case kAudioDeviceUnsupportedFormatError
:
98 str
= "kAudioDeviceUnsupportedFormatError";
101 case kAudioDevicePermissionsError
:
102 str
= "kAudioDevicePermissionsError";
106 AUD_log (AUDIO_CAP
, "Reason: status code %ld\n", status
);
110 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
113 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
122 AUD_log (AUDIO_CAP
, fmt
, ap
);
125 coreaudio_logstatus (status
);
128 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
137 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
140 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
143 coreaudio_logstatus (status
);
146 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
150 UInt32 propertySize
= sizeof(outputDeviceID
);
151 status
= AudioDeviceGetProperty(
152 outputDeviceID
, 0, 0,
153 kAudioDevicePropertyDeviceIsRunning
, &propertySize
, &result
);
154 if (status
!= kAudioHardwareNoError
) {
155 coreaudio_logerr(status
,
156 "Could not determine whether Device is playing\n");
161 static void coreaudio_atexit (void)
166 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
170 err
= pthread_mutex_lock (&core
->mutex
);
172 dolog ("Could not lock voice for %s\nReason: %s\n",
173 fn_name
, strerror (err
));
179 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
183 err
= pthread_mutex_unlock (&core
->mutex
);
185 dolog ("Could not unlock voice for %s\nReason: %s\n",
186 fn_name
, strerror (err
));
192 static int coreaudio_run_out (HWVoiceOut
*hw
)
195 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
197 if (coreaudio_lock (core
, "coreaudio_run_out")) {
201 live
= audio_pcm_hw_get_live_out (hw
);
203 if (core
->decr
> live
) {
204 ldebug ("core->decr %d live %d core->live %d\n",
210 decr
= audio_MIN (core
->decr
, live
);
213 core
->live
= live
- decr
;
214 hw
->rpos
= core
->rpos
;
216 coreaudio_unlock (core
, "coreaudio_run_out");
220 /* callback to feed audiooutput buffer */
221 static OSStatus
audioDeviceIOProc(
222 AudioDeviceID inDevice
,
223 const AudioTimeStamp
* inNow
,
224 const AudioBufferList
* inInputData
,
225 const AudioTimeStamp
* inInputTime
,
226 AudioBufferList
* outOutputData
,
227 const AudioTimeStamp
* inOutputTime
,
230 UInt32 frame
, frameCount
;
231 float *out
= outOutputData
->mBuffers
[0].mData
;
232 HWVoiceOut
*hw
= hwptr
;
233 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
238 const float scale
= 1.f
/ UINT_MAX
;
240 const float scale
= UINT_MAX
;
244 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
249 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
252 /* if there are not enough samples, set signal and return */
253 if (live
< frameCount
) {
255 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
260 src
= hw
->mix_buf
+ rpos
;
263 for (frame
= 0; frame
< frameCount
; frame
++) {
265 *out
++ = src
[frame
].l
; /* left channel */
266 *out
++ = src
[frame
].r
; /* right channel */
269 *out
++ = src
[frame
].l
* scale
; /* left channel */
270 *out
++ = src
[frame
].r
* scale
; /* right channel */
272 *out
++ = src
[frame
].l
/ scale
; /* left channel */
273 *out
++ = src
[frame
].r
/ scale
; /* right channel */
279 mixeng_clear (src
, frameCount
);
280 rpos
= (rpos
+ frameCount
) % hw
->samples
;
281 core
->decr
+= frameCount
;
284 coreaudio_unlock (core
, "audioDeviceIOProc");
288 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
290 return audio_pcm_sw_write (sw
, buf
, len
);
293 static int coreaudio_init_out (HWVoiceOut
*hw
, audsettings_t
*as
)
296 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
301 const char *typ
= "playback";
302 AudioValueRange frameRange
;
305 err
= pthread_mutex_init(&core
->mutex
, NULL
);
307 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
311 if (as
->fmt
== AUD_FMT_S16
|| as
->fmt
== AUD_FMT_U16
) {
316 audio_pcm_init_info (
319 /* Following is irrelevant actually since we do not use
320 mixengs clipping routines */
321 audio_need_to_swap_endian (endianess
)
324 /* open default output device */
325 propertySize
= sizeof(core
->outputDeviceID
);
326 status
= AudioHardwareGetProperty(
327 kAudioHardwarePropertyDefaultOutputDevice
,
329 &core
->outputDeviceID
);
330 if (status
!= kAudioHardwareNoError
) {
331 coreaudio_logerr2 (status
, typ
,
332 "Could not get default output Device\n");
335 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
336 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
340 /* get minimum and maximum buffer frame sizes */
341 propertySize
= sizeof(frameRange
);
342 status
= AudioDeviceGetProperty(
343 core
->outputDeviceID
,
346 kAudioDevicePropertyBufferFrameSizeRange
,
349 if (status
!= kAudioHardwareNoError
) {
350 coreaudio_logerr2 (status
, typ
,
351 "Could not get device buffer frame range\n");
355 if (frameRange
.mMinimum
> conf
.buffer_frames
) {
356 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
357 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
359 else if (frameRange
.mMaximum
< conf
.buffer_frames
) {
360 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
361 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
364 core
->audioDevicePropertyBufferFrameSize
= conf
.buffer_frames
;
367 /* set Buffer Frame Size */
368 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
369 status
= AudioDeviceSetProperty(
370 core
->outputDeviceID
,
374 kAudioDevicePropertyBufferFrameSize
,
376 &core
->audioDevicePropertyBufferFrameSize
);
377 if (status
!= kAudioHardwareNoError
) {
378 coreaudio_logerr2 (status
, typ
,
379 "Could not set device buffer frame size %ld\n",
380 core
->audioDevicePropertyBufferFrameSize
);
384 /* get Buffer Frame Size */
385 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
386 status
= AudioDeviceGetProperty(
387 core
->outputDeviceID
,
390 kAudioDevicePropertyBufferFrameSize
,
392 &core
->audioDevicePropertyBufferFrameSize
);
393 if (status
!= kAudioHardwareNoError
) {
394 coreaudio_logerr2 (status
, typ
,
395 "Could not get device buffer frame size\n");
398 hw
->samples
= conf
.nbuffers
* core
->audioDevicePropertyBufferFrameSize
;
400 /* get StreamFormat */
401 propertySize
= sizeof(core
->outputStreamBasicDescription
);
402 status
= AudioDeviceGetProperty(
403 core
->outputDeviceID
,
406 kAudioDevicePropertyStreamFormat
,
408 &core
->outputStreamBasicDescription
);
409 if (status
!= kAudioHardwareNoError
) {
410 coreaudio_logerr2 (status
, typ
,
411 "Could not get Device Stream properties\n");
412 core
->outputDeviceID
= kAudioDeviceUnknown
;
417 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
418 propertySize
= sizeof(core
->outputStreamBasicDescription
);
419 status
= AudioDeviceSetProperty(
420 core
->outputDeviceID
,
424 kAudioDevicePropertyStreamFormat
,
426 &core
->outputStreamBasicDescription
);
427 if (status
!= kAudioHardwareNoError
) {
428 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
430 core
->outputDeviceID
= kAudioDeviceUnknown
;
435 status
= AudioDeviceAddIOProc(core
->outputDeviceID
, audioDeviceIOProc
, hw
);
436 if (status
!= kAudioHardwareNoError
) {
437 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
438 core
->outputDeviceID
= kAudioDeviceUnknown
;
443 if (!isPlaying(core
->outputDeviceID
)) {
444 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
445 if (status
!= kAudioHardwareNoError
) {
446 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
447 AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
448 core
->outputDeviceID
= kAudioDeviceUnknown
;
456 static void coreaudio_fini_out (HWVoiceOut
*hw
)
460 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
462 if (!conf
.isAtexit
) {
464 if (isPlaying(core
->outputDeviceID
)) {
465 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
466 if (status
!= kAudioHardwareNoError
) {
467 coreaudio_logerr (status
, "Could not stop playback\n");
471 /* remove callback */
472 status
= AudioDeviceRemoveIOProc(core
->outputDeviceID
,
474 if (status
!= kAudioHardwareNoError
) {
475 coreaudio_logerr (status
, "Could not remove IOProc\n");
478 core
->outputDeviceID
= kAudioDeviceUnknown
;
481 err
= pthread_mutex_destroy(&core
->mutex
);
483 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
487 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
490 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
495 if (!isPlaying(core
->outputDeviceID
)) {
496 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
497 if (status
!= kAudioHardwareNoError
) {
498 coreaudio_logerr (status
, "Could not resume playback\n");
505 if (!conf
.isAtexit
) {
506 if (isPlaying(core
->outputDeviceID
)) {
507 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
508 if (status
!= kAudioHardwareNoError
) {
509 coreaudio_logerr (status
, "Could not pause playback\n");
518 static void *coreaudio_audio_init (void)
520 atexit(coreaudio_atexit
);
521 return &coreaudio_audio_init
;
524 static void coreaudio_audio_fini (void *opaque
)
529 static struct audio_option coreaudio_options
[] = {
530 {"BUFFER_SIZE", AUD_OPT_INT
, &conf
.buffer_frames
,
531 "Size of the buffer in frames", NULL
, 0},
532 {"BUFFER_COUNT", AUD_OPT_INT
, &conf
.nbuffers
,
533 "Number of buffers", NULL
, 0},
534 {NULL
, 0, NULL
, NULL
, NULL
, 0}
537 static struct audio_pcm_ops coreaudio_pcm_ops
= {
551 struct audio_driver coreaudio_audio_driver
= {
552 INIT_FIELD (name
= ) "coreaudio",
553 INIT_FIELD (descr
= )
554 "CoreAudio http://developer.apple.com/audio/coreaudio.html",
555 INIT_FIELD (options
= ) coreaudio_options
,
556 INIT_FIELD (init
= ) coreaudio_audio_init
,
557 INIT_FIELD (fini
= ) coreaudio_audio_fini
,
558 INIT_FIELD (pcm_ops
= ) &coreaudio_pcm_ops
,
559 INIT_FIELD (can_be_default
= ) 1,
560 INIT_FIELD (max_voices_out
= ) 1,
561 INIT_FIELD (max_voices_in
= ) 0,
562 INIT_FIELD (voice_size_out
= ) sizeof (coreaudioVoiceOut
),
563 INIT_FIELD (voice_size_in
= ) 0