• 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 "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