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 "qemu-common.h"
31 #include "audio.h"
32
33 #define AUDIO_CAP "coreaudio"
34 #include "audio_int.h"
35
36 #if 0
37 # define D(...) fprintf(stderr, __VA_ARGS__)
38 #else
39 # define D(...) ((void)0)
40 #endif
41
42 struct {
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
coreaudio_logstatus(OSStatus status)64 static 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
coreaudio_logerr(OSStatus status,const char * fmt,...)121 static 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
coreaudio_logerr2(OSStatus status,const char * typ,const char * fmt,...)136 static 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
154 /***************************************************************************************/
155 /***************************************************************************************/
156 /*** ***/
157 /*** S H A R E D I N / O U T V O I C E ***/
158 /*** ***/
159 /***************************************************************************************/
160 /***************************************************************************************/
161
162 typedef 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
174 static inline UInt32
coreaudio_voice_isPlaying(coreaudioVoice * core)175 coreaudio_voice_isPlaying (coreaudioVoice *core)
176 {
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
coreaudio_atexit(void)190 static void coreaudio_atexit (void)
191 {
192 conf.isAtexit = 1;
193 }
194
coreaudio_voice_lock(coreaudioVoice * core,const char * fn_name)195 static int coreaudio_voice_lock (coreaudioVoice *core, const char *fn_name)
196 {
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
208 static int
coreaudio_voice_unlock(coreaudioVoice * core,const char * fn_name)209 coreaudio_voice_unlock (coreaudioVoice *core, const char *fn_name)
210 {
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
222 static int
coreaudio_voice_ctl(coreaudioVoice * core,int cmd)223 coreaudio_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
255 static void
coreaudio_voice_fini(coreaudioVoice * core)256 coreaudio_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
281 static int
coreaudio_voice_init(coreaudioVoice * core,struct audsettings * as,int frameSize,AudioDeviceIOProc ioproc,void * hw,int input)282 coreaudio_voice_init (coreaudioVoice* core,
283 struct audsettings* as,
284 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
457 typedef struct coreaudioVoiceOut {
458 HWVoiceOut hw;
459 coreaudioVoice core[1];
460 } coreaudioVoiceOut;
461
462 #define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core
463
464
coreaudio_run_out(HWVoiceOut * hw,int live)465 static int coreaudio_run_out (HWVoiceOut *hw, int live)
466 {
467 int decr;
468 coreaudioVoice *core = CORE_OUT(hw);
469
470 if (coreaudio_voice_lock (core, "coreaudio_run_out")) {
471 return 0;
472 }
473
474 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
481 decr = audio_MIN (core->decr, live);
482 core->decr -= decr;
483
484 core->live = live - decr;
485 hw->rpos = core->pos;
486
487 coreaudio_voice_unlock (core, "coreaudio_run_out");
488 return decr;
489 }
490
491 /* callback to feed audiooutput buffer */
audioOutDeviceIOProc(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * inInputData,const AudioTimeStamp * inInputTime,AudioBufferList * outOutputData,const AudioTimeStamp * inOutputTime,void * hwptr)492 static OSStatus audioOutDeviceIOProc(
493 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;
506 struct st_sample *src;
507 #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;
551 core->pos = rpos;
552
553 coreaudio_voice_unlock (core, "audioDeviceIOProc");
554 return 0;
555 }
556
coreaudio_write(SWVoiceOut * sw,void * buf,int len)557 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
558 {
559 return audio_pcm_sw_write (sw, buf, len);
560 }
561
coreaudio_init_out(HWVoiceOut * hw,struct audsettings * as)562 static int coreaudio_init_out (HWVoiceOut *hw, struct audsettings *as)
563 {
564 coreaudioVoice* core = CORE_OUT(hw);
565 int err;
566
567 audio_pcm_init_info (&hw->info, as);
568
569 err = coreaudio_voice_init (core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0);
570 if (err < 0)
571 return err;
572
573 hw->samples = core->bufferFrameSize * conf.out_nbuffers;
574 return 0;
575 }
576
coreaudio_fini_out(HWVoiceOut * hw)577 static void coreaudio_fini_out (HWVoiceOut *hw)
578 {
579 coreaudioVoice *core = CORE_OUT(hw);
580
581 coreaudio_voice_fini (core);
582 }
583
584 static int
coreaudio_ctl_out(HWVoiceOut * hw,int cmd,...)585 coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
586 {
587 coreaudioVoice *core = CORE_OUT(hw);
588
589 return coreaudio_voice_ctl (core, cmd);
590 }
591
592 /***************************************************************************************/
593 /***************************************************************************************/
594 /*** ***/
595 /*** I N P U T V O I C E ***/
596 /*** ***/
597 /***************************************************************************************/
598 /***************************************************************************************/
599
600
601
602 typedef struct coreaudioVoiceIn {
603 HWVoiceIn hw;
604 coreaudioVoice core[1];
605 } coreaudioVoiceIn;
606
607 #define CORE_IN(hw) ((coreaudioVoiceIn *) (hw))->core
608
609
coreaudio_run_in(HWVoiceIn * hw,int live)610 static int coreaudio_run_in (HWVoiceIn *hw, int live)
611 {
612 int decr;
613
614 coreaudioVoice *core = CORE_IN(hw);
615
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 */
audioInDeviceIOProc(AudioDeviceID inDevice,const AudioTimeStamp * inNow,const AudioBufferList * inInputData,const AudioTimeStamp * inInputTime,AudioBufferList * outOutputData,const AudioTimeStamp * inOutputTime,void * hwptr)630 static OSStatus audioInDeviceIOProc(
631 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;
644 struct st_sample *dst;
645 #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
699 static int
coreaudio_read(SWVoiceIn * sw,void * buf,int len)700 coreaudio_read (SWVoiceIn *sw, void *buf, int len)
701 {
702 int result = audio_pcm_sw_read (sw, buf, len);
703 D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result);
704 return result;
705 }
706
707 static int
coreaudio_init_in(HWVoiceIn * hw,struct audsettings * as)708 coreaudio_init_in (HWVoiceIn *hw, struct audsettings *as)
709 {
710 coreaudioVoice* core = CORE_IN(hw);
711 int err;
712
713 audio_pcm_init_info (&hw->info, as);
714
715 err = coreaudio_voice_init (core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1);
716 if (err < 0) {
717 return err;
718 }
719
720 hw->samples = core->bufferFrameSize * conf.in_nbuffers;
721 return 0;
722 }
723
724 static void
coreaudio_fini_in(HWVoiceIn * hw)725 coreaudio_fini_in (HWVoiceIn *hw)
726 {
727
728 coreaudioVoice* core = CORE_IN(hw);
729
730 coreaudio_voice_fini(core);
731 }
732
733 static int
coreaudio_ctl_in(HWVoiceIn * hw,int cmd,...)734 coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
735 {
736 coreaudioVoice* core = CORE_IN(hw);
737
738 return coreaudio_voice_ctl(core, cmd);
739 }
740
coreaudio_audio_init(void)741 static void *coreaudio_audio_init (void)
742 {
743 atexit(coreaudio_atexit);
744 return &coreaudio_audio_init;
745 }
746
coreaudio_audio_fini(void * opaque)747 static void coreaudio_audio_fini (void *opaque)
748 {
749 (void) opaque;
750 }
751
752 static struct audio_option coreaudio_options[] = {
753 {
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 */ }
778 };
779
780 static struct audio_pcm_ops coreaudio_pcm_ops = {
781 .init_out = coreaudio_init_out,
782 .fini_out = coreaudio_fini_out,
783 .run_out = coreaudio_run_out,
784 .write = coreaudio_write,
785 .ctl_out = coreaudio_ctl_out,
786
787 .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
792 };
793
794 struct audio_driver coreaudio_audio_driver = {
795 .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),
806 };
807