docs/devel/reset.rst: add doc about Resettable interface
[qemu/ar7.git] / audio / coreaudio.c
blob66f0f459cf09f9f796342eb89e6df929bddc3a70
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 "qemu/osdep.h"
26 #include <CoreAudio/CoreAudio.h>
27 #include <pthread.h> /* pthread_X */
29 #include "qemu/module.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 typedef struct coreaudioVoiceOut {
40 HWVoiceOut hw;
41 pthread_mutex_t mutex;
42 AudioDeviceID outputDeviceID;
43 UInt32 audioDevicePropertyBufferFrameSize;
44 AudioStreamBasicDescription outputStreamBasicDescription;
45 AudioDeviceIOProcID ioprocid;
46 } coreaudioVoiceOut;
48 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
49 /* The APIs used here only become available from 10.6 */
51 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
53 UInt32 size = sizeof(*id);
54 AudioObjectPropertyAddress addr = {
55 kAudioHardwarePropertyDefaultOutputDevice,
56 kAudioObjectPropertyScopeGlobal,
57 kAudioObjectPropertyElementMaster
60 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
61 &addr,
63 NULL,
64 &size,
65 id);
68 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
69 AudioValueRange *framerange)
71 UInt32 size = sizeof(*framerange);
72 AudioObjectPropertyAddress addr = {
73 kAudioDevicePropertyBufferFrameSizeRange,
74 kAudioDevicePropertyScopeOutput,
75 kAudioObjectPropertyElementMaster
78 return AudioObjectGetPropertyData(id,
79 &addr,
81 NULL,
82 &size,
83 framerange);
86 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
88 UInt32 size = sizeof(*framesize);
89 AudioObjectPropertyAddress addr = {
90 kAudioDevicePropertyBufferFrameSize,
91 kAudioDevicePropertyScopeOutput,
92 kAudioObjectPropertyElementMaster
95 return AudioObjectGetPropertyData(id,
96 &addr,
98 NULL,
99 &size,
100 framesize);
103 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
105 UInt32 size = sizeof(*framesize);
106 AudioObjectPropertyAddress addr = {
107 kAudioDevicePropertyBufferFrameSize,
108 kAudioDevicePropertyScopeOutput,
109 kAudioObjectPropertyElementMaster
112 return AudioObjectSetPropertyData(id,
113 &addr,
115 NULL,
116 size,
117 framesize);
120 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
121 AudioStreamBasicDescription *d)
123 UInt32 size = sizeof(*d);
124 AudioObjectPropertyAddress addr = {
125 kAudioDevicePropertyStreamFormat,
126 kAudioDevicePropertyScopeOutput,
127 kAudioObjectPropertyElementMaster
130 return AudioObjectGetPropertyData(id,
131 &addr,
133 NULL,
134 &size,
138 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
139 AudioStreamBasicDescription *d)
141 UInt32 size = sizeof(*d);
142 AudioObjectPropertyAddress addr = {
143 kAudioDevicePropertyStreamFormat,
144 kAudioDevicePropertyScopeOutput,
145 kAudioObjectPropertyElementMaster
148 return AudioObjectSetPropertyData(id,
149 &addr,
151 NULL,
152 size,
156 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
158 UInt32 size = sizeof(*result);
159 AudioObjectPropertyAddress addr = {
160 kAudioDevicePropertyDeviceIsRunning,
161 kAudioDevicePropertyScopeOutput,
162 kAudioObjectPropertyElementMaster
165 return AudioObjectGetPropertyData(id,
166 &addr,
168 NULL,
169 &size,
170 result);
172 #else
173 /* Legacy versions of functions using deprecated APIs */
175 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
177 UInt32 size = sizeof(*id);
179 return AudioHardwareGetProperty(
180 kAudioHardwarePropertyDefaultOutputDevice,
181 &size,
182 id);
185 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
186 AudioValueRange *framerange)
188 UInt32 size = sizeof(*framerange);
190 return AudioDeviceGetProperty(
194 kAudioDevicePropertyBufferFrameSizeRange,
195 &size,
196 framerange);
199 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
201 UInt32 size = sizeof(*framesize);
203 return AudioDeviceGetProperty(
206 false,
207 kAudioDevicePropertyBufferFrameSize,
208 &size,
209 framesize);
212 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
214 UInt32 size = sizeof(*framesize);
216 return AudioDeviceSetProperty(
218 NULL,
220 false,
221 kAudioDevicePropertyBufferFrameSize,
222 size,
223 framesize);
226 static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
227 AudioStreamBasicDescription *d)
229 UInt32 size = sizeof(*d);
231 return AudioDeviceGetProperty(
234 false,
235 kAudioDevicePropertyStreamFormat,
236 &size,
240 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
241 AudioStreamBasicDescription *d)
243 UInt32 size = sizeof(*d);
245 return AudioDeviceSetProperty(
250 kAudioDevicePropertyStreamFormat,
251 size,
255 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
257 UInt32 size = sizeof(*result);
259 return AudioDeviceGetProperty(
263 kAudioDevicePropertyDeviceIsRunning,
264 &size,
265 result);
267 #endif
269 static void coreaudio_logstatus (OSStatus status)
271 const char *str = "BUG";
273 switch(status) {
274 case kAudioHardwareNoError:
275 str = "kAudioHardwareNoError";
276 break;
278 case kAudioHardwareNotRunningError:
279 str = "kAudioHardwareNotRunningError";
280 break;
282 case kAudioHardwareUnspecifiedError:
283 str = "kAudioHardwareUnspecifiedError";
284 break;
286 case kAudioHardwareUnknownPropertyError:
287 str = "kAudioHardwareUnknownPropertyError";
288 break;
290 case kAudioHardwareBadPropertySizeError:
291 str = "kAudioHardwareBadPropertySizeError";
292 break;
294 case kAudioHardwareIllegalOperationError:
295 str = "kAudioHardwareIllegalOperationError";
296 break;
298 case kAudioHardwareBadDeviceError:
299 str = "kAudioHardwareBadDeviceError";
300 break;
302 case kAudioHardwareBadStreamError:
303 str = "kAudioHardwareBadStreamError";
304 break;
306 case kAudioHardwareUnsupportedOperationError:
307 str = "kAudioHardwareUnsupportedOperationError";
308 break;
310 case kAudioDeviceUnsupportedFormatError:
311 str = "kAudioDeviceUnsupportedFormatError";
312 break;
314 case kAudioDevicePermissionsError:
315 str = "kAudioDevicePermissionsError";
316 break;
318 default:
319 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
320 return;
323 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
326 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
327 OSStatus status,
328 const char *fmt,
332 va_list ap;
334 va_start (ap, fmt);
335 AUD_log (AUDIO_CAP, fmt, ap);
336 va_end (ap);
338 coreaudio_logstatus (status);
341 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
342 OSStatus status,
343 const char *typ,
344 const char *fmt,
348 va_list ap;
350 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
352 va_start (ap, fmt);
353 AUD_vlog (AUDIO_CAP, fmt, ap);
354 va_end (ap);
356 coreaudio_logstatus (status);
359 static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
361 OSStatus status;
362 UInt32 result = 0;
363 status = coreaudio_get_isrunning(outputDeviceID, &result);
364 if (status != kAudioHardwareNoError) {
365 coreaudio_logerr(status,
366 "Could not determine whether Device is playing\n");
368 return result;
371 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
373 int err;
375 err = pthread_mutex_lock (&core->mutex);
376 if (err) {
377 dolog ("Could not lock voice for %s\nReason: %s\n",
378 fn_name, strerror (err));
379 return -1;
381 return 0;
384 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
386 int err;
388 err = pthread_mutex_unlock (&core->mutex);
389 if (err) {
390 dolog ("Could not unlock voice for %s\nReason: %s\n",
391 fn_name, strerror (err));
392 return -1;
394 return 0;
397 #define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
398 static ret_type glue(coreaudio_, name)args_decl \
400 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
401 ret_type ret; \
403 if (coreaudio_lock(core, "coreaudio_" #name)) { \
404 return 0; \
407 ret = glue(audio_generic_, name)args; \
409 coreaudio_unlock(core, "coreaudio_" #name); \
410 return ret; \
412 COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
413 (hw, size))
414 COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
415 (HWVoiceOut *hw, void *buf, size_t size),
416 (hw, buf, size))
417 COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
418 (hw, buf, size))
419 #undef COREAUDIO_WRAPPER_FUNC
421 /* callback to feed audiooutput buffer */
422 static OSStatus audioDeviceIOProc(
423 AudioDeviceID inDevice,
424 const AudioTimeStamp* inNow,
425 const AudioBufferList* inInputData,
426 const AudioTimeStamp* inInputTime,
427 AudioBufferList* outOutputData,
428 const AudioTimeStamp* inOutputTime,
429 void* hwptr)
431 UInt32 frameCount, pending_frames;
432 void *out = outOutputData->mBuffers[0].mData;
433 HWVoiceOut *hw = hwptr;
434 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
435 size_t len;
437 if (coreaudio_lock (core, "audioDeviceIOProc")) {
438 inInputTime = 0;
439 return 0;
442 frameCount = core->audioDevicePropertyBufferFrameSize;
443 pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
445 /* if there are not enough samples, set signal and return */
446 if (pending_frames < frameCount) {
447 inInputTime = 0;
448 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
449 return 0;
452 len = frameCount * hw->info.bytes_per_frame;
453 while (len) {
454 size_t write_len;
455 ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
456 if (start < 0) {
457 start += hw->size_emul;
459 assert(start >= 0 && start < hw->size_emul);
461 write_len = MIN(MIN(hw->pending_emul, len),
462 hw->size_emul - start);
464 memcpy(out, hw->buf_emul + start, write_len);
465 hw->pending_emul -= write_len;
466 len -= write_len;
467 out += write_len;
470 coreaudio_unlock (core, "audioDeviceIOProc");
471 return 0;
474 static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
475 struct audsettings *as)
477 UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
478 if (as->endianness) { /* 0 = little, 1 = big */
479 flags |= kAudioFormatFlagIsBigEndian;
482 if (flags == 0) { /* must not be 0 */
483 flags = kAudioFormatFlagsAreAllClear;
485 return flags;
488 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
489 void *drv_opaque)
491 OSStatus status;
492 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
493 int err;
494 const char *typ = "playback";
495 AudioValueRange frameRange;
496 Audiodev *dev = drv_opaque;
497 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
498 int frames;
500 /* create mutex */
501 err = pthread_mutex_init(&core->mutex, NULL);
502 if (err) {
503 dolog("Could not create mutex\nReason: %s\n", strerror (err));
504 return -1;
507 audio_pcm_init_info (&hw->info, as);
509 status = coreaudio_get_voice(&core->outputDeviceID);
510 if (status != kAudioHardwareNoError) {
511 coreaudio_logerr2 (status, typ,
512 "Could not get default output Device\n");
513 return -1;
515 if (core->outputDeviceID == kAudioDeviceUnknown) {
516 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
517 return -1;
520 /* get minimum and maximum buffer frame sizes */
521 status = coreaudio_get_framesizerange(core->outputDeviceID,
522 &frameRange);
523 if (status != kAudioHardwareNoError) {
524 coreaudio_logerr2 (status, typ,
525 "Could not get device buffer frame range\n");
526 return -1;
529 frames = audio_buffer_frames(
530 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
531 if (frameRange.mMinimum > frames) {
532 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
533 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
534 } else if (frameRange.mMaximum < frames) {
535 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
536 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
538 else {
539 core->audioDevicePropertyBufferFrameSize = frames;
542 /* set Buffer Frame Size */
543 status = coreaudio_set_framesize(core->outputDeviceID,
544 &core->audioDevicePropertyBufferFrameSize);
545 if (status != kAudioHardwareNoError) {
546 coreaudio_logerr2 (status, typ,
547 "Could not set device buffer frame size %" PRIu32 "\n",
548 (uint32_t)core->audioDevicePropertyBufferFrameSize);
549 return -1;
552 /* get Buffer Frame Size */
553 status = coreaudio_get_framesize(core->outputDeviceID,
554 &core->audioDevicePropertyBufferFrameSize);
555 if (status != kAudioHardwareNoError) {
556 coreaudio_logerr2 (status, typ,
557 "Could not get device buffer frame size\n");
558 return -1;
560 hw->samples = (cpdo->has_buffer_count ? cpdo->buffer_count : 4) *
561 core->audioDevicePropertyBufferFrameSize;
563 /* get StreamFormat */
564 status = coreaudio_get_streamformat(core->outputDeviceID,
565 &core->outputStreamBasicDescription);
566 if (status != kAudioHardwareNoError) {
567 coreaudio_logerr2 (status, typ,
568 "Could not get Device Stream properties\n");
569 core->outputDeviceID = kAudioDeviceUnknown;
570 return -1;
573 /* set Samplerate */
574 core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
575 core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
576 core->outputStreamBasicDescription.mFormatFlags =
577 coreaudio_get_flags(&hw->info, as);
578 core->outputStreamBasicDescription.mBytesPerPacket =
579 core->outputStreamBasicDescription.mBytesPerFrame =
580 hw->info.nchannels * hw->info.bits / 8;
581 core->outputStreamBasicDescription.mFramesPerPacket = 1;
582 core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
583 core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
585 status = coreaudio_set_streamformat(core->outputDeviceID,
586 &core->outputStreamBasicDescription);
587 if (status != kAudioHardwareNoError) {
588 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
589 as->freq);
590 core->outputDeviceID = kAudioDeviceUnknown;
591 return -1;
594 /* set Callback */
595 core->ioprocid = NULL;
596 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
597 audioDeviceIOProc,
599 &core->ioprocid);
600 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
601 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
602 core->outputDeviceID = kAudioDeviceUnknown;
603 return -1;
606 /* start Playback */
607 if (!isPlaying(core->outputDeviceID)) {
608 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
609 if (status != kAudioHardwareNoError) {
610 coreaudio_logerr2 (status, typ, "Could not start playback\n");
611 AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid);
612 core->outputDeviceID = kAudioDeviceUnknown;
613 return -1;
617 return 0;
620 static void coreaudio_fini_out (HWVoiceOut *hw)
622 OSStatus status;
623 int err;
624 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
626 if (!audio_is_cleaning_up()) {
627 /* stop playback */
628 if (isPlaying(core->outputDeviceID)) {
629 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
630 if (status != kAudioHardwareNoError) {
631 coreaudio_logerr (status, "Could not stop playback\n");
635 /* remove callback */
636 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
637 core->ioprocid);
638 if (status != kAudioHardwareNoError) {
639 coreaudio_logerr (status, "Could not remove IOProc\n");
642 core->outputDeviceID = kAudioDeviceUnknown;
644 /* destroy mutex */
645 err = pthread_mutex_destroy(&core->mutex);
646 if (err) {
647 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
651 static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
653 OSStatus status;
654 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
656 if (enable) {
657 /* start playback */
658 if (!isPlaying(core->outputDeviceID)) {
659 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
660 if (status != kAudioHardwareNoError) {
661 coreaudio_logerr (status, "Could not resume playback\n");
664 } else {
665 /* stop playback */
666 if (!audio_is_cleaning_up()) {
667 if (isPlaying(core->outputDeviceID)) {
668 status = AudioDeviceStop(core->outputDeviceID,
669 core->ioprocid);
670 if (status != kAudioHardwareNoError) {
671 coreaudio_logerr (status, "Could not pause playback\n");
678 static void *coreaudio_audio_init(Audiodev *dev)
680 return dev;
683 static void coreaudio_audio_fini (void *opaque)
687 static struct audio_pcm_ops coreaudio_pcm_ops = {
688 .init_out = coreaudio_init_out,
689 .fini_out = coreaudio_fini_out,
690 .write = coreaudio_write,
691 .get_buffer_out = coreaudio_get_buffer_out,
692 .put_buffer_out = coreaudio_put_buffer_out_nowrite,
693 .enable_out = coreaudio_enable_out
696 static struct audio_driver coreaudio_audio_driver = {
697 .name = "coreaudio",
698 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
699 .init = coreaudio_audio_init,
700 .fini = coreaudio_audio_fini,
701 .pcm_ops = &coreaudio_pcm_ops,
702 .can_be_default = 1,
703 .max_voices_out = 1,
704 .max_voices_in = 0,
705 .voice_size_out = sizeof (coreaudioVoiceOut),
706 .voice_size_in = 0
709 static void register_audio_coreaudio(void)
711 audio_driver_register(&coreaudio_audio_driver);
713 type_init(register_audio_coreaudio);