Annotation of qemu/audio/alsaaudio.c, revision 1.1.1.10

1.1       root        1: /*
                      2:  * QEMU ALSA audio driver
                      3:  *
                      4:  * Copyright (c) 2005 Vassili Karpov (malc)
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include <alsa/asoundlib.h>
1.1.1.3   root       25: #include "qemu-common.h"
1.1.1.6   root       26: #include "qemu-char.h"
1.1.1.3   root       27: #include "audio.h"
1.1       root       28: 
1.1.1.5   root       29: #if QEMU_GNUC_PREREQ(4, 3)
                     30: #pragma GCC diagnostic ignored "-Waddress"
                     31: #endif
                     32: 
1.1       root       33: #define AUDIO_CAP "alsa"
                     34: #include "audio_int.h"
                     35: 
1.1.1.6   root       36: struct pollhlp {
                     37:     snd_pcm_t *handle;
                     38:     struct pollfd *pfds;
                     39:     int count;
                     40:     int mask;
                     41: };
                     42: 
1.1       root       43: typedef struct ALSAVoiceOut {
                     44:     HWVoiceOut hw;
1.1.1.6   root       45:     int wpos;
                     46:     int pending;
1.1       root       47:     void *pcm_buf;
                     48:     snd_pcm_t *handle;
1.1.1.6   root       49:     struct pollhlp pollhlp;
1.1       root       50: } ALSAVoiceOut;
                     51: 
                     52: typedef struct ALSAVoiceIn {
                     53:     HWVoiceIn hw;
                     54:     snd_pcm_t *handle;
                     55:     void *pcm_buf;
1.1.1.6   root       56:     struct pollhlp pollhlp;
1.1       root       57: } ALSAVoiceIn;
                     58: 
                     59: static struct {
                     60:     int size_in_usec_in;
                     61:     int size_in_usec_out;
                     62:     const char *pcm_name_in;
                     63:     const char *pcm_name_out;
                     64:     unsigned int buffer_size_in;
                     65:     unsigned int period_size_in;
                     66:     unsigned int buffer_size_out;
                     67:     unsigned int period_size_out;
                     68:     unsigned int threshold;
                     69: 
1.1.1.3   root       70:     int buffer_size_in_overridden;
                     71:     int period_size_in_overridden;
1.1       root       72: 
1.1.1.3   root       73:     int buffer_size_out_overridden;
                     74:     int period_size_out_overridden;
1.1       root       75:     int verbose;
                     76: } conf = {
1.1.1.6   root       77:     .buffer_size_out = 4096,
                     78:     .period_size_out = 1024,
1.1.1.2   root       79:     .pcm_name_out = "default",
                     80:     .pcm_name_in = "default",
1.1       root       81: };
                     82: 
                     83: struct alsa_params_req {
1.1.1.4   root       84:     int freq;
                     85:     snd_pcm_format_t fmt;
                     86:     int nchannels;
                     87:     int size_in_usec;
                     88:     int override_mask;
1.1       root       89:     unsigned int buffer_size;
                     90:     unsigned int period_size;
                     91: };
                     92: 
                     93: struct alsa_params_obt {
                     94:     int freq;
                     95:     audfmt_e fmt;
1.1.1.4   root       96:     int endianness;
1.1       root       97:     int nchannels;
                     98:     snd_pcm_uframes_t samples;
                     99: };
                    100: 
                    101: static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
                    102: {
                    103:     va_list ap;
                    104: 
                    105:     va_start (ap, fmt);
                    106:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    107:     va_end (ap);
                    108: 
                    109:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
                    110: }
                    111: 
                    112: static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
                    113:     int err,
                    114:     const char *typ,
                    115:     const char *fmt,
                    116:     ...
                    117:     )
                    118: {
                    119:     va_list ap;
                    120: 
                    121:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
                    122: 
                    123:     va_start (ap, fmt);
                    124:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    125:     va_end (ap);
                    126: 
                    127:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
                    128: }
                    129: 
1.1.1.6   root      130: static void alsa_fini_poll (struct pollhlp *hlp)
                    131: {
                    132:     int i;
                    133:     struct pollfd *pfds = hlp->pfds;
                    134: 
                    135:     if (pfds) {
                    136:         for (i = 0; i < hlp->count; ++i) {
                    137:             qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
                    138:         }
1.1.1.10! root      139:         g_free (pfds);
1.1.1.6   root      140:     }
                    141:     hlp->pfds = NULL;
                    142:     hlp->count = 0;
                    143:     hlp->handle = NULL;
                    144: }
                    145: 
                    146: static void alsa_anal_close1 (snd_pcm_t **handlep)
1.1       root      147: {
                    148:     int err = snd_pcm_close (*handlep);
                    149:     if (err) {
                    150:         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
                    151:     }
                    152:     *handlep = NULL;
                    153: }
                    154: 
1.1.1.6   root      155: static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
                    156: {
                    157:     alsa_fini_poll (hlp);
                    158:     alsa_anal_close1 (handlep);
                    159: }
                    160: 
                    161: static int alsa_recover (snd_pcm_t *handle)
                    162: {
                    163:     int err = snd_pcm_prepare (handle);
                    164:     if (err < 0) {
                    165:         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
                    166:         return -1;
                    167:     }
                    168:     return 0;
                    169: }
                    170: 
                    171: static int alsa_resume (snd_pcm_t *handle)
                    172: {
                    173:     int err = snd_pcm_resume (handle);
                    174:     if (err < 0) {
                    175:         alsa_logerr (err, "Failed to resume handle %p\n", handle);
                    176:         return -1;
                    177:     }
                    178:     return 0;
                    179: }
                    180: 
                    181: static void alsa_poll_handler (void *opaque)
                    182: {
                    183:     int err, count;
                    184:     snd_pcm_state_t state;
                    185:     struct pollhlp *hlp = opaque;
                    186:     unsigned short revents;
                    187: 
                    188:     count = poll (hlp->pfds, hlp->count, 0);
                    189:     if (count < 0) {
                    190:         dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
                    191:         return;
                    192:     }
                    193: 
                    194:     if (!count) {
                    195:         return;
                    196:     }
                    197: 
                    198:     /* XXX: ALSA example uses initial count, not the one returned by
                    199:        poll, correct? */
                    200:     err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
                    201:                                             hlp->count, &revents);
                    202:     if (err < 0) {
                    203:         alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
                    204:         return;
                    205:     }
                    206: 
                    207:     if (!(revents & hlp->mask)) {
                    208:         if (conf.verbose) {
                    209:             dolog ("revents = %d\n", revents);
                    210:         }
                    211:         return;
                    212:     }
                    213: 
                    214:     state = snd_pcm_state (hlp->handle);
                    215:     switch (state) {
1.1.1.7   root      216:     case SND_PCM_STATE_SETUP:
                    217:         alsa_recover (hlp->handle);
                    218:         break;
                    219: 
1.1.1.6   root      220:     case SND_PCM_STATE_XRUN:
                    221:         alsa_recover (hlp->handle);
                    222:         break;
                    223: 
                    224:     case SND_PCM_STATE_SUSPENDED:
                    225:         alsa_resume (hlp->handle);
                    226:         break;
                    227: 
                    228:     case SND_PCM_STATE_PREPARED:
                    229:         audio_run ("alsa run (prepared)");
                    230:         break;
                    231: 
                    232:     case SND_PCM_STATE_RUNNING:
                    233:         audio_run ("alsa run (running)");
                    234:         break;
                    235: 
                    236:     default:
                    237:         dolog ("Unexpected state %d\n", state);
                    238:     }
                    239: }
                    240: 
                    241: static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
                    242: {
                    243:     int i, count, err;
                    244:     struct pollfd *pfds;
                    245: 
                    246:     count = snd_pcm_poll_descriptors_count (handle);
                    247:     if (count <= 0) {
                    248:         dolog ("Could not initialize poll mode\n"
                    249:                "Invalid number of poll descriptors %d\n", count);
                    250:         return -1;
                    251:     }
                    252: 
                    253:     pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
                    254:     if (!pfds) {
                    255:         dolog ("Could not initialize poll mode\n");
                    256:         return -1;
                    257:     }
                    258: 
                    259:     err = snd_pcm_poll_descriptors (handle, pfds, count);
                    260:     if (err < 0) {
                    261:         alsa_logerr (err, "Could not initialize poll mode\n"
                    262:                      "Could not obtain poll descriptors\n");
1.1.1.10! root      263:         g_free (pfds);
1.1.1.6   root      264:         return -1;
                    265:     }
                    266: 
                    267:     for (i = 0; i < count; ++i) {
                    268:         if (pfds[i].events & POLLIN) {
                    269:             err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
                    270:                                        NULL, hlp);
                    271:         }
                    272:         if (pfds[i].events & POLLOUT) {
                    273:             if (conf.verbose) {
                    274:                 dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
                    275:             }
                    276:             err = qemu_set_fd_handler (pfds[i].fd, NULL,
                    277:                                        alsa_poll_handler, hlp);
                    278:         }
                    279:         if (conf.verbose) {
                    280:             dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
                    281:                    pfds[i].events, i, pfds[i].fd, err);
                    282:         }
                    283: 
                    284:         if (err) {
                    285:             dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
                    286:                    pfds[i].events, i, pfds[i].fd, err);
                    287: 
                    288:             while (i--) {
                    289:                 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
                    290:             }
