• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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