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"
34 #define DEVICE_BUFFER_FRAMES (512)
42 typedef struct coreaudioVoiceOut {
44 pthread_mutex_t mutex;
45 AudioDeviceID outputDeviceID;
46 UInt32 audioDevicePropertyBufferSize;
47 AudioStreamBasicDescription outputStreamBasicDescription;
54 static void coreaudio_logstatus (OSStatus status)
59 case kAudioHardwareNoError:
60 str = "kAudioHardwareNoError";
63 case kAudioHardwareNotRunningError:
64 str = "kAudioHardwareNotRunningError";
67 case kAudioHardwareUnspecifiedError:
68 str = "kAudioHardwareUnspecifiedError";
71 case kAudioHardwareUnknownPropertyError:
72 str = "kAudioHardwareUnknownPropertyError";
75 case kAudioHardwareBadPropertySizeError:
76 str = "kAudioHardwareBadPropertySizeError";
79 case kAudioHardwareIllegalOperationError:
80 str = "kAudioHardwareIllegalOperationError";
83 case kAudioHardwareBadDeviceError:
84 str = "kAudioHardwareBadDeviceError";
87 case kAudioHardwareBadStreamError:
88 str = "kAudioHardwareBadStreamError";
91 case kAudioHardwareUnsupportedOperationError:
92 str = "kAudioHardwareUnsupportedOperationError";
95 case kAudioDeviceUnsupportedFormatError:
96 str = "kAudioDeviceUnsupportedFormatError";
99 case kAudioDevicePermissionsError:
100 str = "kAudioDevicePermissionsError";
104 AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
108 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
111 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
120 AUD_log (AUDIO_CAP, fmt, ap);
123 coreaudio_logstatus (status);
126 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
135 AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
138 AUD_vlog (AUDIO_CAP, fmt, ap);
141 coreaudio_logstatus (status);
144 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
148 err = pthread_mutex_lock (&core->mutex);
150 dolog ("Can not lock voice for %s\nReason: %s\n",
151 fn_name, strerror (err));
157 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
161 err = pthread_mutex_unlock (&core->mutex);
163 dolog ("Can not unlock voice for %s\nReason: %s\n",
164 fn_name, strerror (err));
170 static int coreaudio_run_out (HWVoiceOut *hw)
173 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
175 if (coreaudio_lock (core, "coreaudio_run_out")) {
179 live = audio_pcm_hw_get_live_out (hw);
181 if (core->decr > live) {
182 ldebug ("core->decr %d live %d core->live %d\n",
188 decr = audio_MIN (core->decr, live);
191 core->live = live - decr;
192 hw->rpos = core->rpos;
194 coreaudio_unlock (core, "coreaudio_run_out");
198 /* callback to feed audiooutput buffer */
199 static OSStatus audioDeviceIOProc(
200 AudioDeviceID inDevice,
201 const AudioTimeStamp* inNow,
202 const AudioBufferList* inInputData,
203 const AudioTimeStamp* inInputTime,
204 AudioBufferList* outOutputData,
205 const AudioTimeStamp* inOutputTime,
208 unsigned int frame, frameCount;
209 float *out = outOutputData->mBuffers[0].mData;
210 HWVoiceOut *hw = hwptr;
211 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
216 const float scale = 1.f / UINT_MAX;
218 const float scale = UINT_MAX;
222 if (coreaudio_lock (core, "audioDeviceIOProc")) {
227 frameCount = conf.buffer_frames;
230 /* if there are not enough samples, set signal and return */
231 if (live < frameCount) {
233 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
238 src = hw->mix_buf + rpos;
241 for (frame = 0; frame < frameCount; frame++) {
243 *out++ = src[frame].l; /* left channel */
244 *out++ = src[frame].r; /* right channel */
247 *out++ = src[frame].l * scale; /* left channel */
248 *out++ = src[frame].r * scale; /* right channel */
250 *out++ = src[frame].l / scale; /* left channel */
251 *out++ = src[frame].r / scale; /* right channel */
257 mixeng_clear (src, frameCount);
258 rpos = (rpos + frameCount) % hw->samples;
259 core->decr = frameCount;
262 coreaudio_unlock (core, "audioDeviceIOProc");
266 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
268 return audio_pcm_sw_write (sw, buf, len);
271 static int coreaudio_init_out (HWVoiceOut *hw, int freq,
272 int nchannels, audfmt_e fmt)
275 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
280 const char *typ = "DAC";
283 err = pthread_mutex_init(&core->mutex, NULL);
285 dolog("Can not create mutex\nReason: %s\n", strerror (err));
289 if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) {
294 audio_pcm_init_info (
299 /* Following is irrelevant actually since we do not use
300 mixengs clipping routines */
301 audio_need_to_swap_endian (endianess)
303 hw->bufsize = 4 * conf.buffer_frames * nchannels * bits;
305 /* open default output device */
306 propertySize = sizeof(core->outputDeviceID);
307 status = AudioHardwareGetProperty(
308 kAudioHardwarePropertyDefaultOutputDevice,
310 &core->outputDeviceID);
311 if (status != kAudioHardwareNoError) {
312 coreaudio_logerr2 (status, typ,
313 "Can not get default output Device\n");
316 if (core->outputDeviceID == kAudioDeviceUnknown) {
317 dolog ("Can not initialize %s - Unknown Audiodevice\n", typ);
321 /* set Buffersize to conf.buffer_frames frames */
322 propertySize = sizeof(core->audioDevicePropertyBufferSize);
323 core->audioDevicePropertyBufferSize =
324 conf.buffer_frames * sizeof(float) * 2;
325 status = AudioDeviceSetProperty(
326 core->outputDeviceID,
330 kAudioDevicePropertyBufferSize,
332 &core->audioDevicePropertyBufferSize);
333 if (status != kAudioHardwareNoError) {
334 coreaudio_logerr2 (status, typ,
335 "Can not set device buffer size %d\n",
336 kAudioDevicePropertyBufferSize);
341 propertySize = sizeof(core->audioDevicePropertyBufferSize);
342 status = AudioDeviceGetProperty(
343 core->outputDeviceID,
346 kAudioDevicePropertyBufferSize,
348 &core->audioDevicePropertyBufferSize);
349 if (status != kAudioHardwareNoError) {
350 coreaudio_logerr2 (status, typ, "Can not get device buffer size\n");
354 /* get StreamFormat */
355 propertySize = sizeof(core->outputStreamBasicDescription);
356 status = AudioDeviceGetProperty(
357 core->outputDeviceID,
360 kAudioDevicePropertyStreamFormat,
362 &core->outputStreamBasicDescription);
363 if (status != kAudioHardwareNoError) {
364 coreaudio_logerr2 (status, typ,
365 "Can not get Device Stream properties\n");
366 core->outputDeviceID = kAudioDeviceUnknown;
371 core->outputStreamBasicDescription.mSampleRate = (Float64)freq;
372 propertySize = sizeof(core->outputStreamBasicDescription);
373 status = AudioDeviceSetProperty(
374 core->outputDeviceID,
378 kAudioDevicePropertyStreamFormat,
380 &core->outputStreamBasicDescription);
381 if (status != kAudioHardwareNoError) {
382 coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq);
383 core->outputDeviceID = kAudioDeviceUnknown;
388 status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
389 if (status != kAudioHardwareNoError) {
390 coreaudio_logerr2 (status, typ, "Can not set IOProc\n");
391 core->outputDeviceID = kAudioDeviceUnknown;
396 if (!core->isPlaying) {
397 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
398 if (status != kAudioHardwareNoError) {
399 coreaudio_logerr2 (status, typ, "Can not start playback\n");
400 AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
401 core->outputDeviceID = kAudioDeviceUnknown;
410 static void coreaudio_fini_out (HWVoiceOut *hw)
414 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
417 if (core->isPlaying) {
418 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
419 if (status != kAudioHardwareNoError) {
420 coreaudio_logerr (status, "Can not stop playback\n");
425 /* remove callback */
426 status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
427 if (status != kAudioHardwareNoError) {
428 coreaudio_logerr (status, "Can not remove IOProc\n");
430 core->outputDeviceID = kAudioDeviceUnknown;
433 err = pthread_mutex_destroy(&core->mutex);
435 dolog("Can not destroy mutex\nReason: %s\n", strerror (err));
439 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
442 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
447 if (!core->isPlaying) {
448 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
449 if (status != kAudioHardwareNoError) {
450 coreaudio_logerr (status, "Can not unpause playback\n");
458 if (core->isPlaying) {
459 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
460 if (status != kAudioHardwareNoError) {
461 coreaudio_logerr (status, "Can not pause playback\n");
470 static void *coreaudio_audio_init (void)
472 return &coreaudio_audio_init;
475 static void coreaudio_audio_fini (void *opaque)
480 static struct audio_option coreaudio_options[] = {
481 {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
482 "Size of the buffer in frames", NULL, 0},
483 {NULL, 0, NULL, NULL, NULL, 0}
486 static struct audio_pcm_ops coreaudio_pcm_ops = {
500 struct audio_driver coreaudio_audio_driver = {
501 INIT_FIELD (name = ) "coreaudio",
502 INIT_FIELD (descr = )
503 "CoreAudio http://developer.apple.com/audio/coreaudio.html",
504 INIT_FIELD (options = ) coreaudio_options,
505 INIT_FIELD (init = ) coreaudio_audio_init,
506 INIT_FIELD (fini = ) coreaudio_audio_fini,
507 INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
508 INIT_FIELD (can_be_default = ) 1,
509 INIT_FIELD (max_voices_out = ) 1,
510 INIT_FIELD (max_voices_in = ) 0,
511 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
512 INIT_FIELD (voice_size_in = ) 0