1.1.1.10! root      291:             g_free (pfds);
1.1.1.6   root      292:             return -1;
                    293:         }
                    294:     }
                    295:     hlp->pfds = pfds;
                    296:     hlp->count = count;
                    297:     hlp->handle = handle;
                    298:     hlp->mask = mask;
                    299:     return 0;
                    300: }
                    301: 
                    302: static int alsa_poll_out (HWVoiceOut *hw)
                    303: {
                    304:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    305: 
                    306:     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
                    307: }
                    308: 
                    309: static int alsa_poll_in (HWVoiceIn *hw)
                    310: {
                    311:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    312: 
                    313:     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
                    314: }
                    315: 
1.1       root      316: static int alsa_write (SWVoiceOut *sw, void *buf, int len)
                    317: {
                    318:     return audio_pcm_sw_write (sw, buf, len);
                    319: }
                    320: 
1.1.1.9   root      321: static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
1.1       root      322: {
                    323:     switch (fmt) {
                    324:     case AUD_FMT_S8:
                    325:         return SND_PCM_FORMAT_S8;
                    326: 
                    327:     case AUD_FMT_U8:
                    328:         return SND_PCM_FORMAT_U8;
                    329: 
                    330:     case AUD_FMT_S16:
1.1.1.9   root      331:         if (endianness) {
                    332:             return SND_PCM_FORMAT_S16_BE;
                    333:         }
                    334:         else {
                    335:             return SND_PCM_FORMAT_S16_LE;
                    336:         }
1.1       root      337: 
                    338:     case AUD_FMT_U16:
1.1.1.9   root      339:         if (endianness) {
                    340:             return SND_PCM_FORMAT_U16_BE;
                    341:         }
                    342:         else {
                    343:             return SND_PCM_FORMAT_U16_LE;
                    344:         }
1.1       root      345: 
1.1.1.3   root      346:     case AUD_FMT_S32:
1.1.1.9   root      347:         if (endianness) {
                    348:             return SND_PCM_FORMAT_S32_BE;
                    349:         }
                    350:         else {
                    351:             return SND_PCM_FORMAT_S32_LE;
                    352:         }
1.1.1.3   root      353: 
                    354:     case AUD_FMT_U32:
1.1.1.9   root      355:         if (endianness) {
                    356:             return SND_PCM_FORMAT_U32_BE;
                    357:         }
                    358:         else {
                    359:             return SND_PCM_FORMAT_U32_LE;
                    360:         }
1.1.1.3   root      361: 
1.1       root      362:     default:
                    363:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    364: #ifdef DEBUG_AUDIO
                    365:         abort ();
                    366: #endif
                    367:         return SND_PCM_FORMAT_U8;
                    368:     }
                    369: }
                    370: 
