blob: 7eb844804782aba64cd0866d5fc100450211bbd8 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * QEMU OS X CoreAudio audio driver
3 *
4 * Copyright (c) 2008 The Android Open Source Project
5 * Copyright (c) 2005 Mike Kronenberg
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26#include <CoreAudio/CoreAudio.h>
27#include <string.h> /* strerror */
28#include <pthread.h> /* pthread_X */
29
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +010030#include "qemu-common.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080031#include "audio.h"
32
33#define AUDIO_CAP "coreaudio"
34#include "audio_int.h"
35
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080036#if 0
37# define D(...) fprintf(stderr, __VA_ARGS__)
38#else
39# define D(...) ((void)0)
40#endif
41
42struct {
43 int out_buffer_frames;
44 int out_nbuffers;
45 int in_buffer_frames;
46 int in_nbuffers;
47 int isAtexit;
48} conf = {
49 .out_buffer_frames = 512,
50 .out_nbuffers = 4,
51 .in_buffer_frames = 512,
52 .in_nbuffers = 4,
53 .isAtexit = 0
54};
55
56/***************************************************************************************/
57/***************************************************************************************/
58/*** ***/
59/*** U T I L I T Y R O U T I N E S ***/
60/*** ***/
61/***************************************************************************************/
62/***************************************************************************************/
63
64static void coreaudio_logstatus (OSStatus status)
65{
66 char *str = "BUG";
67
68 switch(status) {
69 case kAudioHardwareNoError:
70 str = "kAudioHardwareNoError";
71 break;
72
73 case kAudioHardwareNotRunningError:
74 str = "kAudioHardwareNotRunningError";
75 break;
76
77 case kAudioHardwareUnspecifiedError:
78 str = "kAudioHardwareUnspecifiedError";
79 break;
80
81 case kAudioHardwareUnknownPropertyError:
82 str = "kAudioHardwareUnknownPropertyError";
83 break;
84
85 case kAudioHardwareBadPropertySizeError:
86 str = "kAudioHardwareBadPropertySizeError";
87 break;
88
89 case kAudioHardwareIllegalOperationError:
90 str = "kAudioHardwareIllegalOperationError";
91 break;
92
93 case kAudioHardwareBadDeviceError:
94 str = "kAudioHardwareBadDeviceError";
95 break;
96
97 case kAudioHardwareBadStreamError:
98 str = "kAudioHardwareBadStreamError";
99 break;
100
101 case kAudioHardwareUnsupportedOperationError:
102 str = "kAudioHardwareUnsupportedOperationError";
103 break;
104
105 case kAudioDeviceUnsupportedFormatError:
106 str = "kAudioDeviceUnsupportedFormatError";
107 break;
108
109 case kAudioDevicePermissionsError:
110 str = "kAudioDevicePermissionsError";
111 break;
112
113 default:
114 AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
115 return;
116 }
117
118 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
119}
120
121static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
122 OSStatus status,
123 const char *fmt,
124 ...
125 )
126{
127 va_list ap;
128
129 va_start (ap, fmt);
130 AUD_log (AUDIO_CAP, fmt, ap);
131 va_end (ap);
132
133 coreaudio_logstatus (status);
134}
135
136static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
137 OSStatus status,
138 const char *typ,
139 const char *fmt,
140 ...
141 )
142{
143 va_list ap;
144
145 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
146
147 va_start (ap, fmt);
148 AUD_vlog (AUDIO_CAP, fmt, ap);
149 va_end (ap);
150
151 coreaudio_logstatus (status);
152}
153
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800154/***************************************************************************************/
155/***************************************************************************************/
156/*** ***/
157/*** S H A R E D I N / O U T V O I C E ***/
158/*** ***/
159/***************************************************************************************/
160/***************************************************************************************/
161
162typedef struct coreAudioVoice {
163 pthread_mutex_t mutex;
164 AudioDeviceID deviceID;
165 Boolean isInput;
166 UInt32 bufferFrameSize;
167 AudioStreamBasicDescription streamBasicDescription;
168 AudioDeviceIOProc ioproc;
169 int live;
170 int decr;
171 int pos;
172} coreaudioVoice;
173
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800174static inline UInt32
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100175coreaudio_voice_isPlaying (coreaudioVoice *core)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800176{
177 OSStatus status;
178 UInt32 result = 0;
179 UInt32 propertySize = sizeof(core->deviceID);
180 status = AudioDeviceGetProperty(
181 core->deviceID, 0, core->isInput,
182 kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
183 if (status != kAudioHardwareNoError) {
184 coreaudio_logerr(status,
185 "Could not determine whether Device is playing\n");
186 }
187 return result;
188}
189
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100190static void coreaudio_atexit (void)
191{
192 conf.isAtexit = 1;
193}
194
195static int coreaudio_voice_lock (coreaudioVoice *core, const char *fn_name)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800196{
197 int err;
198
199 err = pthread_mutex_lock (&core->mutex);
200 if (err) {
201 dolog ("Could not lock voice for %s\nReason: %s\n",
202 fn_name, strerror (err));
203 return -1;
204 }
205 return 0;
206}
207
208static int
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100209coreaudio_voice_unlock (coreaudioVoice *core, const char *fn_name)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800210{
211 int err;
212
213 err = pthread_mutex_unlock (&core->mutex);
214 if (err) {
215 dolog ("Could not unlock voice for %s\nReason: %s\n",
216 fn_name, strerror (err));
217 return -1;
218 }
219 return 0;
220}
221
222static int
223coreaudio_voice_ctl (coreaudioVoice* core, int cmd)
224{
225 OSStatus status;
226
227 switch (cmd) {
228 case VOICE_ENABLE:
229 /* start playback */
230 D("%s: %s started\n", __FUNCTION__, core->isInput ? "input" : "output");
231 if (!coreaudio_voice_isPlaying(core)) {
232 status = AudioDeviceStart(core->deviceID, core->ioproc);
233 if (status != kAudioHardwareNoError) {
234 coreaudio_logerr (status, "Could not resume playback\n");
235 }
236 }
237 break;
238
239 case VOICE_DISABLE:
240 /* stop playback */
241 D("%s: %s stopped\n", __FUNCTION__, core->isInput ? "input" : "output");
242 if (!conf.isAtexit) {
243 if (coreaudio_voice_isPlaying(core)) {
244 status = AudioDeviceStop(core->deviceID, core->ioproc);
245 if (status != kAudioHardwareNoError) {
246 coreaudio_logerr (status, "Could not pause playback\n");
247 }
248 }
249 }
250 break;
251 }
252 return 0;
253}
254
255static void
256coreaudio_voice_fini (coreaudioVoice* core)
257{
258 OSStatus status;
259 int err;
260
261 if (!conf.isAtexit) {
262 /* stop playback */
263 coreaudio_voice_ctl(core, VOICE_DISABLE);
264
265 /* remove callback */
266 status = AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
267 if (status != kAudioHardwareNoError) {
268 coreaudio_logerr (status, "Could not remove IOProc\n");
269 }
270 }
271 core->deviceID = kAudioDeviceUnknown;
272
273 /* destroy mutex */
274 err = pthread_mutex_destroy(&core->mutex);
275 if (err) {
276 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
277 }
278}
279
280
281static int
282coreaudio_voice_init (coreaudioVoice* core,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700283 struct audsettings* as,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800284 int frameSize,
285 AudioDeviceIOProc ioproc,
286 void* hw,
287 int input)
288{
289 OSStatus status;
290 UInt32 propertySize;
291 int err;
292 int bits = 8;
293 AudioValueRange frameRange;
294 const char* typ = input ? "input" : "playback";
295
296 core->isInput = input ? true : false;
297
298 /* create mutex */
299 err = pthread_mutex_init(&core->mutex, NULL);
300 if (err) {
301 dolog("Could not create mutex\nReason: %s\n", strerror (err));
302 return -1;
303 }
304
305 if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
306 bits = 16;
307 }
308
309 // TODO: audio_pcm_init_info (&hw->info, as);
310 /* open default output device */
311 /* note: we use DefaultSystemOutputDevice because DefaultOutputDevice seems to
312 * always link to the internal speakers, and not the ones selected through system properties
313 * go figure...
314 */
315 propertySize = sizeof(core->deviceID);
316 status = AudioHardwareGetProperty(
317 input ? kAudioHardwarePropertyDefaultInputDevice :
318 kAudioHardwarePropertyDefaultSystemOutputDevice,
319 &propertySize,
320 &core->deviceID);
321 if (status != kAudioHardwareNoError) {
322 coreaudio_logerr2 (status, typ,
323 "Could not get default %s device\n", typ);
324 return -1;
325 }
326 if (core->deviceID == kAudioDeviceUnknown) {
327 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
328 return -1;
329 }
330
331 /* get minimum and maximum buffer frame sizes */
332 propertySize = sizeof(frameRange);
333 status = AudioDeviceGetProperty(
334 core->deviceID,
335 0,
336 core->isInput,
337 kAudioDevicePropertyBufferFrameSizeRange,
338 &propertySize,
339 &frameRange);
340 if (status != kAudioHardwareNoError) {
341 coreaudio_logerr2 (status, typ,
342 "Could not get device buffer frame range\n");
343 return -1;
344 }
345
346 if (frameRange.mMinimum > frameSize) {
347 core->bufferFrameSize = (UInt32) frameRange.mMinimum;
348 dolog ("warning: Upsizing Output Buffer Frames to %f\n", frameRange.mMinimum);
349 }
350 else if (frameRange.mMaximum < frameSize) {
351 core->bufferFrameSize = (UInt32) frameRange.mMaximum;
352 dolog ("warning: Downsizing Output Buffer Frames to %f\n", frameRange.mMaximum);
353 }
354 else {
355 core->bufferFrameSize = frameSize;
356 }
357
358 /* set Buffer Frame Size */
359 propertySize = sizeof(core->bufferFrameSize);
360 status = AudioDeviceSetProperty(
361 core->deviceID,
362 NULL,
363 0,
364 core->isInput,
365 kAudioDevicePropertyBufferFrameSize,
366 propertySize,
367 &core->bufferFrameSize);
368 if (status != kAudioHardwareNoError) {
369 coreaudio_logerr2 (status, typ,
370 "Could not set device buffer frame size %ld\n",
371 core->bufferFrameSize);
372 return -1;
373 }
374
375 /* get Buffer Frame Size */
376 propertySize = sizeof(core->bufferFrameSize);
377 status = AudioDeviceGetProperty(
378 core->deviceID,
379 0,
380 core->isInput,
381 kAudioDevicePropertyBufferFrameSize,
382 &propertySize,
383 &core->bufferFrameSize);
384 if (status != kAudioHardwareNoError) {
385 coreaudio_logerr2 (status, typ,
386 "Could not get device buffer frame size\n");
387 return -1;
388 }
389 // TODO: hw->samples = *pNBuffers * core->bufferFrameSize;
390
391 /* get StreamFormat */
392 propertySize = sizeof(core->streamBasicDescription);
393 status = AudioDeviceGetProperty(
394 core->deviceID,
395 0,
396 core->isInput,
397 kAudioDevicePropertyStreamFormat,
398 &propertySize,
399 &core->streamBasicDescription);
400 if (status != kAudioHardwareNoError) {
401 coreaudio_logerr2 (status, typ,
402 "Could not get Device Stream properties\n");
403 core->deviceID = kAudioDeviceUnknown;
404 return -1;
405 }
406
407 /* set Samplerate */
408 core->streamBasicDescription.mSampleRate = (Float64) as->freq;
409 propertySize = sizeof(core->streamBasicDescription);
410 status = AudioDeviceSetProperty(
411 core->deviceID,
412 0,
413 0,
414 core->isInput,
415 kAudioDevicePropertyStreamFormat,
416 propertySize,
417 &core->streamBasicDescription);
418 if (status != kAudioHardwareNoError) {
419 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
420 as->freq);
421 core->deviceID = kAudioDeviceUnknown;
422 return -1;
423 }
424
425 /* set Callback */
426 core->ioproc = ioproc;
427 status = AudioDeviceAddIOProc(core->deviceID, ioproc, hw);
428 if (status != kAudioHardwareNoError) {
429 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
430 core->deviceID = kAudioDeviceUnknown;
431 return -1;
432 }
433
434 /* start Playback */
435 if (!input && !coreaudio_voice_isPlaying(core)) {
436 status = AudioDeviceStart(core->deviceID, core->ioproc);
437 if (status != kAudioHardwareNoError) {
438 coreaudio_logerr2 (status, typ, "Could not start playback\n");
439 AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
440 core->deviceID = kAudioDeviceUnknown;
441 return -1;
442 }
443 }
444
445 return 0;
446}
447
448
449/***************************************************************************************/
450/***************************************************************************************/
451/*** ***/
452/*** O U T P U T V O I C E ***/
453/*** ***/
454/***************************************************************************************/
455/***************************************************************************************/
456
457typedef struct coreaudioVoiceOut {
458 HWVoiceOut hw;
459 coreaudioVoice core[1];
460} coreaudioVoiceOut;
461
462#define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core
463
464
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100465static int coreaudio_run_out (HWVoiceOut *hw, int live)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800466{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100467 int decr;
468 coreaudioVoice *core = CORE_OUT(hw);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800469
470 if (coreaudio_voice_lock (core, "coreaudio_run_out")) {
471 return 0;
472 }
473
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800474 if (core->decr > live) {
475 ldebug ("core->decr %d live %d core->live %d\n",
476 core->decr,
477 live,
478 core->live);
479 }
480
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100481 decr = audio_MIN (core->decr, live);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800482 core->decr -= decr;
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100483
484 core->live = live - decr;
485 hw->rpos = core->pos;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800486
487 coreaudio_voice_unlock (core, "coreaudio_run_out");
488 return decr;
489}
490
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800491/* callback to feed audiooutput buffer */
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100492static OSStatus audioOutDeviceIOProc(
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800493 AudioDeviceID inDevice,
494 const AudioTimeStamp* inNow,
495 const AudioBufferList* inInputData,
496 const AudioTimeStamp* inInputTime,
497 AudioBufferList* outOutputData,
498 const AudioTimeStamp* inOutputTime,
499 void* hwptr)
500{
501 UInt32 frame, frameCount;
502 float *out = outOutputData->mBuffers[0].mData;
503 HWVoiceOut *hw = hwptr;
504 coreaudioVoice *core = CORE_OUT(hw);
505 int rpos, live;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700506 struct st_sample *src;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800507#ifndef FLOAT_MIXENG
508#ifdef RECIPROCAL
509 const float scale = 1.f / UINT_MAX;
510#else
511 const float scale = UINT_MAX;
512#endif
513#endif
514
515 if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
516 inInputTime = 0;
517 return 0;
518 }
519
520 frameCount = core->bufferFrameSize;
521 live = core->live;
522
523 /* if there are not enough samples, set signal and return */
524 if (live < frameCount) {
525 inInputTime = 0;
526 coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
527 return 0;
528 }
529
530 rpos = core->pos;
531 src = hw->mix_buf + rpos;
532
533 /* fill buffer */
534 for (frame = 0; frame < frameCount; frame++) {
535#ifdef FLOAT_MIXENG
536 *out++ = src[frame].l; /* left channel */
537 *out++ = src[frame].r; /* right channel */
538#else
539#ifdef RECIPROCAL
540 *out++ = src[frame].l * scale; /* left channel */
541 *out++ = src[frame].r * scale; /* right channel */
542#else
543 *out++ = src[frame].l / scale; /* left channel */
544 *out++ = src[frame].r / scale; /* right channel */
545#endif
546#endif
547 }
548
549 rpos = (rpos + frameCount) % hw->samples;
550 core->decr += frameCount;
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100551 core->pos = rpos;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800552
553 coreaudio_voice_unlock (core, "audioDeviceIOProc");
554 return 0;
555}
556
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100557static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800558{
559 return audio_pcm_sw_write (sw, buf, len);
560}
561
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100562static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800563{
564 coreaudioVoice* core = CORE_OUT(hw);
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100565 int err;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800566
567 audio_pcm_init_info (&hw->info, as);
568
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100569 err = coreaudio_voice_init (core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800570 if (err < 0)
571 return err;
572
573 hw->samples = core->bufferFrameSize * conf.out_nbuffers;
574 return 0;
575}
576
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100577static void coreaudio_fini_out (HWVoiceOut *hw)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800578{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100579 coreaudioVoice *core = CORE_OUT(hw);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800580
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100581 coreaudio_voice_fini (core);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800582}
583
584static int
585coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
586{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100587 coreaudioVoice *core = CORE_OUT(hw);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800588
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100589 return coreaudio_voice_ctl (core, cmd);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800590}
591
592/***************************************************************************************/
593/***************************************************************************************/
594/*** ***/
595/*** I N P U T V O I C E ***/
596/*** ***/
597/***************************************************************************************/
598/***************************************************************************************/
599
600
601
602typedef struct coreaudioVoiceIn {
603 HWVoiceIn hw;
604 coreaudioVoice core[1];
605} coreaudioVoiceIn;
606
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100607#define CORE_IN(hw) ((coreaudioVoiceIn *) (hw))->core
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800608
609
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100610static int coreaudio_run_in (HWVoiceIn *hw, int live)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800611{
612 int decr;
613
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100614 coreaudioVoice *core = CORE_IN(hw);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800615
616 if (coreaudio_voice_lock (core, "coreaudio_run_in")) {
617 return 0;
618 }
619 D("%s: core.decr=%d core.pos=%d\n", __FUNCTION__, core->decr, core->pos);
620 decr = core->decr;
621 core->decr -= decr;
622 hw->wpos = core->pos;
623
624 coreaudio_voice_unlock (core, "coreaudio_run_in");
625 return decr;
626}
627
628
629/* callback to feed audiooutput buffer */
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100630static OSStatus audioInDeviceIOProc(
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800631 AudioDeviceID inDevice,
632 const AudioTimeStamp* inNow,
633 const AudioBufferList* inInputData,
634 const AudioTimeStamp* inInputTime,
635 AudioBufferList* outOutputData,
636 const AudioTimeStamp* inOutputTime,
637 void* hwptr)
638{
639 UInt32 frame, frameCount;
640 float *in = inInputData->mBuffers[0].mData;
641 HWVoiceIn *hw = hwptr;
642 coreaudioVoice *core = CORE_IN(hw);
643 int wpos, avail;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700644 struct st_sample *dst;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800645#ifndef FLOAT_MIXENG
646#ifdef RECIPROCAL
647 const float scale = 1.f / UINT_MAX;
648#else
649 const float scale = UINT_MAX;
650#endif
651#endif
652
653 if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
654 inInputTime = 0;
655 return 0;
656 }
657
658 frameCount = core->bufferFrameSize;
659 avail = hw->samples - hw->total_samples_captured - core->decr;
660
661 D("%s: enter avail=%d core.decr=%d core.pos=%d hw.samples=%d hw.total_samples_captured=%d frameCount=%d\n",
662 __FUNCTION__, avail, core->decr, core->pos, hw->samples, hw->total_samples_captured, (int)frameCount);
663
664 /* if there are not enough samples, set signal and return */
665 if (avail < frameCount) {
666 inInputTime = 0;
667 coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
668 return 0;
669 }
670
671 wpos = core->pos;
672 dst = hw->conv_buf + wpos;
673
674 /* fill buffer */
675 for (frame = 0; frame < frameCount; frame++) {
676#ifdef FLOAT_MIXENG
677 dst[frame].l = *in++; /* left channel */
678 dst[frame].r = *in++; /* right channel */
679#else
680#ifdef RECIPROCAL
681 dst[frame].l = *in++ * scale; /* left channel */
682 dst[frame].r = *in++ * scale; /* right channel */
683#else
684 dst[frame].l = *in++ / scale; /* left channel */
685 dst[frame].r = *in++ / scale; /* right channel */
686#endif
687#endif
688 }
689
690 wpos = (wpos + frameCount) % hw->samples;
691 core->decr += frameCount;
692 core->pos = wpos;
693
694 D("exit: core.decr=%d core.pos=%d\n", core->decr, core->pos);
695 coreaudio_voice_unlock (core, "audioDeviceIOProc");
696 return 0;
697}
698
699static int
700coreaudio_read (SWVoiceIn *sw, void *buf, int len)
701{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100702 int result = audio_pcm_sw_read (sw, buf, len);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800703 D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result);
704 return result;
705}
706
707static int
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700708coreaudio_init_in (HWVoiceIn *hw, struct audsettings *as)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800709{
710 coreaudioVoice* core = CORE_IN(hw);
711 int err;
712
713 audio_pcm_init_info (&hw->info, as);
714
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100715 err = coreaudio_voice_init (core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800716 if (err < 0) {
717 return err;
718 }
719
720 hw->samples = core->bufferFrameSize * conf.in_nbuffers;
721 return 0;
722}
723
724static void
725coreaudio_fini_in (HWVoiceIn *hw)
726{
727
728 coreaudioVoice* core = CORE_IN(hw);
729
730 coreaudio_voice_fini(core);
731}
732
733static int
734coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
735{
736 coreaudioVoice* core = CORE_IN(hw);
737
738 return coreaudio_voice_ctl(core, cmd);
739}
740
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100741static void *coreaudio_audio_init (void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800742{
743 atexit(coreaudio_atexit);
744 return &coreaudio_audio_init;
745}
746
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100747static void coreaudio_audio_fini (void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800748{
749 (void) opaque;
750}
751
752static struct audio_option coreaudio_options[] = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100753 {
754 .name = "OUT_BUFFER_SIZE",
755 .tag = AUD_OPT_INT,
756 .valp = &conf.out_buffer_frames,
757 .descr = "Size of the output buffer in frames"
758 },
759 {
760 .name = "OUT_BUFFER_COUNT",
761 .tag = AUD_OPT_INT,
762 .valp = &conf.out_nbuffers,
763 .descr = "Number of output buffers"
764 },
765 {
766 .name = "IN_BUFFER_SIZE",
767 .tag = AUD_OPT_INT,
768 .valp = &conf.in_buffer_frames,
769 .descr = "Size of the input buffer in frames"
770 },
771 {
772 .name = "IN_BUFFER_COUNT",
773 .tag = AUD_OPT_INT,
774 .valp = &conf.in_nbuffers,
775 .descr = "Number of input buffers"
776 },
777 { /* End of list */ }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800778};
779
780static struct audio_pcm_ops coreaudio_pcm_ops = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100781 .init_out = coreaudio_init_out,
782 .fini_out = coreaudio_fini_out,
783 .run_out = coreaudio_run_out,
784 .write = coreaudio_write,
David 'Digit' Turner832a4c22011-01-03 11:24:02 +0100785 .ctl_out = coreaudio_ctl_out,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800786
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100787 .init_in = coreaudio_init_in,
788 .fini_in = coreaudio_fini_in,
789 .run_in = coreaudio_run_in,
790 .read = coreaudio_read,
791 .ctl_in = coreaudio_ctl_in
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800792};
793
794struct audio_driver coreaudio_audio_driver = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100795 .name = "coreaudio",
796 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
797 .options = coreaudio_options,
798 .init = coreaudio_audio_init,
799 .fini = coreaudio_audio_fini,
800 .pcm_ops = &coreaudio_pcm_ops,
801 .can_be_default = 1,
802 .max_voices_out = 1,
803 .max_voices_in = 1,
804 .voice_size_out = sizeof (coreaudioVoiceOut),
805 .voice_size_in = sizeof (coreaudioVoiceIn),
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800806};