audio/coreaudio.c: Use new-in-OSX-10.6 API for getting default voice
[qemu/ar7.git] / audio / coreaudio.c
blob2211e179980ee513641da4e3408d193391409269
1 /*
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
22 * THE SOFTWARE.
25 #include <CoreAudio/CoreAudio.h>
26 #include <string.h> /* strerror */
27 #include <pthread.h> /* pthread_X */
29 #include "qemu-common.h"
30 #include "audio.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
37 #endif
39 static int isAtexit;
41 typedef struct {
42 int buffer_frames;
43 int nbuffers;
44 } CoreaudioConf;
46 typedef struct coreaudioVoiceOut {
47 HWVoiceOut hw;
48 pthread_mutex_t mutex;
49 AudioDeviceID outputDeviceID;
50 UInt32 audioDevicePropertyBufferFrameSize;
51 AudioStreamBasicDescription outputStreamBasicDescription;
52 int live;
53 int decr;
54 int rpos;
55 } coreaudioVoiceOut;
57 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
58 /* The APIs used here only become available from 10.6 */
60 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
62 UInt32 size = sizeof(*id);
63 AudioObjectPropertyAddress addr = {
64 kAudioHardwarePropertyDefaultOutputDevice,
65 kAudioObjectPropertyScopeGlobal,
66 kAudioObjectPropertyElementMaster
69 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
70 &addr,
72 NULL,
73 &size,
74 id);
76 #else
77 /* Legacy versions of functions using deprecated APIs */
79 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
81 UInt32 size = sizeof(*id);
83 return AudioHardwareGetProperty(
84 kAudioHardwarePropertyDefaultOutputDevice,
85 &size,
86 id);
88 #endif
90 static void coreaudio_logstatus (OSStatus status)
92 const char *str = "BUG";
94 switch(status) {
95 case kAudioHardwareNoError:
96 str = "kAudioHardwareNoError";
97 break;
99 case kAudioHardwareNotRunningError:
100 str = "kAudioHardwareNotRunningError";
101 break;
103 case kAudioHardwareUnspecifiedError:
104 str = "kAudioHardwareUnspecifiedError";
105 break;
107 case kAudioHardwareUnknownPropertyError:
108 str = "kAudioHardwareUnknownPropertyError";
109 break;
111 case kAudioHardwareBadPropertySizeError:
112 str = "kAudioHardwareBadPropertySizeError";
113 break;
115 case kAudioHardwareIllegalOperationError:
116 str = "kAudioHardwareIllegalOperationError";
117 break;
119 case kAudioHardwareBadDeviceError:
120 str = "kAudioHardwareBadDeviceError";
121 break;
123 case kAudioHardwareBadStreamError:
124 str = "kAudioHardwareBadStreamError";
125 break;
127 case kAudioHardwareUnsupportedOperationError:
128 str = "kAudioHardwareUnsupportedOperationError";
129 break;
131 case kAudioDeviceUnsupportedFormatError:
132 str = "kAudioDeviceUnsupportedFormatError";
133 break;
135 case kAudioDevicePermissionsError:
136 str = "kAudioDevicePermissionsError";
137 break;
139 default:
140 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
141 return;
144 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
147 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
148 OSStatus status,
149 const char *fmt,
153 va_list ap;
155 va_start (ap, fmt);
156 AUD_log (AUDIO_CAP, fmt, ap);
157 va_end (ap);
159 coreaudio_logstatus (status);
162 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
163 OSStatus status,
164 const char *typ,
165 const char *fmt,
169 va_list ap;
171 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
173 va_start (ap, fmt);
174 AUD_vlog (AUDIO_CAP, fmt, ap);
175 va_end (ap);
177 coreaudio_logstatus (status);
180 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
182 OSStatus status;
183 UInt32 result = 0;
184 UInt32 propertySize = sizeof(outputDeviceID);
185 status = AudioDeviceGetProperty(
186 outputDeviceID, 0, 0,
187 kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
188 if (status != kAudioHardwareNoError) {
189 coreaudio_logerr(status,
190 "Could not determine whether Device is playing\n");
192 return result;
195 static void coreaudio_atexit (void)
197 isAtexit = 1;
200 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
202 int err;
204 err = pthread_mutex_lock (&core->mutex);
205 if (err) {
206 dolog ("Could not lock voice for %s\nReason: %s\n",
207 fn_name, strerror (err));
208 return -1;
210 return 0;
213 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
215 int err;
217 err = pthread_mutex_unlock (&core->mutex);
218 if (err) {
219 dolog ("Could not unlock voice for %s\nReason: %s\n",
220 fn_name, strerror (err));
221 return -1;
223 return 0;
226 static int coreaudio_run_out (HWVoiceOut *hw, int live)
228 int decr;
229 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
231 if (coreaudio_lock (core, "coreaudio_run_out")) {
232 return 0;
235 if (core->decr > live) {
236 ldebug ("core->decr %d live %d core->live %d\n",
237 core->decr,
238 live,
239 core->live);
242 decr = audio_MIN (core->decr, live);
243 core->decr -= decr;
245 core->live = live - decr;
246 hw->rpos = core->rpos;
248 coreaudio_unlock (core, "coreaudio_run_out");
249 return decr;
252 /* callback to feed audiooutput buffer */
253 static OSStatus audioDeviceIOProc(
254 AudioDeviceID inDevice,
255 const AudioTimeStamp* inNow,
256 const AudioBufferList* inInputData,
257 const AudioTimeStamp* inInputTime,
258 AudioBufferList* outOutputData,
259 const AudioTimeStamp* inOutputTime,
260 void* hwptr)
262 UInt32 frame, frameCount;
263 float *out = outOutputData->mBuffers[0].mData;
264 HWVoiceOut *hw = hwptr;
265 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
266 int rpos, live;
267 struct st_sample *src;
268 #ifndef FLOAT_MIXENG
269 #ifdef RECIPROCAL
270 const float scale = 1.f / UINT_MAX;
271 #else
272 const float scale = UINT_MAX;
273 #endif
274 #endif
276 if (coreaudio_lock (core, "audioDeviceIOProc")) {
277 inInputTime = 0;
278 return 0;
281 frameCount = core->audioDevicePropertyBufferFrameSize;
282 live = core->live;
284 /* if there are not enough samples, set signal and return */
285 if (live < frameCount) {
286 inInputTime = 0;
287 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
288 return 0;
291 rpos = core->rpos;
292 src = hw->mix_buf + rpos;
294 /* fill buffer */
295 for (frame = 0; frame < frameCount; frame++) {
296 #ifdef FLOAT_MIXENG
297 *out++ = src[frame].l; /* left channel */
298 *out++ = src[frame].r; /* right channel */
299 #else
300 #ifdef RECIPROCAL
301 *out++ = src[frame].l * scale; /* left channel */
302 *out++ = src[frame].r * scale; /* right channel */
303 #else
304 *out++ = src[frame].l / scale; /* left channel */
305 *out++ = src[frame].r / scale; /* right channel */
306 #endif
307 #endif
310 rpos = (rpos + frameCount) % hw->samples;
311 core->decr += frameCount;
312 core->rpos = rpos;
314 coreaudio_unlock (core, "audioDeviceIOProc");
315 return 0;
318 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
320 return audio_pcm_sw_write (sw, buf, len);
323 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
324 void *drv_opaque)
326 OSStatus status;
327 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
328 UInt32 propertySize;
329 int err;
330 const char *typ = "playback";
331 AudioValueRange frameRange;
332 CoreaudioConf *conf = drv_opaque;
334 /* create mutex */
335 err = pthread_mutex_init(&core->mutex, NULL);
336 if (err) {
337 dolog("Could not create mutex\nReason: %s\n", strerror (err));
338 return -1;
341 audio_pcm_init_info (&hw->info, as);
343 status = coreaudio_get_voice(&core->outputDeviceID);
344 if (status != kAudioHardwareNoError) {
345 coreaudio_logerr2 (status, typ,
346 "Could not get default output Device\n");
347 return -1;
349 if (core->outputDeviceID == kAudioDeviceUnknown) {
350 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
351 return -1;
354 /* get minimum and maximum buffer frame sizes */
355 propertySize = sizeof(frameRange);
356 status = AudioDeviceGetProperty(
357 core->outputDeviceID,
360 kAudioDevicePropertyBufferFrameSizeRange,
361 &propertySize,
362 &frameRange);
363 if (status != kAudioHardwareNoError) {
364 coreaudio_logerr2 (status, typ,
365 "Could not get device buffer frame range\n");
366 return -1;
369 if (frameRange.mMinimum > conf->buffer_frames) {
370 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
371 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
373 else if (frameRange.mMaximum < conf->buffer_frames) {
374 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
375 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
377 else {
378 core->audioDevicePropertyBufferFrameSize = conf->buffer_frames;
381 /* set Buffer Frame Size */
382 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
383 status = AudioDeviceSetProperty(
384 core->outputDeviceID,
385 NULL,
387 false,
388 kAudioDevicePropertyBufferFrameSize,
389 propertySize,
390 &core->audioDevicePropertyBufferFrameSize);
391 if (status != kAudioHardwareNoError) {
392 coreaudio_logerr2 (status, typ,
393 "Could not set device buffer frame size %" PRIu32 "\n",
394 (uint32_t)core->audioDevicePropertyBufferFrameSize);
395 return -1;
398 /* get Buffer Frame Size */
399 propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
400 status = AudioDeviceGetProperty(
401 core->outputDeviceID,
403 false,
404 kAudioDevicePropertyBufferFrameSize,
405 &propertySize,
406 &core->audioDevicePropertyBufferFrameSize);
407 if (status != kAudioHardwareNoError) {
408 coreaudio_logerr2 (status, typ,
409 "Could not get device buffer frame size\n");
410 return -1;
412 hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize;
414 /* get StreamFormat */
415 propertySize = sizeof(core->outputStreamBasicDescription);
416 status = AudioDeviceGetProperty(
417 core->outputDeviceID,
419 false,
420 kAudioDevicePropertyStreamFormat,
421 &propertySize,
422 &core->outputStreamBasicDescription);
423 if (status != kAudioHardwareNoError) {
424 coreaudio_logerr2 (status, typ,
425 "Could not get Device Stream properties\n");
426 core->outputDeviceID = kAudioDeviceUnknown;
427 return -1;
430 /* set Samplerate */
431 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
432 propertySize = sizeof(core->outputStreamBasicDescription);
433 status = AudioDeviceSetProperty(
434 core->outputDeviceID,
438 kAudioDevicePropertyStreamFormat,
439 propertySize,
440 &core->outputStreamBasicDescription);
441 if (status != kAudioHardwareNoError) {
442 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
443 as->freq);
444 core->outputDeviceID = kAudioDeviceUnknown;
445 return -1;
448 /* set Callback */
449 status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
450 if (status != kAudioHardwareNoError) {
451 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
452 core->outputDeviceID = kAudioDeviceUnknown;
453 return -1;
456 /* start Playback */
457 if (!isPlaying(core->outputDeviceID)) {
458 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
459 if (status != kAudioHardwareNoError) {
460 coreaudio_logerr2 (status, typ, "Could not start playback\n");
461 AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
462 core->outputDeviceID = kAudioDeviceUnknown;
463 return -1;
467 return 0;
470 static void coreaudio_fini_out (HWVoiceOut *hw)
472 OSStatus status;
473 int err;
474 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
476 if (!isAtexit) {
477 /* stop playback */
478 if (isPlaying(core->outputDeviceID)) {
479 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
480 if (status != kAudioHardwareNoError) {
481 coreaudio_logerr (status, "Could not stop playback\n");
485 /* remove callback */
486 status = AudioDeviceRemoveIOProc(core->outputDeviceID,
487 audioDeviceIOProc);
488 if (status != kAudioHardwareNoError) {
489 coreaudio_logerr (status, "Could not remove IOProc\n");
492 core->outputDeviceID = kAudioDeviceUnknown;
494 /* destroy mutex */
495 err = pthread_mutex_destroy(&core->mutex);
496 if (err) {
497 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
501 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
503 OSStatus status;
504 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
506 switch (cmd) {
507 case VOICE_ENABLE:
508 /* start playback */
509 if (!isPlaying(core->outputDeviceID)) {
510 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
511 if (status != kAudioHardwareNoError) {
512 coreaudio_logerr (status, "Could not resume playback\n");
515 break;
517 case VOICE_DISABLE:
518 /* stop playback */
519 if (!isAtexit) {
520 if (isPlaying(core->outputDeviceID)) {
521 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
522 if (status != kAudioHardwareNoError) {
523 coreaudio_logerr (status, "Could not pause playback\n");
527 break;
529 return 0;
532 static CoreaudioConf glob_conf = {
533 .buffer_frames = 512,
534 .nbuffers = 4,
537 static void *coreaudio_audio_init (void)
539 CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf));
540 *conf = glob_conf;
542 atexit(coreaudio_atexit);
543 return conf;
546 static void coreaudio_audio_fini (void *opaque)
548 g_free(opaque);
551 static struct audio_option coreaudio_options[] = {
553 .name = "BUFFER_SIZE",
554 .tag = AUD_OPT_INT,
555 .valp = &glob_conf.buffer_frames,
556 .descr = "Size of the buffer in frames"
559 .name = "BUFFER_COUNT",
560 .tag = AUD_OPT_INT,
561 .valp = &glob_conf.nbuffers,
562 .descr = "Number of buffers"
564 { /* End of list */ }
567 static struct audio_pcm_ops coreaudio_pcm_ops = {
568 .init_out = coreaudio_init_out,
569 .fini_out = coreaudio_fini_out,
570 .run_out = coreaudio_run_out,
571 .write = coreaudio_write,
572 .ctl_out = coreaudio_ctl_out
575 struct audio_driver coreaudio_audio_driver = {
576 .name = "coreaudio",
577 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
578 .options = coreaudio_options,
579 .init = coreaudio_audio_init,
580 .fini = coreaudio_audio_fini,
581 .pcm_ops = &coreaudio_pcm_ops,
582 .can_be_default = 1,
583 .max_voices_out = 1,
584 .max_voices_in = 0,
585 .voice_size_out = sizeof (coreaudioVoiceOut),
586 .voice_size_in = 0