1.1.1.4   root      371: static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
                    372:                            int *endianness)
1.1       root      373: {
                    374:     switch (alsafmt) {
                    375:     case SND_PCM_FORMAT_S8:
                    376:         *endianness = 0;
                    377:         *fmt = AUD_FMT_S8;
                    378:         break;
                    379: 
                    380:     case SND_PCM_FORMAT_U8:
                    381:         *endianness = 0;
                    382:         *fmt = AUD_FMT_U8;
                    383:         break;
                    384: 
                    385:     case SND_PCM_FORMAT_S16_LE:
                    386:         *endianness = 0;
                    387:         *fmt = AUD_FMT_S16;
                    388:         break;
                    389: 
                    390:     case SND_PCM_FORMAT_U16_LE:
                    391:         *endianness = 0;
                    392:         *fmt = AUD_FMT_U16;
                    393:         break;
                    394: 
                    395:     case SND_PCM_FORMAT_S16_BE:
                    396:         *endianness = 1;
                    397:         *fmt = AUD_FMT_S16;
                    398:         break;
                    399: 
                    400:     case SND_PCM_FORMAT_U16_BE:
                    401:         *endianness = 1;
                    402:         *fmt = AUD_FMT_U16;
                    403:         break;
                    404: 
1.1.1.3   root      405:     case SND_PCM_FORMAT_S32_LE:
                    406:         *endianness = 0;
                    407:         *fmt = AUD_FMT_S32;
                    408:         break;
                    409: 
                    410:     case SND_PCM_FORMAT_U32_LE:
                    411:         *endianness = 0;
                    412:         *fmt = AUD_FMT_U32;
                    413:         break;
                    414: 
                    415:     case SND_PCM_FORMAT_S32_BE:
                    416:         *endianness = 1;
                    417:         *fmt = AUD_FMT_S32;
                    418:         break;
                    419: 
                    420:     case SND_PCM_FORMAT_U32_BE:
                    421:         *endianness = 1;
                    422:         *fmt = AUD_FMT_U32;
                    423:         break;
                    424: 
1.1       root      425:     default:
                    426:         dolog ("Unrecognized audio format %d\n", alsafmt);
                    427:         return -1;
                    428:     }
                    429: 
                    430:     return 0;
                    431: }
                    432: 
                    433: static void alsa_dump_info (struct alsa_params_req *req,
1.1.1.8   root      434:                             struct alsa_params_obt *obt,
                    435:                             snd_pcm_format_t obtfmt)
1.1       root      436: {
                    437:     dolog ("parameter | requested value | obtained value\n");
1.1.1.8   root      438:     dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
1.1       root      439:     dolog ("channels  |      %10d |     %10d\n",
                    440:            req->nchannels, obt->nchannels);
                    441:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
                    442:     dolog ("============================================\n");
                    443:     dolog ("requested: buffer size %d period size %d\n",
                    444:            req->buffer_size, req->period_size);
                    445:     dolog ("obtained: samples %ld\n", obt->samples);
                    446: }
                    447: 
                    448: static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
                    449: {
                    450:     int err;
                    451:     snd_pcm_sw_params_t *sw_params;
                    452: 
                    453:     snd_pcm_sw_params_alloca (&sw_params);
                    454: 
                    455:     err = snd_pcm_sw_params_current (handle, sw_params);
                    456:     if (err < 0) {
                    457:         dolog ("Could not fully initialize DAC\n");
                    458:         alsa_logerr (err, "Failed to get current software parameters\n");
                    459:         return;
                    460:     }
                    461: 
                    462:     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
                    463:     if (err < 0) {
                    464:         dolog ("Could not fully initialize DAC\n");
                    465:         alsa_logerr (err, "Failed to set software threshold to %ld\n",
                    466:                      threshold);
                    467:         return;
                    468:     }
                    469: 
                    470:     err = snd_pcm_sw_params (handle, sw_params);
                    471:     if (err < 0) {
                    472:         dolog ("Could not fully initialize DAC\n");
                    473:         alsa_logerr (err, "Failed to set software parameters\n");
                    474:         return;
                    475:     }
                    476: }
                    477: 
                    478: static int alsa_open (int in, struct alsa_params_req *req,
                    479:                       struct alsa_params_obt *obt, snd_pcm_t **handlep)
                    480: {
                    481:     snd_pcm_t *handle;
                    482:     snd_pcm_hw_params_t *hw_params;
1.1.1.3   root      483:     int err;
1.1.1.4   root      484:     int size_in_usec;
1.1.1.3   root      485:     unsigned int freq, nchannels;
1.1       root      486:     const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
                    487:     snd_pcm_uframes_t obt_buffer_size;
                    488:     const char *typ = in ? "ADC" : "DAC";
1.1.1.4   root      489:     snd_pcm_format_t obtfmt;
1.1       root      490: 
                    491:     freq = req->freq;
                    492:     nchannels = req->nchannels;
1.1.1.4   root      493:     size_in_usec = req->size_in_usec;
1.1       root      494: 
                    495:     snd_pcm_hw_params_alloca (&hw_params);
                    496: 
                    497:     err = snd_pcm_open (
                    498:         &handle,
                    499:         pcm_name,
                    500:         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
                    501:         SND_PCM_NONBLOCK
                    502:         );
                    503:     if (err < 0) {
                    504:         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
                    505:         return -1;
                    506:     }
                    507: 
                    508:     err = snd_pcm_hw_params_any (handle, hw_params);
                    509:     if (err < 0) {
                    510:         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
                    511:         goto err;
                    512:     }
                    513: 
                    514:     err = snd_pcm_hw_params_set_access (
                    515:         handle,
                    516:         hw_params,
                    517:         SND_PCM_ACCESS_RW_INTERLEAVED
                    518:         );
                    519:     if (err < 0) {
                    520:         alsa_logerr2 (err, typ, "Failed to set access type\n");
                    521:         goto err;
                    522:     }
                    523: 
                    524:     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
1.1.1.4   root      525:     if (err < 0 && conf.verbose) {
1.1       root      526:         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
                    527:     }
                    528: 
                    529:     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
                    530:     if (err < 0) {
                    531:         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
                    532:         goto err;
                    533:     }
                    534: 
                    535:     err = snd_pcm_hw_params_set_channels_near (
                    536:         handle,
                    537:         hw_params,
                    538:         &nchannels
                    539:         );
                    540:     if (err < 0) {
                    541:         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
                    542:                       req->nchannels);
                    543:         goto err;
                    544:     }
                    545: 
                    546:     if (nchannels != 1 && nchannels != 2) {
                    547:         alsa_logerr2 (err, typ,
                    548:                       "Can not handle obtained number of channels %d\n",
                    549:                       nchannels);
                    550:         goto err;
                    551:     }
                    552: 
