Home | History | Annotate | Download | only in audio
      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 
     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 
    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 
    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
    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 
    190 static void coreaudio_atexit (void)
    191 {
    192     conf.isAtexit = 1;
    193 }
    194 
    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
    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
    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
    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
    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 
    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 */
    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 
    557 static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
    558 {
    559     return audio_pcm_sw_write (sw, buf, len);
    560 }
    561 
    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 
    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
    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 
    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 */
    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
    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
    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
    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
    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 
    741 static void *coreaudio_audio_init (void)
    742 {
    743     atexit(coreaudio_atexit);
    744     return &coreaudio_audio_init;
    745 }
    746 
    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