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)
59 const char *str = "BUG";
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 %" PRId32 "\n", (int32_t)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 %" PRIu32 "\n",
364 (uint32_t)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),