1.1.1.4   root      553:     if (req->buffer_size) {
                    554:         unsigned long obt;
1.1       root      555: 
1.1.1.4   root      556:         if (size_in_usec) {
                    557:             int dir = 0;
                    558:             unsigned int btime = req->buffer_size;
1.1       root      559: 
                    560:             err = snd_pcm_hw_params_set_buffer_time_near (
                    561:                 handle,
                    562:                 hw_params,
1.1.1.4   root      563:                 &btime,
                    564:                 &dir
1.1       root      565:                 );
1.1.1.4   root      566:             obt = btime;
1.1       root      567:         }
                    568:         else {
1.1.1.4   root      569:             snd_pcm_uframes_t bsize = req->buffer_size;
1.1       root      570: 
1.1.1.4   root      571:             err = snd_pcm_hw_params_set_buffer_size_near (
                    572:                 handle,
                    573:                 hw_params,
                    574:                 &bsize
                    575:                 );
                    576:             obt = bsize;
                    577:         }
                    578:         if (err < 0) {
                    579:             alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
                    580:                           size_in_usec ? "time" : "size", req->buffer_size);
                    581:             goto err;
                    582:         }
1.1       root      583: 
1.1.1.4   root      584:         if ((req->override_mask & 2) && (obt - req->buffer_size))
                    585:             dolog ("Requested buffer %s %u was rejected, using %lu\n",
                    586:                    size_in_usec ? "time" : "size", req->buffer_size, obt);
                    587:     }
                    588: 
                    589:     if (req->period_size) {
                    590:         unsigned long obt;
                    591: 
                    592:         if (size_in_usec) {
                    593:             int dir = 0;
                    594:             unsigned int ptime = req->period_size;
1.1       root      595: 
1.1.1.4   root      596:             err = snd_pcm_hw_params_set_period_time_near (
                    597:                 handle,
1.1       root      598:                 hw_params,
1.1.1.4   root      599:                 &ptime,
                    600:                 &dir
1.1       root      601:                 );
1.1.1.4   root      602:             obt = ptime;
                    603:         }
                    604:         else {
                    605:             int dir = 0;
                    606:             snd_pcm_uframes_t psize = req->period_size;
1.1       root      607: 
1.1.1.4   root      608:             err = snd_pcm_hw_params_set_period_size_near (
1.1       root      609:                 handle,
                    610:                 hw_params,
1.1.1.4   root      611:                 &psize,
                    612:                 &dir
1.1       root      613:                 );
1.1.1.4   root      614:             obt = psize;
1.1       root      615:         }
1.1.1.4   root      616: 
                    617:         if (err < 0) {
                    618:             alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
                    619:                           size_in_usec ? "time" : "size", req->period_size);
                    620:             goto err;
                    621:         }
                    622: 
1.1.1.6   root      623:         if (((req->override_mask & 1) && (obt - req->period_size)))
1.1.1.4   root      624:             dolog ("Requested period %s %u was rejected, using %lu\n",
                    625:                    size_in_usec ? "time" : "size", req->period_size, obt);
1.1       root      626:     }
                    627: 
                    628:     err = snd_pcm_hw_params (handle, hw_params);
                    629:     if (err < 0) {
                    630:         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
                    631:         goto err;
                    632:     }
                    633: 
                    634:     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
                    635:     if (err < 0) {
                    636:         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
                    637:         goto err;
                    638:     }
                    639: 
1.1.1.4   root      640:     err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
                    641:     if (err < 0) {
                    642:         alsa_logerr2 (err, typ, "Failed to get format\n");
                    643:         goto err;
                    644:     }
                    645: 
                    646:     if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
                    647:         dolog ("Invalid format was returned %d\n", obtfmt);
                    648:         goto err;
                    649:     }
                    650: 
