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