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"
45 typedef struct coreaudioVoiceOut
{
47 pthread_mutex_t mutex
;
49 AudioDeviceID outputDeviceID
;
50 UInt32 audioDevicePropertyBufferFrameSize
;
51 AudioStreamBasicDescription outputStreamBasicDescription
;
57 static void coreaudio_logstatus (OSStatus status
)
62 case kAudioHardwareNoError
:
63 str
= "kAudioHardwareNoError";
66 case kAudioHardwareNotRunningError
:
67 str
= "kAudioHardwareNotRunningError";
70 case kAudioHardwareUnspecifiedError
:
71 str
= "kAudioHardwareUnspecifiedError";
74 case kAudioHardwareUnknownPropertyError
:
75 str
= "kAudioHardwareUnknownPropertyError";
78 case kAudioHardwareBadPropertySizeError
:
79 str
= "kAudioHardwareBadPropertySizeError";
82 case kAudioHardwareIllegalOperationError
:
83 str
= "kAudioHardwareIllegalOperationError";
86 case kAudioHardwareBadDeviceError
:
87 str
= "kAudioHardwareBadDeviceError";
90 case kAudioHardwareBadStreamError
:
91 str
= "kAudioHardwareBadStreamError";
94 case kAudioHardwareUnsupportedOperationError
:
95 str
= "kAudioHardwareUnsupportedOperationError";
98 case kAudioDeviceUnsupportedFormatError
:
99 str
= "kAudioDeviceUnsupportedFormatError";
102 case kAudioDevicePermissionsError
:
103 str
= "kAudioDevicePermissionsError";
107 AUD_log (AUDIO_CAP
, "Reason: status code %ld\n", status
);
111 AUD_log (AUDIO_CAP
, "Reason: %s\n", str
);
114 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
123 AUD_log (AUDIO_CAP
, fmt
, ap
);
126 coreaudio_logstatus (status
);
129 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
138 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
141 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
144 coreaudio_logstatus (status
);
147 static inline UInt32
isPlaying (AudioDeviceID outputDeviceID
)
151 UInt32 propertySize
= sizeof(outputDeviceID
);
152 status
= AudioDeviceGetProperty(
153 outputDeviceID
, 0, 0,
154 kAudioDevicePropertyDeviceIsRunning
, &propertySize
, &result
);
155 if (status
!= kAudioHardwareNoError
) {
156 coreaudio_logerr(status
,
157 "Could not determine whether Device is playing\n");
162 static void coreaudio_atexit (void)
167 static int coreaudio_lock (coreaudioVoiceOut
*core
, const char *fn_name
)
171 err
= pthread_mutex_lock (&core
->mutex
);
173 dolog ("Could not lock voice for %s\nReason: %s\n",
174 fn_name
, strerror (err
));
180 static int coreaudio_unlock (coreaudioVoiceOut
*core
, const char *fn_name
)
184 err
= pthread_mutex_unlock (&core
->mutex
);
186 dolog ("Could not unlock voice for %s\nReason: %s\n",
187 fn_name
, strerror (err
));
193 static int coreaudio_run_out (HWVoiceOut
*hw
, int live
)
196 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
198 if (coreaudio_lock (core
, "coreaudio_run_out")) {
202 if (core
->decr
> live
) {
203 ldebug ("core->decr %d live %d core->live %d\n",
209 decr
= audio_MIN (core
->decr
, live
);
212 core
->live
= live
- decr
;
213 hw
->rpos
= core
->rpos
;
215 coreaudio_unlock (core
, "coreaudio_run_out");
219 /* callback to feed audiooutput buffer */
220 static OSStatus
audioDeviceIOProc(
221 AudioDeviceID inDevice
,
222 const AudioTimeStamp
* inNow
,
223 const AudioBufferList
* inInputData
,
224 const AudioTimeStamp
* inInputTime
,
225 AudioBufferList
* outOutputData
,
226 const AudioTimeStamp
* inOutputTime
,
229 UInt32 frame
, frameCount
;
230 float *out
= outOutputData
->mBuffers
[0].mData
;
231 HWVoiceOut
*hw
= hwptr
;
232 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hwptr
;
234 struct st_sample
*src
;
237 const float scale
= 1.f
/ UINT_MAX
;
239 const float scale
= UINT_MAX
;
243 if (coreaudio_lock (core
, "audioDeviceIOProc")) {
248 frameCount
= core
->audioDevicePropertyBufferFrameSize
;
251 /* if there are not enough samples, set signal and return */
252 if (live
< frameCount
) {
254 coreaudio_unlock (core
, "audioDeviceIOProc(empty)");
259 src
= hw
->mix_buf
+ rpos
;
262 for (frame
= 0; frame
< frameCount
; frame
++) {
264 *out
++ = src
[frame
].l
; /* left channel */
265 *out
++ = src
[frame
].r
; /* right channel */
268 *out
++ = src
[frame
].l
* scale
; /* left channel */
269 *out
++ = src
[frame
].r
* scale
; /* right channel */
271 *out
++ = src
[frame
].l
/ scale
; /* left channel */
272 *out
++ = src
[frame
].r
/ scale
; /* right channel */
277 rpos
= (rpos
+ frameCount
) % hw
->samples
;
278 core
->decr
+= frameCount
;
281 coreaudio_unlock (core
, "audioDeviceIOProc");
285 static int coreaudio_write (SWVoiceOut
*sw
, void *buf
, int len
)
287 return audio_pcm_sw_write (sw
, buf
, len
);
290 static int coreaudio_init_out (HWVoiceOut
*hw
, struct audsettings
*as
)
293 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
296 const char *typ
= "playback";
297 AudioValueRange frameRange
;
300 err
= pthread_mutex_init(&core
->mutex
, NULL
);
302 dolog("Could not create mutex\nReason: %s\n", strerror (err
));
306 audio_pcm_init_info (&hw
->info
, as
);
308 /* open default output device */
309 propertySize
= sizeof(core
->outputDeviceID
);
310 status
= AudioHardwareGetProperty(
311 kAudioHardwarePropertyDefaultOutputDevice
,
313 &core
->outputDeviceID
);
314 if (status
!= kAudioHardwareNoError
) {
315 coreaudio_logerr2 (status
, typ
,
316 "Could not get default output Device\n");
319 if (core
->outputDeviceID
== kAudioDeviceUnknown
) {
320 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ
);
324 /* get minimum and maximum buffer frame sizes */
325 propertySize
= sizeof(frameRange
);
326 status
= AudioDeviceGetProperty(
327 core
->outputDeviceID
,
330 kAudioDevicePropertyBufferFrameSizeRange
,
333 if (status
!= kAudioHardwareNoError
) {
334 coreaudio_logerr2 (status
, typ
,
335 "Could not get device buffer frame range\n");
339 if (frameRange
.mMinimum
> conf
.buffer_frames
) {
340 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMinimum
;
341 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange
.mMinimum
);
343 else if (frameRange
.mMaximum
< conf
.buffer_frames
) {
344 core
->audioDevicePropertyBufferFrameSize
= (UInt32
) frameRange
.mMaximum
;
345 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange
.mMaximum
);
348 core
->audioDevicePropertyBufferFrameSize
= conf
.buffer_frames
;
351 /* set Buffer Frame Size */
352 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
353 status
= AudioDeviceSetProperty(
354 core
->outputDeviceID
,
358 kAudioDevicePropertyBufferFrameSize
,
360 &core
->audioDevicePropertyBufferFrameSize
);
361 if (status
!= kAudioHardwareNoError
) {
362 coreaudio_logerr2 (status
, typ
,
363 "Could not set device buffer frame size %ld\n",
364 core
->audioDevicePropertyBufferFrameSize
);
368 /* get Buffer Frame Size */
369 propertySize
= sizeof(core
->audioDevicePropertyBufferFrameSize
);
370 status
= AudioDeviceGetProperty(
371 core
->outputDeviceID
,
374 kAudioDevicePropertyBufferFrameSize
,
376 &core
->audioDevicePropertyBufferFrameSize
);
377 if (status
!= kAudioHardwareNoError
) {
378 coreaudio_logerr2 (status
, typ
,
379 "Could not get device buffer frame size\n");
382 hw
->samples
= conf
.nbuffers
* core
->audioDevicePropertyBufferFrameSize
;
384 /* get StreamFormat */
385 propertySize
= sizeof(core
->outputStreamBasicDescription
);
386 status
= AudioDeviceGetProperty(
387 core
->outputDeviceID
,
390 kAudioDevicePropertyStreamFormat
,
392 &core
->outputStreamBasicDescription
);
393 if (status
!= kAudioHardwareNoError
) {
394 coreaudio_logerr2 (status
, typ
,
395 "Could not get Device Stream properties\n");
396 core
->outputDeviceID
= kAudioDeviceUnknown
;
401 core
->outputStreamBasicDescription
.mSampleRate
= (Float64
) as
->freq
;
402 propertySize
= sizeof(core
->outputStreamBasicDescription
);
403 status
= AudioDeviceSetProperty(
404 core
->outputDeviceID
,
408 kAudioDevicePropertyStreamFormat
,
410 &core
->outputStreamBasicDescription
);
411 if (status
!= kAudioHardwareNoError
) {
412 coreaudio_logerr2 (status
, typ
, "Could not set samplerate %d\n",
414 core
->outputDeviceID
= kAudioDeviceUnknown
;
419 status
= AudioDeviceAddIOProc(core
->outputDeviceID
, audioDeviceIOProc
, hw
);
420 if (status
!= kAudioHardwareNoError
) {
421 coreaudio_logerr2 (status
, typ
, "Could not set IOProc\n");
422 core
->outputDeviceID
= kAudioDeviceUnknown
;
427 if (!isPlaying(core
->outputDeviceID
)) {
428 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
429 if (status
!= kAudioHardwareNoError
) {
430 coreaudio_logerr2 (status
, typ
, "Could not start playback\n");
431 AudioDeviceRemoveIOProc(core
->outputDeviceID
, audioDeviceIOProc
);
432 core
->outputDeviceID
= kAudioDeviceUnknown
;
440 static void coreaudio_fini_out (HWVoiceOut
*hw
)
444 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
446 if (!conf
.isAtexit
) {
448 if (isPlaying(core
->outputDeviceID
)) {
449 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
450 if (status
!= kAudioHardwareNoError
) {
451 coreaudio_logerr (status
, "Could not stop playback\n");
455 /* remove callback */
456 status
= AudioDeviceRemoveIOProc(core
->outputDeviceID
,
458 if (status
!= kAudioHardwareNoError
) {
459 coreaudio_logerr (status
, "Could not remove IOProc\n");
462 core
->outputDeviceID
= kAudioDeviceUnknown
;
465 err
= pthread_mutex_destroy(&core
->mutex
);
467 dolog("Could not destroy mutex\nReason: %s\n", strerror (err
));
471 static int coreaudio_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
474 coreaudioVoiceOut
*core
= (coreaudioVoiceOut
*) hw
;
479 if (!isPlaying(core
->outputDeviceID
)) {
480 status
= AudioDeviceStart(core
->outputDeviceID
, audioDeviceIOProc
);
481 if (status
!= kAudioHardwareNoError
) {
482 coreaudio_logerr (status
, "Could not resume playback\n");
489 if (!conf
.isAtexit
) {
490 if (isPlaying(core
->outputDeviceID
)) {
491 status
= AudioDeviceStop(core
->outputDeviceID
, audioDeviceIOProc
);
492 if (status
!= kAudioHardwareNoError
) {
493 coreaudio_logerr (status
, "Could not pause playback\n");
502 static void *coreaudio_audio_init (void)
504 atexit(coreaudio_atexit
);
505 return &coreaudio_audio_init
;
508 static void coreaudio_audio_fini (void *opaque
)
513 static struct audio_option coreaudio_options
[] = {
515 .name
= "BUFFER_SIZE",
517 .valp
= &conf
.buffer_frames
,
518 .descr
= "Size of the buffer in frames"
521 .name
= "BUFFER_COUNT",
523 .valp
= &conf
.nbuffers
,
524 .descr
= "Number of buffers"
526 { /* End of list */ }
529 static struct audio_pcm_ops coreaudio_pcm_ops
= {
530 .init_out
= coreaudio_init_out
,
531 .fini_out
= coreaudio_fini_out
,
532 .run_out
= coreaudio_run_out
,
533 .write
= coreaudio_write
,
534 .ctl_out
= coreaudio_ctl_out
537 struct audio_driver coreaudio_audio_driver
= {
539 .descr
= "CoreAudio http://developer.apple.com/audio/coreaudio.html",
540 .options
= coreaudio_options
,
541 .init
= coreaudio_audio_init
,
542 .fini
= coreaudio_audio_fini
,
543 .pcm_ops
= &coreaudio_pcm_ops
,
547 .voice_size_out
= sizeof (coreaudioVoiceOut
),