1.1       root      651:     err = snd_pcm_prepare (handle);
                    652:     if (err < 0) {
                    653:         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
                    654:         goto err;
                    655:     }
                    656: 
                    657:     if (!in && conf.threshold) {
                    658:         snd_pcm_uframes_t threshold;
                    659:         int bytes_per_sec;
                    660: 
1.1.1.4   root      661:         bytes_per_sec = freq << (nchannels == 2);
                    662: 
                    663:         switch (obt->fmt) {
                    664:         case AUD_FMT_S8:
                    665:         case AUD_FMT_U8:
                    666:             break;
                    667: 
                    668:         case AUD_FMT_S16:
                    669:         case AUD_FMT_U16:
                    670:             bytes_per_sec <<= 1;
                    671:             break;
                    672: 
                    673:         case AUD_FMT_S32:
                    674:         case AUD_FMT_U32:
                    675:             bytes_per_sec <<= 2;
                    676:             break;
                    677:         }
1.1       root      678: 
                    679:         threshold = (conf.threshold * bytes_per_sec) / 1000;
                    680:         alsa_set_threshold (handle, threshold);
                    681:     }
                    682: 
                    683:     obt->nchannels = nchannels;
                    684:     obt->freq = freq;
                    685:     obt->samples = obt_buffer_size;
1.1.1.4   root      686: 
1.1       root      687:     *handlep = handle;
                    688: 
1.1.1.4   root      689:     if (conf.verbose &&
1.1.1.8   root      690:         (obtfmt != req->fmt ||
1.1.1.4   root      691:          obt->nchannels != req->nchannels ||
                    692:          obt->freq != req->freq)) {
1.1.1.7   root      693:         dolog ("Audio parameters for %s\n", typ);
1.1.1.8   root      694:         alsa_dump_info (req, obt, obtfmt);
1.1       root      695:     }
                    696: 
                    697: #ifdef DEBUG
1.1.1.8   root      698:     alsa_dump_info (req, obt, obtfmt);
1.1       root      699: #endif
                    700:     return 0;
                    701: 
                    702:  err:
1.1.1.6   root      703:     alsa_anal_close1 (&handle);
1.1       root      704:     return -1;
                    705: }
                    706: 
                    707: static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
                    708: {
                    709:     snd_pcm_sframes_t avail;
                    710: 
                    711:     avail = snd_pcm_avail_update (handle);
                    712:     if (avail < 0) {
                    713:         if (avail == -EPIPE) {
                    714:             if (!alsa_recover (handle)) {
                    715:                 avail = snd_pcm_avail_update (handle);
                    716:             }
                    717:         }
                    718: 
                    719:         if (avail < 0) {
                    720:             alsa_logerr (avail,
                    721:                          "Could not obtain number of available frames\n");
                    722:             return -1;
                    723:         }
                    724:     }
                    725: 
                    726:     return avail;
                    727: }
                    728: 
1.1.1.6   root      729: static void alsa_write_pending (ALSAVoiceOut *alsa)
1.1       root      730: {
1.1.1.6   root      731:     HWVoiceOut *hw = &alsa->hw;
1.1       root      732: 
1.1.1.6   root      733:     while (alsa->pending) {
                    734:         int left_till_end_samples = hw->samples - alsa->wpos;
                    735:         int len = audio_MIN (alsa->pending, left_till_end_samples);
                    736:         char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
1.1       root      737: 
                    738:         while (len) {
1.1.1.6   root      739:             snd_pcm_sframes_t written;
                    740: 
                    741:             written = snd_pcm_writei (alsa->handle, src, len);
1.1       root      742: 
                    743:             if (written <= 0) {
                    744:                 switch (written) {
                    745:                 case 0:
                    746:                     if (conf.verbose) {
                    747:                         dolog ("Failed to write %d frames (wrote zero)\n", len);
                    748:                     }
1.1.1.6   root      749:                     return;
1.1       root      750: 
                    751:                 case -EPIPE:
                    752:                     if (alsa_recover (alsa->handle)) {
                    753:                         alsa_logerr (written, "Failed to write %d frames\n",
                    754:                                      len);
1.1.1.6   root      755:                         return;
1.1       root      756:                     }
                    757:                     if (conf.verbose) {
                    758:                         dolog ("Recovering from playback xrun\n");
                    759:                     }
                    760:                     continue;
                    761: 
1.1.1.6   root      762:                 case -ESTRPIPE:
                    763:                     /* stream is suspended and waiting for an
                    764:                        application recovery */
                    765:                     if (alsa_resume (alsa->handle)) {
                    766:                         alsa_logerr (written, "Failed to write %d frames\n",
                    767:                                      len);
                    768:                         return;
                    769:                     }
                    770:                     if (conf.verbose) {
                    771:                         dolog ("Resuming suspended output stream\n");
                    772:                     }
                    773:                     continue;
                    774: 
1.1       root      775:                 case -EAGAIN:
1.1.1.6   root      776:                     return;
1.1       root      777: 
                    778:                 default:
1.1.1.6   root      779:                     alsa_logerr (written, "Failed to write %d frames from %p\n",
                    780:                                  len, src);
                    781:                     return;
1.1       root      782:                 }
                    783:             }
                    784: 
1.1.1.6   root      785:             alsa->wpos = (alsa->wpos + written) % hw->samples;
                    786:             alsa->pending -= written;
1.1       root      787:             len -= written;
                    788:         }
                    789:     }
1.1.1.6   root      790: }
1.1       root      791: 
1.1.1.6   root      792: static int alsa_run_out (HWVoiceOut *hw, int live)
                    793: {
                    794:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    795:     int decr;
                    796:     snd_pcm_sframes_t avail;
                    797: 
                    798:     avail = alsa_get_avail (alsa->handle);
                    799:     if (avail < 0) {
                    800:         dolog ("Could not get number of available playback frames\n");
                    801:         return 0;
                    802:     }
                    803: 
                    804:     decr = audio_MIN (live, avail);
                    805:     decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
                    806:     alsa->pending += decr;
                    807:     alsa_write_pending (alsa);
1.1       root      808:     return decr;
                    809: }
                    810: 
                    811: static void alsa_fini_out (HWVoiceOut *hw)
                    812: {
                    813:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    814: 
                    815:     ldebug ("alsa_fini\n");
1.1.1.6   root      816:     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1.1       root      817: 
                    818:     if (alsa->pcm_buf) {
1.1.1.10! root      819:         g_free (alsa->pcm_buf);
1.1       root      820:         alsa->pcm_buf = NULL;
                    821:     }
                    822: }
                    823: 
