1 /*
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
30 #include "audio.h"
31
32 #define AUDIO_CAP "coreaudio"
33 #include "audio_int.h"
34
35 #define ENABLE_IN 1
36
37 #if 0
38 # define D(...) fprintf(stderr, __VA_ARGS__)
39 #else
40 # define D(...) ((void)0)
41 #endif
42
43 struct {
44 int out_buffer_frames;
45 int out_nbuffers;
46 int in_buffer_frames;
47 int in_nbuffers;
48 int isAtexit;
49 } conf = {
50 .out_buffer_frames = 512,
51 .out_nbuffers = 4,
52 .in_buffer_frames = 512,
53 .in_nbuffers = 4,
54 .isAtexit = 0
55 };
56
57 /***************************************************************************************/
58 /***************************************************************************************/
59 /*** ***/
60 /*** U T I L I T Y R O U T I N E S ***/
61 /*** ***/
62 /***************************************************************************************/
63 /***************************************************************************************/
64
coreaudio_logstatus(OSStatus status)65 static void coreaudio_logstatus (OSStatus status)
66 {
67 char *str = "BUG";
68
69 switch(status) {
70 case kAudioHardwareNoError:
71 str = "kAudioHardwareNoError";
72 break;
73
74 case kAudioHardwareNotRunningError:
75 str = "kAudioHardwareNotRunningError";
76 break;
77
78 case kAudioHardwareUnspecifiedError:
79 str = "kAudioHardwareUnspecifiedError";
80 break;
81
82 case kAudioHardwareUnknownPropertyError:
83 str = "kAudioHardwareUnknownPropertyError";
84 break;
85
86 case kAudioHardwareBadPropertySizeError:
87 str = "kAudioHardwareBadPropertySizeError";
88 break;
89
90 case kAudioHardwareIllegalOperationError:
91 str = "kAudioHardwareIllegalOperationError";
92 break;
93
94 case kAudioHardwareBadDeviceError:
95 str = "kAudioHardwareBadDeviceError";
96 break;
97
98 case kAudioHardwareBadStreamError:
99 str = "kAudioHardwareBadStreamError";
100 break;
101
102 case kAudioHardwareUnsupportedOperationError:
103 str = "kAudioHardwareUnsupportedOperationError";
104 break;
105
106 case kAudioDeviceUnsupportedFormatError:
107 str = "kAudioDeviceUnsupportedFormatError";
108 break;
109
110 case kAudioDevicePermissionsError:
111 str = "kAudioDevicePermissionsError";
112 break;
113
114 default:
115 AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
116 return;
117 }
118
119 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
120 }
121
coreaudio_logerr(OSStatus status,const char * fmt,...)122 static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
123 OSStatus status,
124 const char *fmt,
125 ...
126 )
127 {
128 va_list ap;
129
130 va_start (ap, fmt);
131 AUD_log (AUDIO_CAP, fmt, ap);
132 va_end (ap);
133
134 coreaudio_logstatus (status);
135 }
136
coreaudio_logerr2(OSStatus status,const char * typ,const char * fmt,...)137 static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
138 OSStatus status,
139 const char *typ,
140 const char *fmt,
141 ...
142 )
143 {
144 va_list ap;
145
146 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
147
148 va_start (ap, fmt);
149 AUD_vlog (AUDIO_CAP, fmt, ap);
150 va_end (ap);
151
152 coreaudio_logstatus (status);
153 }
154
coreaudio_atexit(void)155 static void coreaudio_atexit (void)
156 {
157 conf.isAtexit = 1;
158 }
159
160 /***************************************************************************************/
161 /***************************************************************************************/
162 /*** ***/
163 /*** S H A R E D I N / O U T V O I C E ***/
164 /*** ***/
165 /***************************************************************************************/
166 /***************************************************************************************/
167
168 typedef struct coreAudioVoice {
169 pthread_mutex_t mutex;
170 AudioDeviceID deviceID;
171 Boolean isInput;
172 UInt32 bufferFrameSize;
173 AudioStreamBasicDescription streamBasicDescription;
174 AudioDeviceIOProc ioproc;
175 int live;
176 int decr;
177 int pos;
178 } coreaudioVoice;
179
180
181 static inline UInt32
coreaudio_voice_isPlaying(coreaudioVoice * core)182 coreaudio_voice_isPlaying (coreaudioVoice* core)
183 {
184 OSStatus status;
185 UInt32 result = 0;
186 UInt32 propertySize = sizeof(core->deviceID);
187 status = AudioDeviceGetProperty(
188 core->deviceID, 0, core->isInput,
189 kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
190 if (status != kAudioHardwareNoError) {
191 coreaudio_logerr(status,
192 "Could not determine whether Device is playing\n");
193 }
194 return result;
195 }
196
197 static int
coreaudio_voice_lock(coreaudioVoice * core,const char * fn_name)198 coreaudio_voice_lock (coreaudioVoice* core, const char *fn_name)
199 {
200 int err;
201
202 err = pthread_mutex_lock (&core->mutex);
203 if (err) {
204 dolog ("Could not lock voice for %s\nReason: %s\n",
205 fn_name, strerror (err));
206 return -1;
207 }
208 return 0;
209 }
210
211 static int
coreaudio_voice_unlock(coreaudioVoice * core,const char * fn_name)212 coreaudio_voice_unlock (coreaudioVoice* core, const char *fn_name)
213 {
214 int err;
215
216 err = pthread_mutex_unlock (&core->mutex);
217 if (err) {
218 dolog ("Could not unlock voice for %s\nReason: %s\n",
219 fn_name, strerror (err));
220 return -1;
221 }
222 return 0;
223 }
224
225 static int
coreaudio_voice_ctl(coreaudioVoice * core,int cmd)226 coreaudio_voice_ctl (coreaudioVoice* core, int cmd)
227 {
228 OSStatus status;
229
230 switch (cmd) {
231 case VOICE_ENABLE:
232 /* start playback */
233 D("%s: %s started\n", __FUNCTION__, core->isInput ? "input" : "output");
234 if (!coreaudio_voice_isPlaying(core)) {
235 status = AudioDeviceStart(core->deviceID, core->ioproc);
236 if (status != kAudioHardwareNoError) {
237 coreaudio_logerr (status, "Could not resume playback\n");
238 }
239 }
240 break;
241
242 case VOICE_DISABLE:
243 /* stop playback */
244 D("%s: %s stopped\n", __FUNCTION__, core->isInput ? "input" : "output");
245 if (!conf.isAtexit) {
246 if (coreaudio_voice_isPlaying(core)) {
247 status = AudioDeviceStop(core->deviceID, core->ioproc);
248 if (status != kAudioHardwareNoError) {
249 coreaudio_logerr (status, "Could not pause playback\n");
250 }
251 }
252 }
253 break;
254 }
255 return 0;
256 }
257
258 static void
coreaudio_voice_fini(coreaudioVoice * core)259 coreaudio_voice_fini (coreaudioVoice* core)
260 {
261 OSStatus status;
262 int err;
263
264 if (!conf.isAtexit) {
265 /* stop playback */
266 coreaudio_voice_ctl(core, VOICE_DISABLE);
267
268 /* remove callback */
269 status = AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
270 if (status != kAudioHardwareNoError) {
271 coreaudio_logerr (status, "Could not remove IOProc\n");
272 }
273 }
274 core->deviceID = kAudioDeviceUnknown;
275
276 /* destroy mutex */
277 err = pthread_mutex_destroy(&core->mutex);
278 if (err) {
279 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
280 }
281 }
282
283
284 static int
coreaudio_voice_init(coreaudioVoice * core,struct audsettings * as,int frameSize,AudioDeviceIOProc ioproc,void * hw,int input)285 coreaudio_voice_init (coreaudioVoice* core,
286 struct audsettings* as,
287 int frameSize,
288 AudioDeviceIOProc ioproc,
289 void* hw,
290 int input)
291 {
292 OSStatus status;
293 UInt32 propertySize;
294 int err;
295 int bits = 8;
296 AudioValueRange frameRange;
297 const char* typ = input ? "input" : "playback";
298
299 core->isInput = input ? true : false;
300
301 /* create mutex */
302 err = pthread_mutex_init(&core->mutex, NULL);
303 if (err) {
304 dolog("Could not create mutex\nReason: %s\n", strerror (err));
305 return -1;
306 }
307
308 if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
309 bits = 16;
310 }
311
312 // TODO: audio_pcm_init_info (&hw->info, as);
313 /* open default output device */
314 /* note: we use DefaultSystemOutputDevice because DefaultOutputDevice seems to
315 * always link to the internal speakers, and not the ones selected through system properties
316 * go figure...
317 */
318 propertySize = sizeof(core->deviceID);
319 status = AudioHardwareGetProperty(
320 input ? kAudioHardwarePropertyDefaultInputDevice :
321 kAudioHardwarePropertyDefaultSystemOutputDevice,
322 &propertySize,
323 &core->deviceID);
324 if (status != kAudioHardwareNoError) {
325 coreaudio_logerr2 (status, typ,
326 "Could not get default %s device\n", typ);
327 return -1;
328 }
329 if (core->deviceID == kAudioDeviceUnknown) {
330 dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
331 return -1;
332 }
333
334 /* get minimum and maximum buffer frame sizes */
335 propertySize = sizeof(frameRange);
336 status = AudioDeviceGetProperty(
337 core->deviceID,
338 0,
339 core->isInput,
340 kAudioDevicePropertyBufferFrameSizeRange,
341 &propertySize,
342 &frameRange);
343 if (status != kAudioHardwareNoError) {
344 coreaudio_logerr2 (status, typ,
345 "Could not get device buffer frame range\n");
346 return -1;
347 }
348
349 if (frameRange.mMinimum > frameSize) {
350 core->bufferFrameSize = (UInt32) frameRange.mMinimum;
351 dolog ("warning: Upsizing Output Buffer Frames to %f\n", frameRange.mMinimum);
352 }
353 else if (frameRange.mMaximum < frameSize) {
354 core->bufferFrameSize = (UInt32) frameRange.mMaximum;
355 dolog ("warning: Downsizing Output Buffer Frames to %f\n", frameRange.mMaximum);
356 }
357 else {
358 core->bufferFrameSize = frameSize;
359 }
360
361 /* set Buffer Frame Size */
362 propertySize = sizeof(core->bufferFrameSize);
363 status = AudioDeviceSetProperty(
364 core->deviceID,
365 NULL,
366 0,
367 core->isInput,
368 kAudioDevicePropertyBufferFrameSize,
369 propertySize,
370 &core->bufferFrameSize);
371 if (status != kAudioHardwareNoError) {
372 coreaudio_logerr2 (status, typ,
373 "Could not set device buffer frame size %ld\n",
374 core->bufferFrameSize);
375 return -1;
376 }
377
378 /* get Buffer Frame Size */
379 propertySize = sizeof(core->bufferFrameSize);
380 status = AudioDeviceGetProperty(
381 core->deviceID,
382 0,
383 core->isInput,
384 kAudioDevicePropertyBufferFrameSize,
385 &propertySize,
386 &core->bufferFrameSize);
387 if (status != kAudioHardwareNoError) {
388 coreaudio_logerr2 (status, typ,
389 "Could not get device buffer frame size\n");
390 return -1;
391 }
392 // TODO: hw->samples = *pNBuffers * core->bufferFrameSize;
393
394 /* get StreamFormat */
395 propertySize = sizeof(core->streamBasicDescription);
396 status = AudioDeviceGetProperty(
397 core->deviceID,
398 0,
399 core->isInput,
400 kAudioDevicePropertyStreamFormat,
401 &propertySize,
402 &core->streamBasicDescription);
403 if (status != kAudioHardwareNoError) {
404 coreaudio_logerr2 (status, typ,
405 "Could not get Device Stream properties\n");
406 core->deviceID = kAudioDeviceUnknown;
407 return -1;
408 }
409
410 /* set Samplerate */
411 core->streamBasicDescription.mSampleRate = (Float64) as->freq;
412 propertySize = sizeof(core->streamBasicDescription);
413 status = AudioDeviceSetProperty(
414 core->deviceID,
415 0,
416 0,
417 core->isInput,
418 kAudioDevicePropertyStreamFormat,
419 propertySize,
420 &core->streamBasicDescription);
421 if (status != kAudioHardwareNoError) {
422 coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
423 as->freq);
424 core->deviceID = kAudioDeviceUnknown;
425 return -1;
426 }
427
428 /* set Callback */
429 core->ioproc = ioproc;
430 status = AudioDeviceAddIOProc(core->deviceID, ioproc, hw);
431 if (status != kAudioHardwareNoError) {
432 coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
433 core->deviceID = kAudioDeviceUnknown;
434 return -1;
435 }
436
437 /* start Playback */
438 if (!input && !coreaudio_voice_isPlaying(core)) {
439 status = AudioDeviceStart(core->deviceID, core->ioproc);
440 if (status != kAudioHardwareNoError) {
441 coreaudio_logerr2 (status, typ, "Could not start playback\n");
442 AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
443 core->deviceID = kAudioDeviceUnknown;
444 return -1;
445 }
446 }
447
448 return 0;
449 }
450
451
452 /***************************************************************************************/
453 /***************************************************************************************/
454 /*** ***/
455 /*** O U T P U T V O I C E ***/
456 /*** ***/
457 /***************************************************************************************/
458 /***************************************************************************************/
459
460 typedef struct coreaudioVoiceOut {
461 HWVoiceOut hw;
462 coreaudioVoice core[1];
463 } coreaudioVoiceOut;
464
465 #define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core
466
467
468 static int
coreaudio_run_out(HWVoiceOut * hw)469 coreaudio_run_out (HWVoiceOut *hw)
470 {
471 int live, decr;
472 coreaudioVoice *core = CORE_OUT(hw);
473
474 if (coreaudio_voice_lock (core, "coreaudio_run_out")) {
475 return 0;
476 }
477
478 live = audio_pcm_hw_get_live_out (hw);
479
480 if (core->decr > live) {
481 ldebug ("core->decr %d live %d core->live %d\n",
482 core->decr,
483 live,
484 core->live);
485 }
486
487 decr = audio_MIN (core->decr, live);
488 core->decr -= decr;
489 core->live = live - decr;
490 hw->rpos = core->pos;
491
492 coreaudio_voice_unlock (core, "coreaudio_run_out");
493 return decr;
494 }
495
496
497 /* callback to feed audiooutput buffer */
498 static OSStatus
audioOutDeviceIOProc(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * inInputData,const AudioTimeStamp * inInputTime,AudioBufferList * outOutputData,const AudioTimeStamp * inOutputTime,void * hwptr)499 audioOutDeviceIOProc(
500 AudioDeviceID inDevice,
501 const AudioTimeStamp* inNow,
502 const AudioBufferList* inInputData,
503 const AudioTimeStamp* inInputTime,
504 AudioBufferList* outOutputData,
505 const AudioTimeStamp* inOutputTime,
506 void* hwptr)
507 {
508 UInt32 frame, frameCount;
509 float *out = outOutputData->mBuffers[0].mData;
510 HWVoiceOut *hw = hwptr;
511 coreaudioVoice *core = CORE_OUT(hw);
512 int rpos, live;
513 struct st_sample *src;
514 #ifndef FLOAT_MIXENG
515 #ifdef RECIPROCAL
516 const float scale = 1.f / UINT_MAX;
517 #else
518 const float scale = UINT_MAX;
519 #endif
520 #endif
521
522 if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
523 inInputTime = 0;
524 return 0;
525 }
526
527 frameCount = core->bufferFrameSize;
528 live = core->live;
529
530 /* if there are not enough samples, set signal and return */
531 if (live < frameCount) {
532 inInputTime = 0;
533 coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
534 return 0;
535 }
536
537 rpos = core->pos;
538 src = hw->mix_buf + rpos;
539
540 /* fill buffer */
541 for (frame = 0; frame < frameCount; frame++) {
542 #ifdef FLOAT_MIXENG
543 *out++ = src[frame].l; /* left channel */
544 *out++ = src[frame].r; /* right channel */
545 #else
546 #ifdef RECIPROCAL
547 *out++ = src[frame].l * scale; /* left channel */
548 *out++ = src[frame].r * scale; /* right channel */
549 #else
550 *out++ = src[frame].l / scale; /* left channel */
551 *out++ = src[frame].r / scale; /* right channel */
552 #endif
553 #endif
554 }
555
556 rpos = (rpos + frameCount) % hw->samples;
557 core->decr += frameCount;
558 core->pos = rpos;
559
560 coreaudio_voice_unlock (core, "audioDeviceIOProc");
561 return 0;
562 }
563
564 static int
coreaudio_write(SWVoiceOut * sw,void * buf,int len)565 coreaudio_write (SWVoiceOut *sw, void *buf, int len)
566 {
567 return audio_pcm_sw_write (sw, buf, len);
568 }
569
570 static int
coreaudio_init_out(HWVoiceOut * hw,struct audsettings * as)571 coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
572 {
573 coreaudioVoice* core = CORE_OUT(hw);
574 int err;
575
576 audio_pcm_init_info (&hw->info, as);
577
578 err = coreaudio_voice_init( core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0 );
579 if (err < 0)
580 return err;
581
582 hw->samples = core->bufferFrameSize * conf.out_nbuffers;
583 return 0;
584 }
585
586 static void
coreaudio_fini_out(HWVoiceOut * hw)587 coreaudio_fini_out (HWVoiceOut *hw)
588 {
589
590 coreaudioVoice* core = CORE_OUT(hw);
591
592 coreaudio_voice_fini(core);
593 }
594
595 static int
coreaudio_ctl_out(HWVoiceOut * hw,int cmd,...)596 coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
597 {
598 coreaudioVoice* core = CORE_OUT(hw);
599
600 return coreaudio_voice_ctl(core, cmd);
601 }
602
603 /***************************************************************************************/
604 /***************************************************************************************/
605 /*** ***/
606 /*** I N P U T V O I C E ***/
607 /*** ***/
608 /***************************************************************************************/
609 /***************************************************************************************/
610
611
612
613 typedef struct coreaudioVoiceIn {
614 HWVoiceIn hw;
615 coreaudioVoice core[1];
616 } coreaudioVoiceIn;
617
618 #define CORE_IN(hw) ((coreaudioVoiceIn*)(hw))->core
619
620
621 static int
coreaudio_run_in(HWVoiceIn * hw)622 coreaudio_run_in (HWVoiceIn *hw)
623 {
624 int decr;
625
626 coreaudioVoice *core = CORE_IN(hw);
627
628 if (coreaudio_voice_lock (core, "coreaudio_run_in")) {
629 return 0;
630 }
631 D("%s: core.decr=%d core.pos=%d\n", __FUNCTION__, core->decr, core->pos);
632 decr = core->decr;
633 core->decr -= decr;
634 hw->wpos = core->pos;
635
636 coreaudio_voice_unlock (core, "coreaudio_run_in");
637 return decr;
638 }
639
640
641 /* callback to feed audiooutput buffer */
642 static OSStatus
audioInDeviceIOProc(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * inInputData,const AudioTimeStamp * inInputTime,AudioBufferList * outOutputData,const AudioTimeStamp * inOutputTime,void * hwptr)643 audioInDeviceIOProc(
644 AudioDeviceID inDevice,
645 const AudioTimeStamp* inNow,
646 const AudioBufferList* inInputData,
647 const AudioTimeStamp* inInputTime,
648 AudioBufferList* outOutputData,
649 const AudioTimeStamp* inOutputTime,
650 void* hwptr)
651 {
652 UInt32 frame, frameCount;
653 float *in = inInputData->mBuffers[0].mData;
654 HWVoiceIn *hw = hwptr;
655 coreaudioVoice *core = CORE_IN(hw);
656 int wpos, avail;
657 struct st_sample *dst;
658 #ifndef FLOAT_MIXENG
659 #ifdef RECIPROCAL
660 const float scale = 1.f / UINT_MAX;
661 #else
662 const float scale = UINT_MAX;
663 #endif
664 #endif
665
666 if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
667 inInputTime = 0;
668 return 0;
669 }
670
671 frameCount = core->bufferFrameSize;
672 avail = hw->samples - hw->total_samples_captured - core->decr;
673
674 D("%s: enter avail=%d core.decr=%d core.pos=%d hw.samples=%d hw.total_samples_captured=%d frameCount=%d\n",
675 __FUNCTION__, avail, core->decr, core->pos, hw->samples, hw->total_samples_captured, (int)frameCount);
676
677 /* if there are not enough samples, set signal and return */
678 if (avail < frameCount) {
679 inInputTime = 0;
680 coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
681 return 0;
682 }
683
684 wpos = core->pos;
685 dst = hw->conv_buf + wpos;
686
687 /* fill buffer */
688 for (frame = 0; frame < frameCount; frame++) {
689 #ifdef FLOAT_MIXENG
690 dst[frame].l = *in++; /* left channel */
691 dst[frame].r = *in++; /* right channel */
692 #else
693 #ifdef RECIPROCAL
694 dst[frame].l = *in++ * scale; /* left channel */
695 dst[frame].r = *in++ * scale; /* right channel */
696 #else
697 dst[frame].l = *in++ / scale; /* left channel */
698 dst[frame].r = *in++ / scale; /* right channel */
699 #endif
700 #endif
701 }
702
703 wpos = (wpos + frameCount) % hw->samples;
704 core->decr += frameCount;
705 core->pos = wpos;
706
707 D("exit: core.decr=%d core.pos=%d\n", core->decr, core->pos);
708 coreaudio_voice_unlock (core, "audioDeviceIOProc");
709 return 0;
710 }
711
712 static int
coreaudio_read(SWVoiceIn * sw,void * buf,int len)713 coreaudio_read (SWVoiceIn *sw, void *buf, int len)
714 {
715 int result = audio_pcm_sw_read(sw, buf, len);
716 D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result);
717 return result;
718 }
719
720 static int
coreaudio_init_in(HWVoiceIn * hw,struct audsettings * as)721 coreaudio_init_in (HWVoiceIn *hw, struct audsettings *as)
722 {
723 coreaudioVoice* core = CORE_IN(hw);
724 int err;
725
726 audio_pcm_init_info (&hw->info, as);
727
728 err = coreaudio_voice_init( core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1 );
729 if (err < 0) {
730 return err;
731 }
732
733 hw->samples = core->bufferFrameSize * conf.in_nbuffers;
734 return 0;
735 }
736
737 static void
coreaudio_fini_in(HWVoiceIn * hw)738 coreaudio_fini_in (HWVoiceIn *hw)
739 {
740
741 coreaudioVoice* core = CORE_IN(hw);
742
743 coreaudio_voice_fini(core);
744 }
745
746 static int
coreaudio_ctl_in(HWVoiceIn * hw,int cmd,...)747 coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
748 {
749 coreaudioVoice* core = CORE_IN(hw);
750
751 return coreaudio_voice_ctl(core, cmd);
752 }
753
754 static void*
coreaudio_audio_init(void)755 coreaudio_audio_init (void)
756 {
757 atexit(coreaudio_atexit);
758 return &coreaudio_audio_init;
759 }
760
761 static void
coreaudio_audio_fini(void * opaque)762 coreaudio_audio_fini (void *opaque)
763 {
764 (void) opaque;
765 }
766
767 static struct audio_option coreaudio_options[] = {
768 {"OUT_BUFFER_SIZE", AUD_OPT_INT, &conf.out_buffer_frames,
769 "Size of the output buffer in frames", NULL, 0},
770 {"OUT_BUFFER_COUNT", AUD_OPT_INT, &conf.out_nbuffers,
771 "Number of output buffers", NULL, 0},
772 {"IN_BUFFER_SIZE", AUD_OPT_INT, &conf.in_buffer_frames,
773 "Size of the input buffer in frames", NULL, 0},
774 {"IN_BUFFER_COUNT", AUD_OPT_INT, &conf.in_nbuffers,
775 "Number of input buffers", NULL, 0},
776 {NULL, 0, NULL, NULL, NULL, 0}
777 };
778
779 static struct audio_pcm_ops coreaudio_pcm_ops = {
780 coreaudio_init_out,
781 coreaudio_fini_out,
782 coreaudio_run_out,
783 coreaudio_write,
784 coreaudio_ctl_out,
785
786 #if ENABLE_IN
787 coreaudio_init_in,
788 coreaudio_fini_in,
789 coreaudio_run_in,
790 coreaudio_read,
791 coreaudio_ctl_in
792 #else
793 NULL,
794 NULL,
795 NULL,
796 NULL,
797 NULL
798 #endif
799 };
800
801 struct audio_driver coreaudio_audio_driver = {
802 INIT_FIELD (name = ) "coreaudio",
803 INIT_FIELD (descr = )
804 "CoreAudio (developer.apple.com/audio/coreaudio.html)",
805 INIT_FIELD (options = ) coreaudio_options,
806 INIT_FIELD (init = ) coreaudio_audio_init,
807 INIT_FIELD (fini = ) coreaudio_audio_fini,
808 INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
809 INIT_FIELD (can_be_default = ) 1,
810 #if ENABLE_IN
811 INIT_FIELD (max_voices_out = ) 1,
812 INIT_FIELD (max_voices_in = ) 1,
813 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
814 INIT_FIELD (voice_size_in = ) sizeof (coreaudioVoiceIn),
815 #else
816 INIT_FIELD (max_voices_out = ) 1,
817 INIT_FIELD (max_voices_in = ) 0,
818 INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
819 INIT_FIELD (voice_size_in = ) 0,
820 #endif
821 };
822