]> git.proxmox.com Git - mirror_qemu.git/blob - audio/coreaudio.c
merged 15a_aqemu.patch audio patch (malc)
[mirror_qemu.git] / audio / coreaudio.c
1 /*
2 * QEMU OS X CoreAudio audio driver
3 *
4 * Copyright (c) 2005 Mike Kronenberg
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
24
25 #include <CoreAudio/CoreAudio.h>
26 #include <string.h> /* strerror */
27 #include <pthread.h> /* pthread_X */
28
29 #include "vl.h"
30
31 #define AUDIO_CAP "coreaudio"
32 #include "audio_int.h"
33
34 #define DEVICE_BUFFER_FRAMES (512)
35
36 struct {
37 int buffer_frames;
38 } conf = {
39 .buffer_frames = 512
40 };
41
42 typedef struct coreaudioVoiceOut {
43 HWVoiceOut hw;
44 pthread_mutex_t mutex;
45 AudioDeviceID outputDeviceID;
46 UInt32 audioDevicePropertyBufferSize;
47 AudioStreamBasicDescription outputStreamBasicDescription;
48 int isPlaying;
49 int live;
50 int decr;
51 int rpos;
52 } coreaudioVoiceOut;
53
54 static void coreaudio_logstatus (OSStatus status)
55 {
56 char *str = "BUG";
57
58 switch(status) {
59 case kAudioHardwareNoError:
60 str = "kAudioHardwareNoError";
61 break;
62
63 case kAudioHardwareNotRunningError:
64 str = "kAudioHardwareNotRunningError";
65 break;
66
67 case kAudioHardwareUnspecifiedError:
68 str = "kAudioHardwareUnspecifiedError";
69 break;
70
71 case kAudioHardwareUnknownPropertyError:
72 str = "kAudioHardwareUnknownPropertyError";
73 break;
74
75 case kAudioHardwareBadPropertySizeError:
76 str = "kAudioHardwareBadPropertySizeError";
77 break;
78
79 case kAudioHardwareIllegalOperationError:
80 str = "kAudioHardwareIllegalOperationError";
81 break;
82
83 case kAudioHardwareBadDeviceError:
84 str = "kAudioHardwareBadDeviceError";
85 break;
86
87 case kAudioHardwareBadStreamError:
88 str = "kAudioHardwareBadStreamError";
89 break;
90
91 case kAudioHardwareUnsupportedOperationError:
92 str = "kAudioHardwareUnsupportedOperationError";
93 break;
94
95 case kAudioDeviceUnsupportedFormatError:
96 str = "kAudioDeviceUnsupportedFormatError";
97 break;
98
99 case kAudioDevicePermissionsError:
100 str = "kAudioDevicePermissionsError";
101 break;
102
103 default:
104 AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
105 return;
106 }
107
108 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
109 }
110
111 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
112 OSStatus status,
113 const char *fmt,
114 ...
115 )
116 {
117 va_list ap;
118
119 va_start (ap, fmt);
120 AUD_log (AUDIO_CAP, fmt, ap);
121 va_end (ap);
122
123 coreaudio_logstatus (status);
124 }
125
126 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
127 OSStatus status,
128 const char *typ,
129 const char *fmt,
130 ...
131 )
132 {
133 va_list ap;
134
135 AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
136
137 va_start (ap, fmt);
138 AUD_vlog (AUDIO_CAP, fmt, ap);
139 va_end (ap);
140
141 coreaudio_logstatus (status);
142 }
143
144 static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
145 {
146 int err;
147
148 err = pthread_mutex_lock (&core->mutex);
149 if (err) {
150 dolog ("Can not lock voice for %s\nReason: %s\n",
151 fn_name, strerror (err));
152 return -1;
153 }
154 return 0;
155 }
156
157 static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
158 {
159 int err;
160
161 err = pthread_mutex_unlock (&core->mutex);
162 if (err) {
163 dolog ("Can not unlock voice for %s\nReason: %s\n",
164 fn_name, strerror (err));
165 return -1;
166 }
167 return 0;
168 }
169
170 static int coreaudio_run_out (HWVoiceOut *hw)
171 {
172 int live, decr;
173 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
174
175 if (coreaudio_lock (core, "coreaudio_run_out")) {
176 return 0;
177 }
178
179 live = audio_pcm_hw_get_live_out (hw);
180
181 if (core->decr > live) {
182 ldebug ("core->decr %d live %d core->live %d\n",
183 core->decr,
184 live,
185 core->live);
186 }
187
188 decr = audio_MIN (core->decr, live);
189 core->decr -= decr;
190
191 core->live = live - decr;
192 hw->rpos = core->rpos;
193
194 coreaudio_unlock (core, "coreaudio_run_out");
195 return decr;
196 }
197
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,
206 void* hwptr)
207 {
208 unsigned int frame, frameCount;
209 float *out = outOutputData->mBuffers[0].mData;
210 HWVoiceOut *hw = hwptr;
211 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
212 int rpos, live;
213 st_sample_t *src;
214 #ifndef FLOAT_MIXENG
215 #ifdef RECIPROCAL
216 const float scale = 1.f / UINT_MAX;
217 #else
218 const float scale = UINT_MAX;
219 #endif
220 #endif
221
222 if (coreaudio_lock (core, "audioDeviceIOProc")) {
223 inInputTime = 0;
224 return 0;
225 }
226
227 frameCount = conf.buffer_frames;
228 live = core->live;
229
230 /* if there are not enough samples, set signal and return */
231 if (live < frameCount) {
232 inInputTime = 0;
233 coreaudio_unlock (core, "audioDeviceIOProc(empty)");
234 return 0;
235 }
236
237 rpos = core->rpos;
238 src = hw->mix_buf + rpos;
239
240 /* fill buffer */
241 for (frame = 0; frame < frameCount; frame++) {
242 #ifdef FLOAT_MIXENG
243 *out++ = src[frame].l; /* left channel */
244 *out++ = src[frame].r; /* right channel */
245 #else
246 #ifdef RECIPROCAL
247 *out++ = src[frame].l * scale; /* left channel */
248 *out++ = src[frame].r * scale; /* right channel */
249 #else
250 *out++ = src[frame].l / scale; /* left channel */
251 *out++ = src[frame].r / scale; /* right channel */
252 #endif
253 #endif
254 }
255
256 /* cleanup */
257 mixeng_clear (src, frameCount);
258 rpos = (rpos + frameCount) % hw->samples;
259 core->decr = frameCount;
260 core->rpos = rpos;
261
262 coreaudio_unlock (core, "audioDeviceIOProc");
263 return 0;
264 }
265
266 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
267 {
268 return audio_pcm_sw_write (sw, buf, len);
269 }
270
271 static int coreaudio_init_out (HWVoiceOut *hw, int freq,
272 int nchannels, audfmt_e fmt)
273 {
274 OSStatus status;
275 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
276 UInt32 propertySize;
277 int err;
278 int bits = 8;
279 int endianess = 0;
280 const char *typ = "DAC";
281
282 /* create mutex */
283 err = pthread_mutex_init(&core->mutex, NULL);
284 if (err) {
285 dolog("Can not create mutex\nReason: %s\n", strerror (err));
286 return -1;
287 }
288
289 if (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) {
290 bits = 16;
291 endianess = 1;
292 }
293
294 audio_pcm_init_info (
295 &hw->info,
296 freq,
297 nchannels,
298 fmt,
299 /* Following is irrelevant actually since we do not use
300 mixengs clipping routines */
301 audio_need_to_swap_endian (endianess)
302 );
303 hw->bufsize = 4 * conf.buffer_frames * nchannels * bits;
304
305 /* open default output device */
306 propertySize = sizeof(core->outputDeviceID);
307 status = AudioHardwareGetProperty(
308 kAudioHardwarePropertyDefaultOutputDevice,
309 &propertySize,
310 &core->outputDeviceID);
311 if (status != kAudioHardwareNoError) {
312 coreaudio_logerr2 (status, typ,
313 "Can not get default output Device\n");
314 return -1;
315 }
316 if (core->outputDeviceID == kAudioDeviceUnknown) {
317 dolog ("Can not initialize %s - Unknown Audiodevice\n", typ);
318 return -1;
319 }
320
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,
327 NULL,
328 0,
329 false,
330 kAudioDevicePropertyBufferSize,
331 propertySize,
332 &core->audioDevicePropertyBufferSize);
333 if (status != kAudioHardwareNoError) {
334 coreaudio_logerr2 (status, typ,
335 "Can not set device buffer size %d\n",
336 kAudioDevicePropertyBufferSize);
337 return -1;
338 }
339
340 /* get Buffersize */
341 propertySize = sizeof(core->audioDevicePropertyBufferSize);
342 status = AudioDeviceGetProperty(
343 core->outputDeviceID,
344 0,
345 false,
346 kAudioDevicePropertyBufferSize,
347 &propertySize,
348 &core->audioDevicePropertyBufferSize);
349 if (status != kAudioHardwareNoError) {
350 coreaudio_logerr2 (status, typ, "Can not get device buffer size\n");
351 return -1;
352 }
353
354 /* get StreamFormat */
355 propertySize = sizeof(core->outputStreamBasicDescription);
356 status = AudioDeviceGetProperty(
357 core->outputDeviceID,
358 0,
359 false,
360 kAudioDevicePropertyStreamFormat,
361 &propertySize,
362 &core->outputStreamBasicDescription);
363 if (status != kAudioHardwareNoError) {
364 coreaudio_logerr2 (status, typ,
365 "Can not get Device Stream properties\n");
366 core->outputDeviceID = kAudioDeviceUnknown;
367 return -1;
368 }
369
370 /* set Samplerate */
371 core->outputStreamBasicDescription.mSampleRate = (Float64)freq;
372 propertySize = sizeof(core->outputStreamBasicDescription);
373 status = AudioDeviceSetProperty(
374 core->outputDeviceID,
375 0,
376 0,
377 0,
378 kAudioDevicePropertyStreamFormat,
379 propertySize,
380 &core->outputStreamBasicDescription);
381 if (status != kAudioHardwareNoError) {
382 coreaudio_logerr2 (status, typ, "Can not set samplerate %d\n", freq);
383 core->outputDeviceID = kAudioDeviceUnknown;
384 return -1;
385 }
386
387 /* set Callback */
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;
392 return -1;
393 }
394
395 /* start Playback */
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;
402 return -1;
403 }
404 core->isPlaying = 1;
405 }
406
407 return 0;
408 }
409
410 static void coreaudio_fini_out (HWVoiceOut *hw)
411 {
412 OSStatus status;
413 int err;
414 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
415
416 /* stop playback */
417 if (core->isPlaying) {
418 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
419 if (status != kAudioHardwareNoError) {
420 coreaudio_logerr (status, "Can not stop playback\n");
421 }
422 core->isPlaying = 0;
423 }
424
425 /* remove callback */
426 status = AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
427 if (status != kAudioHardwareNoError) {
428 coreaudio_logerr (status, "Can not remove IOProc\n");
429 }
430 core->outputDeviceID = kAudioDeviceUnknown;
431
432 /* destroy mutex */
433 err = pthread_mutex_destroy(&core->mutex);
434 if (err) {
435 dolog("Can not destroy mutex\nReason: %s\n", strerror (err));
436 }
437 }
438
439 static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
440 {
441 OSStatus status;
442 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
443
444 switch (cmd) {
445 case VOICE_ENABLE:
446 /* start playback */
447 if (!core->isPlaying) {
448 status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
449 if (status != kAudioHardwareNoError) {
450 coreaudio_logerr (status, "Can not unpause playback\n");
451 }
452 core->isPlaying = 1;
453 }
454 break;
455
456 case VOICE_DISABLE:
457 /* stop playback */
458 if (core->isPlaying) {
459 status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
460 if (status != kAudioHardwareNoError) {
461 coreaudio_logerr (status, "Can not pause playback\n");
462 }
463 core->isPlaying = 0;
464 }
465 break;
466 }
467 return 0;
468 }
469
470 static void *coreaudio_audio_init (void)
471 {
472 return &coreaudio_audio_init;
473 }
474
475 static void coreaudio_audio_fini (void *opaque)
476 {
477 (void) opaque;
478 }
479
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}
484 };
485
486 static struct audio_pcm_ops coreaudio_pcm_ops = {
487 coreaudio_init_out,
488 coreaudio_fini_out,
489 coreaudio_run_out,
490 coreaudio_write,
491 coreaudio_ctl_out,
492
493 NULL,
494 NULL,
495 NULL,
496 NULL,
497 NULL
498 };
499
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
513 };