1.1.1.4   root      824: static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1       root      825: {
                    826:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    827:     struct alsa_params_req req;
                    828:     struct alsa_params_obt obt;
                    829:     snd_pcm_t *handle;
1.1.1.4   root      830:     struct audsettings obt_as;
1.1       root      831: 
1.1.1.9   root      832:     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
1.1       root      833:     req.freq = as->freq;
                    834:     req.nchannels = as->nchannels;
                    835:     req.period_size = conf.period_size_out;
                    836:     req.buffer_size = conf.buffer_size_out;
1.1.1.4   root      837:     req.size_in_usec = conf.size_in_usec_out;
1.1.1.5   root      838:     req.override_mask =
                    839:         (conf.period_size_out_overridden ? 1 : 0) |
                    840:         (conf.buffer_size_out_overridden ? 2 : 0);
1.1       root      841: 
                    842:     if (alsa_open (0, &req, &obt, &handle)) {
                    843:         return -1;
                    844:     }
                    845: 
                    846:     obt_as.freq = obt.freq;
                    847:     obt_as.nchannels = obt.nchannels;
1.1.1.4   root      848:     obt_as.fmt = obt.fmt;
                    849:     obt_as.endianness = obt.endianness;
1.1       root      850: 
1.1.1.2   root      851:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      852:     hw->samples = obt.samples;
                    853: 
                    854:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
                    855:     if (!alsa->pcm_buf) {
                    856:         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    857:                hw->samples, 1 << hw->info.shift);
1.1.1.6   root      858:         alsa_anal_close1 (&handle);
1.1       root      859:         return -1;
                    860:     }
                    861: 
                    862:     alsa->handle = handle;
                    863:     return 0;
                    864: }
                    865: 
1.1.1.9   root      866: #define VOICE_CTL_PAUSE 0
                    867: #define VOICE_CTL_PREPARE 1
                    868: #define VOICE_CTL_START 2
                    869: 
                    870: static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
1.1       root      871: {
                    872:     int err;
                    873: 
1.1.1.9   root      874:     if (ctl == VOICE_CTL_PAUSE) {
1.1       root      875:         err = snd_pcm_drop (handle);
                    876:         if (err < 0) {
                    877:             alsa_logerr (err, "Could not stop %s\n", typ);
                    878:             return -1;
                    879:         }
                    880:     }
                    881:     else {
                    882:         err = snd_pcm_prepare (handle);
                    883:         if (err < 0) {
                    884:             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
                    885:             return -1;
                    886:         }
1.1.1.9   root      887:         if (ctl == VOICE_CTL_START) {
                    888:             err = snd_pcm_start(handle);
                    889:             if (err < 0) {
                    890:                 alsa_logerr (err, "Could not start handle for %s\n", typ);
                    891:                 return -1;
                    892:             }
                    893:         }
1.1       root      894:     }
                    895: 
                    896:     return 0;
                    897: }
                    898: 
                    899: static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    900: {
                    901:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    902: 
                    903:     switch (cmd) {
                    904:     case VOICE_ENABLE:
1.1.1.6   root      905:         {
                    906:             va_list ap;
                    907:             int poll_mode;
                    908: 
                    909:             va_start (ap, cmd);
                    910:             poll_mode = va_arg (ap, int);
                    911:             va_end (ap);
                    912: 
                    913:             ldebug ("enabling voice\n");
                    914:             if (poll_mode && alsa_poll_out (hw)) {
                    915:                 poll_mode = 0;
                    916:             }
                    917:             hw->poll_mode = poll_mode;
1.1.1.9   root      918:             return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
1.1.1.6   root      919:         }
1.1       root      920: 
                    921:     case VOICE_DISABLE:
                    922:         ldebug ("disabling voice\n");
1.1.1.9   root      923:         if (hw->poll_mode) {
                    924:             hw->poll_mode = 0;
                    925:             alsa_fini_poll (&alsa->pollhlp);
                    926:         }
                    927:         return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
1.1       root      928:     }
                    929: 
                    930:     return -1;
                    931: }
                    932: 
