hw/timer: Initial commit of Ibex Timer
[qemu/ar7.git] / audio / coreaudio.c
blobf570e1ee60efa64314b6679f6ad8f9c5d81355fc
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 typedef struct coreaudioVoiceOut {
36 HWVoiceOut hw;
37 pthread_mutex_t mutex;
38 AudioDeviceID outputDeviceID;
39 int frameSizeSetting;
40 uint32_t bufferCount;
41 UInt32 audioDevicePropertyBufferFrameSize;
42 AudioDeviceIOProcID ioprocid;
43 bool enabled;
44 } coreaudioVoiceOut;
46 static const AudioObjectPropertyAddress voice_addr = {
47 kAudioHardwarePropertyDefaultOutputDevice,
48 kAudioObjectPropertyScopeGlobal,
49 kAudioObjectPropertyElementMaster
52 static OSStatus coreaudio_get_voice(AudioDeviceID *id)
54 UInt32 size = sizeof(*id);
56 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
57 &voice_addr,
59 NULL,
60 &size,
61 id);
64 static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
65 AudioValueRange *framerange)
67 UInt32 size = sizeof(*framerange);
68 AudioObjectPropertyAddress addr = {
69 kAudioDevicePropertyBufferFrameSizeRange,
70 kAudioDevicePropertyScopeOutput,
71 kAudioObjectPropertyElementMaster
74 return AudioObjectGetPropertyData(id,
75 &addr,
77 NULL,
78 &size,
79 framerange);
82 static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
84 UInt32 size = sizeof(*framesize);
85 AudioObjectPropertyAddress addr = {
86 kAudioDevicePropertyBufferFrameSize,
87 kAudioDevicePropertyScopeOutput,
88 kAudioObjectPropertyElementMaster
91 return AudioObjectGetPropertyData(id,
92 &addr,
94 NULL,
95 &size,
96 framesize);
99 static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
101 UInt32 size = sizeof(*framesize);
102 AudioObjectPropertyAddress addr = {
103 kAudioDevicePropertyBufferFrameSize,
104 kAudioDevicePropertyScopeOutput,
105 kAudioObjectPropertyElementMaster
108 return AudioObjectSetPropertyData(id,
109 &addr,
111 NULL,
112 size,
113 framesize);
116 static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
117 AudioStreamBasicDescription *d)
119 UInt32 size = sizeof(*d);
120 AudioObjectPropertyAddress addr = {
121 kAudioDevicePropertyStreamFormat,
122 kAudioDevicePropertyScopeOutput,
123 kAudioObjectPropertyElementMaster
126 return AudioObjectSetPropertyData(id,
127 &addr,
129 NULL,
130 size,
134 static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
136 UInt32 size = sizeof(*result);
137 AudioObjectPropertyAddress addr = {
138 kAudioDevicePropertyDeviceIsRunning,
139 kAudioDevicePropertyScopeOutput,
140 kAudioObjectPropertyElementMaster
143 return AudioObjectGetPropertyData(id,
144 &addr,
146 NULL,
147 &size,
148 result);
151 static void coreaudio_logstatus (OSStatus status)
153 const char *str = "BUG";
155 switch (status) {
156 case kAudioHardwareNoError:
157 str = "kAudioHardwareNoError";
158 break;
160 case kAudioHardwareNotRunningError:
161 str = "kAudioHardwareNotRunningError";
162 break;
164 case kAudioHardwareUnspecifiedError:
165 str = "kAudioHardwareUnspecifiedError";
166 break;
168 case kAudioHardwareUnknownPropertyError:
169 str = "kAudioHardwareUnknownPropertyError";
170 break;
172 case kAudioHardwareBadPropertySizeError:
173 str = "kAudioHardwareBadPropertySizeError";
174 break;
176 case kAudioHardwareIllegalOperationError:
177 str = "kAudioHardwareIllegalOperationError";
178 break;
180 case kAudioHardwareBadDeviceError:
181 str = "kAudioHardwareBadDeviceError";
182 break;
184 case kAudioHardwareBadStreamError:
185 str = "kAudioHardwareBadStreamError";
186 break;
188 case kAudioHardwareUnsupportedOperationError:
189 str = "kAudioHardwareUnsupportedOperationError";
190 break;
192 case kAudioDeviceUnsupportedFormatError:
193 str = "kAudioDeviceUnsupportedFormatError";
194 break;
196 case kAudioDevicePermissionsError:
197 str = "kAudioDevicePermissionsError";
198 break;
200 default:
201 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
202 return;
205 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
208 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
209 OSStatus status,
210 const char *fmt,
214 va_list ap;
216 va_start (ap, fmt);
217 AUD_log (AUDIO_CAP, fmt, ap);
218 va_end (ap);
220 coreaudio_logstatus (status);
223 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
224 OSStatus status,
225 const char *typ,
226 const char *fmt,
230 va_list ap;
232 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
234 va_start (ap, fmt);
235 AUD_vlog (AUDIO_CAP, fmt, ap);
236 va_end (ap);
238 coreaudio_logstatus (status);
241 #define coreaudio_playback_logerr(status, ...) \
242 coreaudio_logerr2(status, "playback", __VA_ARGS__)
244 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
246 int err;
248 err = pthread_mutex_lock (&core->mutex);
249 if (err) {
250 dolog ("Could not lock voice for %s\nReason: %s\n",
251 fn_name, strerror (err));
252 return -1;
254 return 0;
257 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
259 int err;
261 err = pthread_mutex_unlock (&core->mutex);
262 if (err) {
263 dolog ("Could not unlock voice for %s\nReason: %s\n",
264 fn_name, strerror (err));
265 return -1;
267 return 0;
270 #define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
271 static ret_type glue(coreaudio_, name)args_decl \
273 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
274 ret_type ret; \
276 if (coreaudio_lock(core, "coreaudio_" #name)) { \
277 return 0; \
280 ret = glue(audio_generic_, name)args; \
282 coreaudio_unlock(core, "coreaudio_" #name); \
283 return ret; \
285 COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
286 (hw, size))
287 COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
288 (HWVoiceOut *hw, void *buf, size_t size),
289 (hw, buf, size))
290 COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
291 (hw, buf, size))
292 #undef COREAUDIO_WRAPPER_FUNC
294 /* callback to feed audiooutput buffer */
295 static OSStatus audioDeviceIOProc(
296 AudioDeviceID inDevice,
297 const AudioTimeStamp *inNow,
298 const AudioBufferList *inInputData,
299 const AudioTimeStamp *inInputTime,
300 AudioBufferList *outOutputData,
301 const AudioTimeStamp *inOutputTime,
302 void *hwptr)
304 UInt32 frameCount, pending_frames;
305 void *out = outOutputData->mBuffers[0].mData;
306 HWVoiceOut *hw = hwptr;
307 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
308 size_t len;
310 if (coreaudio_lock (core, "audioDeviceIOProc")) {
311 inInputTime = 0;
312 return 0;
315 if (inDevice != core->outputDeviceID) {
316 coreaudio_unlock (core, "audioDeviceIOProc(old device)");
317 return 0;
320 frameCount = core->audioDevicePropertyBufferFrameSize;
321 pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
323 /* if there are not enough samples, set signal and return */
324 if (pending_frames < frameCount) {
325 inInputTime = 0;
326 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
327 return 0;
330 len = frameCount * hw->info.bytes_per_frame;
331 while (len) {
332 size_t write_len;
333 ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
334 if (start < 0) {
335 start += hw->size_emul;
337 assert(start >= 0 && start < hw->size_emul);
339 write_len = MIN(MIN(hw->pending_emul, len),
340 hw->size_emul - start);
342 memcpy(out, hw->buf_emul + start, write_len);
343 hw->pending_emul -= write_len;
344 len -= write_len;
345 out += write_len;
348 coreaudio_unlock (core, "audioDeviceIOProc");
349 return 0;
352 static OSStatus init_out_device(coreaudioVoiceOut *core)
354 OSStatus status;
355 AudioValueRange frameRange;
357 AudioStreamBasicDescription streamBasicDescription = {
358 .mBitsPerChannel = core->hw.info.bits,
359 .mBytesPerFrame = core->hw.info.bytes_per_frame,
360 .mBytesPerPacket = core->hw.info.bytes_per_frame,
361 .mChannelsPerFrame = core->hw.info.nchannels,
362 .mFormatFlags = kLinearPCMFormatFlagIsFloat,
363 .mFormatID = kAudioFormatLinearPCM,
364 .mFramesPerPacket = 1,
365 .mSampleRate = core->hw.info.freq
368 status = coreaudio_get_voice(&core->outputDeviceID);
369 if (status != kAudioHardwareNoError) {
370 coreaudio_playback_logerr (status,
371 "Could not get default output Device\n");
372 return status;
374 if (core->outputDeviceID == kAudioDeviceUnknown) {
375 dolog ("Could not initialize playback - Unknown Audiodevice\n");
376 return status;
379 /* get minimum and maximum buffer frame sizes */
380 status = coreaudio_get_framesizerange(core->outputDeviceID,
381 &frameRange);
382 if (status == kAudioHardwareBadObjectError) {
383 return 0;
385 if (status != kAudioHardwareNoError) {
386 coreaudio_playback_logerr (status,
387 "Could not get device buffer frame range\n");
388 return status;
391 if (frameRange.mMinimum > core->frameSizeSetting) {
392 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
393 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
394 } else if (frameRange.mMaximum < core->frameSizeSetting) {
395 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
396 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
397 } else {
398 core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
401 /* set Buffer Frame Size */
402 status = coreaudio_set_framesize(core->outputDeviceID,
403 &core->audioDevicePropertyBufferFrameSize);
404 if (status == kAudioHardwareBadObjectError) {
405 return 0;
407 if (status != kAudioHardwareNoError) {
408 coreaudio_playback_logerr (status,
409 "Could not set device buffer frame size %" PRIu32 "\n",
410 (uint32_t)core->audioDevicePropertyBufferFrameSize);
411 return status;
414 /* get Buffer Frame Size */
415 status = coreaudio_get_framesize(core->outputDeviceID,
416 &core->audioDevicePropertyBufferFrameSize);
417 if (status == kAudioHardwareBadObjectError) {
418 return 0;
420 if (status != kAudioHardwareNoError) {
421 coreaudio_playback_logerr (status,
422 "Could not get device buffer frame size\n");
423 return status;
425 core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
427 /* set Samplerate */
428 status = coreaudio_set_streamformat(core->outputDeviceID,
429 &streamBasicDescription);
430 if (status == kAudioHardwareBadObjectError) {
431 return 0;
433 if (status != kAudioHardwareNoError) {
434 coreaudio_playback_logerr (status,
435 "Could not set samplerate %lf\n",
436 streamBasicDescription.mSampleRate);
437 core->outputDeviceID = kAudioDeviceUnknown;
438 return status;
441 /* set Callback */
442 core->ioprocid = NULL;
443 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
444 audioDeviceIOProc,
445 &core->hw,
446 &core->ioprocid);
447 if (status == kAudioHardwareBadDeviceError) {
448 return 0;
450 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
451 coreaudio_playback_logerr (status, "Could not set IOProc\n");
452 core->outputDeviceID = kAudioDeviceUnknown;
453 return status;
456 return 0;
459 static void fini_out_device(coreaudioVoiceOut *core)
461 OSStatus status;
462 UInt32 isrunning;
464 /* stop playback */
465 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
466 if (status != kAudioHardwareBadObjectError) {
467 if (status != kAudioHardwareNoError) {
468 coreaudio_logerr(status,
469 "Could not determine whether Device is playing\n");
472 if (isrunning) {
473 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
474 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
475 coreaudio_logerr(status, "Could not stop playback\n");
480 /* remove callback */
481 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
482 core->ioprocid);
483 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
484 coreaudio_logerr(status, "Could not remove IOProc\n");
486 core->outputDeviceID = kAudioDeviceUnknown;
489 static void update_device_playback_state(coreaudioVoiceOut *core)
491 OSStatus status;
492 UInt32 isrunning;
494 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
495 if (status != kAudioHardwareNoError) {
496 if (status != kAudioHardwareBadObjectError) {
497 coreaudio_logerr(status,
498 "Could not determine whether Device is playing\n");
501 return;
504 if (core->enabled) {
505 /* start playback */
506 if (!isrunning) {
507 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
508 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
509 coreaudio_logerr (status, "Could not resume playback\n");
512 } else {
513 /* stop playback */
514 if (isrunning) {
515 status = AudioDeviceStop(core->outputDeviceID,
516 core->ioprocid);
517 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
518 coreaudio_logerr(status, "Could not pause playback\n");
524 static OSStatus handle_voice_change(
525 AudioObjectID in_object_id,
526 UInt32 in_number_addresses,
527 const AudioObjectPropertyAddress *in_addresses,
528 void *in_client_data)
530 OSStatus status;
531 coreaudioVoiceOut *core = in_client_data;
533 if (coreaudio_lock(core, __func__)) {
534 abort();
537 if (core->outputDeviceID) {
538 fini_out_device(core);
541 status = init_out_device(core);
542 if (!status) {
543 update_device_playback_state(core);
546 coreaudio_unlock (core, __func__);
547 return status;
550 static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
551 void *drv_opaque)
553 OSStatus status;
554 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
555 int err;
556 Audiodev *dev = drv_opaque;
557 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
558 struct audsettings obt_as;
560 /* create mutex */
561 err = pthread_mutex_init(&core->mutex, NULL);
562 if (err) {
563 dolog("Could not create mutex\nReason: %s\n", strerror (err));
564 goto mutex_error;
567 if (coreaudio_lock(core, __func__)) {
568 goto lock_error;
571 obt_as = *as;
572 as = &obt_as;
573 as->fmt = AUDIO_FORMAT_F32;
574 audio_pcm_init_info (&hw->info, as);
576 core->frameSizeSetting = audio_buffer_frames(
577 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
579 core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
581 status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
582 &voice_addr, handle_voice_change,
583 core);
584 if (status != kAudioHardwareNoError) {
585 coreaudio_playback_logerr (status,
586 "Could not listen to voice property change\n");
587 goto listener_error;
590 if (init_out_device(core)) {
591 goto device_error;
594 coreaudio_unlock(core, __func__);
595 return 0;
597 device_error:
598 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
599 &voice_addr,
600 handle_voice_change,
601 core);
602 if (status != kAudioHardwareNoError) {
603 coreaudio_playback_logerr(status,
604 "Could not remove voice property change listener\n");
607 listener_error:
608 coreaudio_unlock(core, __func__);
610 lock_error:
611 err = pthread_mutex_destroy(&core->mutex);
612 if (err) {
613 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
616 mutex_error:
617 return -1;
620 static void coreaudio_fini_out (HWVoiceOut *hw)
622 OSStatus status;
623 int err;
624 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
626 if (coreaudio_lock(core, __func__)) {
627 abort();
630 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
631 &voice_addr,
632 handle_voice_change,
633 core);
634 if (status != kAudioHardwareNoError) {
635 coreaudio_logerr(status, "Could not remove voice property change listener\n");
638 fini_out_device(core);
640 coreaudio_unlock(core, __func__);
642 /* destroy mutex */
643 err = pthread_mutex_destroy(&core->mutex);
644 if (err) {
645 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
649 static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
651 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
653 if (coreaudio_lock(core, __func__)) {
654 abort();
657 core->enabled = enable;
658 update_device_playback_state(core);
660 coreaudio_unlock(core, __func__);
663 static void *coreaudio_audio_init(Audiodev *dev)
665 return dev;
668 static void coreaudio_audio_fini (void *opaque)
672 static struct audio_pcm_ops coreaudio_pcm_ops = {
673 .init_out = coreaudio_init_out,
674 .fini_out = coreaudio_fini_out,
675 /* wrapper for audio_generic_write */
676 .write = coreaudio_write,
677 /* wrapper for audio_generic_get_buffer_out */
678 .get_buffer_out = coreaudio_get_buffer_out,
679 /* wrapper for audio_generic_put_buffer_out */
680 .put_buffer_out = coreaudio_put_buffer_out,
681 .enable_out = coreaudio_enable_out
684 static struct audio_driver coreaudio_audio_driver = {
685 .name = "coreaudio",
686 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
687 .init = coreaudio_audio_init,
688 .fini = coreaudio_audio_fini,
689 .pcm_ops = &coreaudio_pcm_ops,
690 .can_be_default = 1,
691 .max_voices_out = 1,
692 .max_voices_in = 0,
693 .voice_size_out = sizeof (coreaudioVoiceOut),
694 .voice_size_in = 0
697 static void register_audio_coreaudio(void)
699 audio_driver_register(&coreaudio_audio_driver);
701 type_init(register_audio_coreaudio);