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 */
278 rpos = (rpos + frameCount) % hw->samples;
279 core->decr += frameCount;
282 coreaudio_unlock (core, "audioDeviceIOProc");
286 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
288 return audio_pcm_sw_write (sw, buf, len);
291 static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
294 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
297 const char *typ = "playback";
298 AudioValueRange frameRange;
301 err = pthread_mutex_init(&core->mutex, NULL);
303 dolog("Could not create mutex\nReason: %s\n", strerror (err));
307 audio_pcm_init_info (&hw->info, as);
309 /* open default output device */
310 propertySize = sizeof(core->outputDeviceID);
311 status = AudioHardwareGetProperty(
312 kAudioHardwarePropertyDefaultOutputDevice,
314 &core->outputDeviceID);
315 if (status != kAudioHardwareNoError) {
316 coreaudio_logerr2 (status, typ,
317 "Could not get default output Device\n");
320 if (core->outputDeviceID == kAudioDeviceUnknown) {
321 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
325 /* get minimum and maximum buffer frame sizes */
326 propertySize = sizeof(frameRange);
327 status = AudioDeviceGetProperty(
328 core->outputDeviceID,
331 kAudioDevicePropertyBufferFrameSizeRange,
334 if (status != kAudioHardwareNoError) {
335 coreaudio_logerr2 (status, typ,
336 "Could not get device buffer frame range\n");
340 if (frameRange.mMinimum > conf.buffer_frames) {
341 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
342 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
344 else if (frameRange.mMaximum < conf.buffer_frames) {
345 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
346 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
349 core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
352 /* set Buffer Frame Size */
353 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
354 status = AudioDeviceSetProperty(
355 core->outputDeviceID,
359 kAudioDevicePropertyBufferFrameSize,
361 &core->audioDevicePropertyBufferFrameSize);
362 if (status != kAudioHardwareNoError) {
363 coreaudio_logerr2 (status, typ,
364 "Could not set device buffer frame size %ld\n",
365 core->audioDevicePropertyBufferFrameSize);
369 /* get Buffer Frame Size */
370 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
371 status = AudioDeviceGetProperty(
372 core->outputDeviceID,
375 kAudioDevicePropertyBufferFrameSize,
377 &core->audioDevicePropertyBufferFrameSize);
378 if (status != kAudioHardwareNoError) {
379 coreaudio_logerr2 (status, typ,
380 "Could not get device buffer frame size\n");
383 hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
385 /* get StreamFormat */
386 propertySize = sizeof(core->outputStreamBasicDescription);
387 status = AudioDeviceGetProperty(
388 core->outputDeviceID,
391 kAudioDevicePropertyStreamFormat,
393 &core->outputStreamBasicDescription);
394 if (status != kAudioHardwareNoError) {
395 coreaudio_logerr2 (status, typ,
396 "Could not get Device Stream properties\n");
397 core->outputDeviceID = kAudioDeviceUnknown;
402 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
403 propertySize = sizeof(core->outputStreamBasicDescription);
404 status = AudioDeviceSetProperty(
405 core->outputDeviceID,
409 kAudioDevicePropertyStreamFormat,
411 &core->outputStreamBasicDescription);
412 if (status != kAudioHardwareNoError) {
413 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
415 core->outputDeviceID = kAudioDeviceUnknown;
420 status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
421 if (status != kAudioHardwareNoError) {
422 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
423 core->outputDeviceID = kAudioDeviceUnknown;
428 if (!isPlaying(core->outputDeviceID)) {
429 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
430 if (status != kAudioHardwareNoError) {
431 coreaudio_logerr2 (status, typ, "Could not start playback\n");
432 AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
433 core->outputDeviceID = kAudioDeviceUnknown;
441 static void coreaudio_fini_out (HWVoiceOut *hw)
445 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
447 if (!conf.isAtexit) {
449 if (isPlaying(core->outputDeviceID)) {
450 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
451 if (status != kAudioHardwareNoError) {
452 coreaudio_logerr (status, "Could not stop playback\n");
456 /* remove callback */
457 status = AudioDeviceRemoveIOProc(core->outputDeviceID,
459 if (status != kAudioHardwareNoError) {
460 coreaudio_logerr (status, "Could not remove IOProc\n");
463 core->outputDeviceID = kAudioDeviceUnknown;
466 err = pthread_mutex_destroy(&core->mutex);
468 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
472 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
475 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
480 if (!isPlaying(core->outputDeviceID)) {
481 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
482 if (status != kAudioHardwareNoError) {
483 coreaudio_logerr (status, "Could not resume playback\n");
490 if (!conf.isAtexit) {
491 if (isPlaying(core->outputDeviceID)) {
492 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
493 if (status != kAudioHardwareNoError) {
494 coreaudio_logerr (status, "Could not pause playback\n");
503 static void *coreaudio_audio_init (void)
505 atexit(coreaudio_atexit);
506 return &coreaudio_audio_init;
509 static void coreaudio_audio_fini (void *opaque)
514 static struct audio_option coreaudio_options[] = {
515 {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
516 "Size of the buffer in frames", NULL, 0},
517 {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
518 "Number of buffers", NULL, 0},
519 {NULL, 0, NULL, NULL, NULL, 0}
522 static struct audio_pcm_ops coreaudio_pcm_ops = {
536 struct audio_driver coreaudio_audio_driver = {
537 INIT_FIELD (name = ) "coreaudio",
538 INIT_FIELD (descr = )
539 "CoreAudio http://developer.apple.com/audio/coreaudio.html",
540 INIT_FIELD (options = ) coreaudio_options,
541 INIT_FIELD (init = ) coreaudio_audio_init,
542 INIT_FIELD (fini = ) coreaudio_audio_fini,
543 INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
544 INIT_FIELD (can_be_default = ) 1,
545 INIT_FIELD (max_voices_out = ) 1,
546 INIT_FIELD (max_voices_in = ) 0,
547 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
548 INIT_FIELD (voice_size_in = ) 0