1.1.1.4   root      933: static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1       root      934: {
                    935:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    936:     struct alsa_params_req req;
                    937:     struct alsa_params_obt obt;
                    938:     snd_pcm_t *handle;
1.1.1.4   root      939:     struct audsettings obt_as;
1.1       root      940: 
1.1.1.9   root      941:     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
1.1       root      942:     req.freq = as->freq;
                    943:     req.nchannels = as->nchannels;
                    944:     req.period_size = conf.period_size_in;
                    945:     req.buffer_size = conf.buffer_size_in;
1.1.1.4   root      946:     req.size_in_usec = conf.size_in_usec_in;
1.1.1.5   root      947:     req.override_mask =
                    948:         (conf.period_size_in_overridden ? 1 : 0) |
                    949:         (conf.buffer_size_in_overridden ? 2 : 0);
1.1       root      950: 
                    951:     if (alsa_open (1, &req, &obt, &handle)) {
                    952:         return -1;
                    953:     }
                    954: 
                    955:     obt_as.freq = obt.freq;
                    956:     obt_as.nchannels = obt.nchannels;
1.1.1.4   root      957:     obt_as.fmt = obt.fmt;
                    958:     obt_as.endianness = obt.endianness;
1.1       root      959: 
1.1.1.2   root      960:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      961:     hw->samples = obt.samples;
                    962: 
                    963:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    964:     if (!alsa->pcm_buf) {
                    965:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    966:                hw->samples, 1 << hw->info.shift);
1.1.1.6   root      967:         alsa_anal_close1 (&handle);
1.1       root      968:         return -1;
                    969:     }
                    970: 
                    971:     alsa->handle = handle;
                    972:     return 0;
                    973: }
                    974: 
                    975: static void alsa_fini_in (HWVoiceIn *hw)
                    976: {
                    977:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    978: 
1.1.1.6   root      979:     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1.1       root      980: 
                    981:     if (alsa->pcm_buf) {
1.1.1.10! root      982:         g_free (alsa->pcm_buf);
1.1       root      983:         alsa->pcm_buf = NULL;
                    984:     }
                    985: }
                    986: 
                    987: static int alsa_run_in (HWVoiceIn *hw)
                    988: {
                    989:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    990:     int hwshift = hw->info.shift;
                    991:     int i;
                    992:     int live = audio_pcm_hw_get_live_in (hw);
                    993:     int dead = hw->samples - live;
                    994:     int decr;
                    995:     struct {
                    996:         int add;
                    997:         int len;
                    998:     } bufs[2] = {
1.1.1.6   root      999:         { .add = hw->wpos, .len = 0 },
                   1000:         { .add = 0,        .len = 0 }
1.1       root     1001:     };
                   1002:     snd_pcm_sframes_t avail;
                   1003:     snd_pcm_uframes_t read_samples = 0;
                   1004: 
                   1005:     if (!dead) {
                   1006:         return 0;
                   1007:     }
                   1008: 
                   1009:     avail = alsa_get_avail (alsa->handle);
                   1010:     if (avail < 0) {
                   1011:         dolog ("Could not get number of captured frames\n");
                   1012:         return 0;
                   1013:     }
                   1014: 
1.1.1.6   root     1015:     if (!avail) {
                   1016:         snd_pcm_state_t state;
                   1017: 
                   1018:         state = snd_pcm_state (alsa->handle);
                   1019:         switch (state) {
                   1020:         case SND_PCM_STATE_PREPARED:
                   1021:             avail = hw->samples;
                   1022:             break;
                   1023:         case SND_PCM_STATE_SUSPENDED:
                   1024:             /* stream is suspended and waiting for an application recovery */
                   1025:             if (alsa_resume (alsa->handle)) {
                   1026:                 dolog ("Failed to resume suspended input stream\n");
                   1027:                 return 0;
                   1028:             }
                   1029:             if (conf.verbose) {
                   1030:                 dolog ("Resuming suspended input stream\n");
                   1031:             }
                   1032:             break;
                   1033:         default:
                   1034:             if (conf.verbose) {
                   1035:                 dolog ("No frames available and ALSA state is %d\n", state);
                   1036:             }
                   1037:             return 0;
                   1038:         }
1.1       root     1039:     }
                   1040: 
                   1041:     decr = audio_MIN (dead, avail);
                   1042:     if (!decr) {
                   1043:         return 0;
                   1044:     }
                   1045: 
                   1046:     if (hw->wpos + decr > hw->samples) {
                   1047:         bufs[0].len = (hw->samples - hw->wpos);
                   1048:         bufs[1].len = (decr - (hw->samples - hw->wpos));
                   1049:     }
                   1050:     else {
                   1051:         bufs[0].len = decr;
                   1052:     }
                   1053: 
                   1054:     for (i = 0; i < 2; ++i) {
                   1055:         void *src;
1.1.1.4   root     1056:         struct st_sample *dst;
1.1       root     1057:         snd_pcm_sframes_t nread;
                   1058:         snd_pcm_uframes_t len;
                   1059: 
                   1060:         len = bufs[i].len;
                   1061: 
                   1062:         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
                   1063:         dst = hw->conv_buf + bufs[i].add;
                   1064: 
                   1065:         while (len) {
                   1066:             nread = snd_pcm_readi (alsa->handle, src, len);
                   1067: 
                   1068:             if (nread <= 0) {
                   1069:                 switch (nread) {
                   1070:                 case 0:
                   1071:                     if (conf.verbose) {
                   1072:                         dolog ("Failed to read %ld frames (read zero)\n", len);
                   1073:                     }
                   1074:                     goto exit;
                   1075: 
                   1076:                 case -EPIPE:
                   1077:                     if (alsa_recover (alsa->handle)) {
                   1078:                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
                   1079:                         goto exit;
                   1080:                     }
                   1081:                     if (conf.verbose) {
                   1082:                         dolog ("Recovering from capture xrun\n");
                   1083:                     }
                   1084:                     continue;
                   1085: 
                   1086:                 case -EAGAIN:
                   1087:                     goto exit;
                   1088: 
                   1089:                 default:
                   1090:                     alsa_logerr (
                   1091:                         nread,
                   1092:                         "Failed to read %ld frames from %p\n",
                   1093:                         len,
                   1094:                         src
                   1095:                         );
                   1096:                     goto exit;
                   1097:                 }
                   1098:             }
                   1099: 
1.1.1.9   root     1100:             hw->conv (dst, src, nread);
1.1       root     1101: 
                   1102:             src = advance (src, nread << hwshift);
                   1103:             dst += nread;
                   1104: 
                   1105:             read_samples += nread;
                   1106:             len -= nread;
                   1107:         }
                   1108:     }
                   1109: 
                   1110:  exit:
                   1111:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                   1112:     return read_samples;
                   1113: }
                   1114: 
                   1115: static int alsa_read (SWVoiceIn *sw, void *buf, int size)
                   1116: {
                   1117:     return audio_pcm_sw_read (sw, buf, size);
                   1118: }
                   1119: 
                   1120: static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
                   1121: {
                   1122:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                   1123: 
                   1124:     switch (cmd) {
                   1125:     case VOICE_ENABLE:
1.1.1.6   root     1126:         {
                   1127:             va_list ap;
                   1128:             int poll_mode;
                   1129: 
                   1130:             va_start (ap, cmd);
                   1131:             poll_mode = va_arg (ap, int);
                   1132:             va_end (ap);
                   1133: 
                   1134:             ldebug ("enabling voice\n");
                   1135:             if (poll_mode && alsa_poll_in (hw)) {
                   1136:                 poll_mode = 0;
                   1137:             }
                   1138:             hw->poll_mode = poll_mode;
                   1139: 
1.1.1.9   root     1140:             return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
1.1.1.6   root     1141:         }
1.1       root     1142: 
                   1143:     case VOICE_DISABLE:
                   1144:         ldebug ("disabling voice\n");
1.1.1.6   root     1145:         if (hw->poll_mode) {
                   1146:             hw->poll_mode = 0;
                   1147:             alsa_fini_poll (&alsa->pollhlp);
                   1148:         }
1.1.1.9   root     1149:         return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
1.1       root     1150:     }
                   1151: 
                   1152:     return -1;
                   1153: }
                   1154: 
                   1155: static void *alsa_audio_init (void)
                   1156: {
                   1157:     return &conf;
                   1158: }
                   1159: 
                   1160: static void alsa_audio_fini (void *opaque)
                   1161: {
                   1162:     (void) opaque;
                   1163: }
                   1164: 
                   1165: static struct audio_option alsa_options[] = {
1.1.1.6   root     1166:     {
                   1167:         .name        = "DAC_SIZE_IN_USEC",
                   1168:         .tag         = AUD_OPT_BOOL,
                   1169:         .valp        = &conf.size_in_usec_out,
                   1170:         .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
                   1171:     },
                   1172:     {
                   1173:         .name        = "DAC_PERIOD_SIZE",
                   1174:         .tag         = AUD_OPT_INT,
                   1175:         .valp        = &conf.period_size_out,
                   1176:         .descr       = "DAC period size (0 to go with system default)",
                   1177:         .overriddenp = &conf.period_size_out_overridden
                   1178:     },
                   1179:     {
                   1180:         .name        = "DAC_BUFFER_SIZE",
                   1181:         .tag         = AUD_OPT_INT,
                   1182:         .valp        = &conf.buffer_size_out,
                   1183:         .descr       = "DAC buffer size (0 to go with system default)",
                   1184:         .overriddenp = &conf.buffer_size_out_overridden
                   1185:     },
                   1186:     {
                   1187:         .name        = "ADC_SIZE_IN_USEC",
                   1188:         .tag         = AUD_OPT_BOOL,
                   1189:         .valp        = &conf.size_in_usec_in,
                   1190:         .descr       =
                   1191:         "ADC period/buffer size in microseconds (otherwise in frames)"
                   1192:     },
                   1193:     {
                   1194:         .name        = "ADC_PERIOD_SIZE",
                   1195:         .tag         = AUD_OPT_INT,
                   1196:         .valp        = &conf.period_size_in,
                   1197:         .descr       = "ADC period size (0 to go with system default)",
                   1198:         .overriddenp = &conf.period_size_in_overridden
                   1199:     },
                   1200:     {
                   1201:         .name        = "ADC_BUFFER_SIZE",
                   1202:         .tag         = AUD_OPT_INT,
                   1203:         .valp        = &conf.buffer_size_in,
                   1204:         .descr       = "ADC buffer size (0 to go with system default)",
                   1205:         .overriddenp = &conf.buffer_size_in_overridden
                   1206:     },
                   1207:     {
                   1208:         .name        = "THRESHOLD",
                   1209:         .tag         = AUD_OPT_INT,
                   1210:         .valp        = &conf.threshold,
                   1211:         .descr       = "(undocumented)"
                   1212:     },
                   1213:     {
                   1214:         .name        = "DAC_DEV",
                   1215:         .tag         = AUD_OPT_STR,
                   1216:         .valp        = &conf.pcm_name_out,
                   1217:         .descr       = "DAC device name (for instance dmix)"
                   1218:     },
                   1219:     {
                   1220:         .name        = "ADC_DEV",
                   1221:         .tag         = AUD_OPT_STR,
                   1222:         .valp        = &conf.pcm_name_in,
                   1223:         .descr       = "ADC device name"
                   1224:     },
                   1225:     {
                   1226:         .name        = "VERBOSE",
                   1227:         .tag         = AUD_OPT_BOOL,
                   1228:         .valp        = &conf.verbose,
                   1229:         .descr       = "Behave in a more verbose way"
                   1230:     },
                   1231:     { /* End of list */ }
1.1       root     1232: };
                   1233: 
                   1234: static struct audio_pcm_ops alsa_pcm_ops = {
1.1.1.6   root     1235:     .init_out = alsa_init_out,
                   1236:     .fini_out = alsa_fini_out,
                   1237:     .run_out  = alsa_run_out,
                   1238:     .write    = alsa_write,
                   1239:     .ctl_out  = alsa_ctl_out,
                   1240: 
                   1241:     .init_in  = alsa_init_in,
                   1242:     .fini_in  = alsa_fini_in,
                   1243:     .run_in   = alsa_run_in,
                   1244:     .read     = alsa_read,
                   1245:     .ctl_in   = alsa_ctl_in,
1.1       root     1246: };
                   1247: 
                   1248: struct audio_driver alsa_audio_driver = {
1.1.1.6   root     1249:     .name           = "alsa",
                   1250:     .descr          = "ALSA http://www.alsa-project.org",
                   1251:     .options        = alsa_options,
                   1252:     .init           = alsa_audio_init,
                   1253:     .fini           = alsa_audio_fini,
                   1254:     .pcm_ops        = &alsa_pcm_ops,
                   1255:     .can_be_default = 1,
                   1256:     .max_voices_out = INT_MAX,
                   1257:     .max_voices_in  = INT_MAX,
                   1258:     .voice_size_out = sizeof (ALSAVoiceOut),
                   1259:     .voice_size_in  = sizeof (ALSAVoiceIn)
1.1       root     1260: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.