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

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:         }
        !           139:         qemu_free (pfds);
        !           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) {
        !           216:     case SND_PCM_STATE_XRUN:
        !           217:         alsa_recover (hlp->handle);
        !           218:         break;
        !           219: 
        !           220:     case SND_PCM_STATE_SUSPENDED:
        !           221:         alsa_resume (hlp->handle);
        !           222:         break;
        !           223: 
        !           224:     case SND_PCM_STATE_PREPARED:
        !           225:         audio_run ("alsa run (prepared)");
        !           226:         break;
        !           227: 
        !           228:     case SND_PCM_STATE_RUNNING:
        !           229:         audio_run ("alsa run (running)");
        !           230:         break;
        !           231: 
        !           232:     default:
        !           233:         dolog ("Unexpected state %d\n", state);
        !           234:     }
        !           235: }
        !           236: 
        !           237: static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
        !           238: {
        !           239:     int i, count, err;
        !           240:     struct pollfd *pfds;
        !           241: 
        !           242:     count = snd_pcm_poll_descriptors_count (handle);
        !           243:     if (count <= 0) {
        !           244:         dolog ("Could not initialize poll mode\n"
        !           245:                "Invalid number of poll descriptors %d\n", count);
        !           246:         return -1;
        !           247:     }
        !           248: 
        !           249:     pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
        !           250:     if (!pfds) {
        !           251:         dolog ("Could not initialize poll mode\n");
        !           252:         return -1;
        !           253:     }
        !           254: 
        !           255:     err = snd_pcm_poll_descriptors (handle, pfds, count);
        !           256:     if (err < 0) {
        !           257:         alsa_logerr (err, "Could not initialize poll mode\n"
        !           258:                      "Could not obtain poll descriptors\n");
        !           259:         qemu_free (pfds);
        !           260:         return -1;
        !           261:     }
        !           262: 
        !           263:     for (i = 0; i < count; ++i) {
        !           264:         if (pfds[i].events & POLLIN) {
        !           265:             err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
        !           266:                                        NULL, hlp);
        !           267:         }
        !           268:         if (pfds[i].events & POLLOUT) {
        !           269:             if (conf.verbose) {
        !           270:                 dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
        !           271:             }
        !           272:             err = qemu_set_fd_handler (pfds[i].fd, NULL,
        !           273:                                        alsa_poll_handler, hlp);
        !           274:         }
        !           275:         if (conf.verbose) {
        !           276:             dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
        !           277:                    pfds[i].events, i, pfds[i].fd, err);
        !           278:         }
        !           279: 
        !           280:         if (err) {
        !           281:             dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
        !           282:                    pfds[i].events, i, pfds[i].fd, err);
        !           283: 
        !           284:             while (i--) {
        !           285:                 qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
        !           286:             }
        !           287:             qemu_free (pfds);
        !           288:             return -1;
        !           289:         }
        !           290:     }
        !           291:     hlp->pfds = pfds;
        !           292:     hlp->count = count;
        !           293:     hlp->handle = handle;
        !           294:     hlp->mask = mask;
        !           295:     return 0;
        !           296: }
        !           297: 
        !           298: static int alsa_poll_out (HWVoiceOut *hw)
        !           299: {
        !           300:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
        !           301: 
        !           302:     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
        !           303: }
        !           304: 
        !           305: static int alsa_poll_in (HWVoiceIn *hw)
        !           306: {
        !           307:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
        !           308: 
        !           309:     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
        !           310: }
        !           311: 
1.1       root      312: static int alsa_write (SWVoiceOut *sw, void *buf, int len)
                    313: {
                    314:     return audio_pcm_sw_write (sw, buf, len);
                    315: }
                    316: 
1.1.1.4   root      317: static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt)
1.1       root      318: {
                    319:     switch (fmt) {
                    320:     case AUD_FMT_S8:
                    321:         return SND_PCM_FORMAT_S8;
                    322: 
                    323:     case AUD_FMT_U8:
                    324:         return SND_PCM_FORMAT_U8;
                    325: 
                    326:     case AUD_FMT_S16:
                    327:         return SND_PCM_FORMAT_S16_LE;
                    328: 
                    329:     case AUD_FMT_U16:
                    330:         return SND_PCM_FORMAT_U16_LE;
                    331: 
1.1.1.3   root      332:     case AUD_FMT_S32:
                    333:         return SND_PCM_FORMAT_S32_LE;
                    334: 
                    335:     case AUD_FMT_U32:
                    336:         return SND_PCM_FORMAT_U32_LE;
                    337: 
1.1       root      338:     default:
                    339:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    340: #ifdef DEBUG_AUDIO
                    341:         abort ();
                    342: #endif
                    343:         return SND_PCM_FORMAT_U8;
                    344:     }
                    345: }
                    346: 
1.1.1.4   root      347: static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
                    348:                            int *endianness)
1.1       root      349: {
                    350:     switch (alsafmt) {
                    351:     case SND_PCM_FORMAT_S8:
                    352:         *endianness = 0;
                    353:         *fmt = AUD_FMT_S8;
                    354:         break;
                    355: 
                    356:     case SND_PCM_FORMAT_U8:
                    357:         *endianness = 0;
                    358:         *fmt = AUD_FMT_U8;
                    359:         break;
                    360: 
                    361:     case SND_PCM_FORMAT_S16_LE:
                    362:         *endianness = 0;
                    363:         *fmt = AUD_FMT_S16;
                    364:         break;
                    365: 
                    366:     case SND_PCM_FORMAT_U16_LE:
                    367:         *endianness = 0;
                    368:         *fmt = AUD_FMT_U16;
                    369:         break;
                    370: 
                    371:     case SND_PCM_FORMAT_S16_BE:
                    372:         *endianness = 1;
                    373:         *fmt = AUD_FMT_S16;
                    374:         break;
                    375: 
                    376:     case SND_PCM_FORMAT_U16_BE:
                    377:         *endianness = 1;
                    378:         *fmt = AUD_FMT_U16;
                    379:         break;
                    380: 
1.1.1.3   root      381:     case SND_PCM_FORMAT_S32_LE:
                    382:         *endianness = 0;
                    383:         *fmt = AUD_FMT_S32;
                    384:         break;
                    385: 
                    386:     case SND_PCM_FORMAT_U32_LE:
                    387:         *endianness = 0;
                    388:         *fmt = AUD_FMT_U32;
                    389:         break;
                    390: 
                    391:     case SND_PCM_FORMAT_S32_BE:
                    392:         *endianness = 1;
                    393:         *fmt = AUD_FMT_S32;
                    394:         break;
                    395: 
                    396:     case SND_PCM_FORMAT_U32_BE:
                    397:         *endianness = 1;
                    398:         *fmt = AUD_FMT_U32;
                    399:         break;
                    400: 
1.1       root      401:     default:
                    402:         dolog ("Unrecognized audio format %d\n", alsafmt);
                    403:         return -1;
                    404:     }
                    405: 
                    406:     return 0;
                    407: }
                    408: 
                    409: static void alsa_dump_info (struct alsa_params_req *req,
                    410:                             struct alsa_params_obt *obt)
                    411: {
                    412:     dolog ("parameter | requested value | obtained value\n");
                    413:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
                    414:     dolog ("channels  |      %10d |     %10d\n",
                    415:            req->nchannels, obt->nchannels);
                    416:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
                    417:     dolog ("============================================\n");
                    418:     dolog ("requested: buffer size %d period size %d\n",
                    419:            req->buffer_size, req->period_size);
                    420:     dolog ("obtained: samples %ld\n", obt->samples);
                    421: }
                    422: 
                    423: static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
                    424: {
                    425:     int err;
                    426:     snd_pcm_sw_params_t *sw_params;
                    427: 
                    428:     snd_pcm_sw_params_alloca (&sw_params);
                    429: 
                    430:     err = snd_pcm_sw_params_current (handle, sw_params);
                    431:     if (err < 0) {
                    432:         dolog ("Could not fully initialize DAC\n");
                    433:         alsa_logerr (err, "Failed to get current software parameters\n");
                    434:         return;
                    435:     }
                    436: 
                    437:     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
                    438:     if (err < 0) {
                    439:         dolog ("Could not fully initialize DAC\n");
                    440:         alsa_logerr (err, "Failed to set software threshold to %ld\n",
                    441:                      threshold);
                    442:         return;
                    443:     }
                    444: 
                    445:     err = snd_pcm_sw_params (handle, sw_params);
                    446:     if (err < 0) {
                    447:         dolog ("Could not fully initialize DAC\n");
                    448:         alsa_logerr (err, "Failed to set software parameters\n");
                    449:         return;
                    450:     }
                    451: }
                    452: 
                    453: static int alsa_open (int in, struct alsa_params_req *req,
                    454:                       struct alsa_params_obt *obt, snd_pcm_t **handlep)
                    455: {
                    456:     snd_pcm_t *handle;
                    457:     snd_pcm_hw_params_t *hw_params;
1.1.1.3   root      458:     int err;
1.1.1.4   root      459:     int size_in_usec;
1.1.1.3   root      460:     unsigned int freq, nchannels;
1.1       root      461:     const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
                    462:     snd_pcm_uframes_t obt_buffer_size;
                    463:     const char *typ = in ? "ADC" : "DAC";
1.1.1.4   root      464:     snd_pcm_format_t obtfmt;
1.1       root      465: 
                    466:     freq = req->freq;
                    467:     nchannels = req->nchannels;
1.1.1.4   root      468:     size_in_usec = req->size_in_usec;
1.1       root      469: 
                    470:     snd_pcm_hw_params_alloca (&hw_params);
                    471: 
                    472:     err = snd_pcm_open (
                    473:         &handle,
                    474:         pcm_name,
                    475:         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
                    476:         SND_PCM_NONBLOCK
                    477:         );
                    478:     if (err < 0) {
                    479:         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
                    480:         return -1;
                    481:     }
                    482: 
                    483:     err = snd_pcm_hw_params_any (handle, hw_params);
                    484:     if (err < 0) {
                    485:         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
                    486:         goto err;
                    487:     }
                    488: 
                    489:     err = snd_pcm_hw_params_set_access (
                    490:         handle,
                    491:         hw_params,
                    492:         SND_PCM_ACCESS_RW_INTERLEAVED
                    493:         );
                    494:     if (err < 0) {
                    495:         alsa_logerr2 (err, typ, "Failed to set access type\n");
                    496:         goto err;
                    497:     }
                    498: 
                    499:     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
1.1.1.4   root      500:     if (err < 0 && conf.verbose) {
1.1       root      501:         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
                    502:     }
                    503: 
                    504:     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
                    505:     if (err < 0) {
                    506:         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
                    507:         goto err;
                    508:     }
                    509: 
                    510:     err = snd_pcm_hw_params_set_channels_near (
                    511:         handle,
                    512:         hw_params,
                    513:         &nchannels
                    514:         );
                    515:     if (err < 0) {
                    516:         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
                    517:                       req->nchannels);
                    518:         goto err;
                    519:     }
                    520: 
                    521:     if (nchannels != 1 && nchannels != 2) {
                    522:         alsa_logerr2 (err, typ,
                    523:                       "Can not handle obtained number of channels %d\n",
                    524:                       nchannels);
                    525:         goto err;
                    526:     }
                    527: 
1.1.1.4   root      528:     if (req->buffer_size) {
                    529:         unsigned long obt;
1.1       root      530: 
1.1.1.4   root      531:         if (size_in_usec) {
                    532:             int dir = 0;
                    533:             unsigned int btime = req->buffer_size;
1.1       root      534: 
                    535:             err = snd_pcm_hw_params_set_buffer_time_near (
                    536:                 handle,
                    537:                 hw_params,
1.1.1.4   root      538:                 &btime,
                    539:                 &dir
1.1       root      540:                 );
1.1.1.4   root      541:             obt = btime;
1.1       root      542:         }
                    543:         else {
1.1.1.4   root      544:             snd_pcm_uframes_t bsize = req->buffer_size;
1.1       root      545: 
1.1.1.4   root      546:             err = snd_pcm_hw_params_set_buffer_size_near (
                    547:                 handle,
                    548:                 hw_params,
                    549:                 &bsize
                    550:                 );
                    551:             obt = bsize;
                    552:         }
                    553:         if (err < 0) {
                    554:             alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
                    555:                           size_in_usec ? "time" : "size", req->buffer_size);
                    556:             goto err;
                    557:         }
1.1       root      558: 
1.1.1.4   root      559:         if ((req->override_mask & 2) && (obt - req->buffer_size))
                    560:             dolog ("Requested buffer %s %u was rejected, using %lu\n",
                    561:                    size_in_usec ? "time" : "size", req->buffer_size, obt);
                    562:     }
                    563: 
                    564:     if (req->period_size) {
                    565:         unsigned long obt;
                    566: 
                    567:         if (size_in_usec) {
                    568:             int dir = 0;
                    569:             unsigned int ptime = req->period_size;
1.1       root      570: 
1.1.1.4   root      571:             err = snd_pcm_hw_params_set_period_time_near (
                    572:                 handle,
1.1       root      573:                 hw_params,
1.1.1.4   root      574:                 &ptime,
                    575:                 &dir
1.1       root      576:                 );
1.1.1.4   root      577:             obt = ptime;
                    578:         }
                    579:         else {
                    580:             int dir = 0;
                    581:             snd_pcm_uframes_t psize = req->period_size;
1.1       root      582: 
1.1.1.4   root      583:             err = snd_pcm_hw_params_set_period_size_near (
1.1       root      584:                 handle,
                    585:                 hw_params,
1.1.1.4   root      586:                 &psize,
                    587:                 &dir
1.1       root      588:                 );
1.1.1.4   root      589:             obt = psize;
1.1       root      590:         }
1.1.1.4   root      591: 
                    592:         if (err < 0) {
                    593:             alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
                    594:                           size_in_usec ? "time" : "size", req->period_size);
                    595:             goto err;
                    596:         }
                    597: 
1.1.1.6 ! root      598:         if (((req->override_mask & 1) && (obt - req->period_size)))
1.1.1.4   root      599:             dolog ("Requested period %s %u was rejected, using %lu\n",
                    600:                    size_in_usec ? "time" : "size", req->period_size, obt);
1.1       root      601:     }
                    602: 
                    603:     err = snd_pcm_hw_params (handle, hw_params);
                    604:     if (err < 0) {
                    605:         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
                    606:         goto err;
                    607:     }
                    608: 
                    609:     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
                    610:     if (err < 0) {
                    611:         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
                    612:         goto err;
                    613:     }
                    614: 
1.1.1.4   root      615:     err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
                    616:     if (err < 0) {
                    617:         alsa_logerr2 (err, typ, "Failed to get format\n");
                    618:         goto err;
                    619:     }
                    620: 
                    621:     if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
                    622:         dolog ("Invalid format was returned %d\n", obtfmt);
                    623:         goto err;
                    624:     }
                    625: 
1.1       root      626:     err = snd_pcm_prepare (handle);
                    627:     if (err < 0) {
                    628:         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
                    629:         goto err;
                    630:     }
                    631: 
                    632:     if (!in && conf.threshold) {
                    633:         snd_pcm_uframes_t threshold;
                    634:         int bytes_per_sec;
                    635: 
1.1.1.4   root      636:         bytes_per_sec = freq << (nchannels == 2);
                    637: 
                    638:         switch (obt->fmt) {
                    639:         case AUD_FMT_S8:
                    640:         case AUD_FMT_U8:
                    641:             break;
                    642: 
                    643:         case AUD_FMT_S16:
                    644:         case AUD_FMT_U16:
                    645:             bytes_per_sec <<= 1;
                    646:             break;
                    647: 
                    648:         case AUD_FMT_S32:
                    649:         case AUD_FMT_U32:
                    650:             bytes_per_sec <<= 2;
                    651:             break;
                    652:         }
1.1       root      653: 
                    654:         threshold = (conf.threshold * bytes_per_sec) / 1000;
                    655:         alsa_set_threshold (handle, threshold);
                    656:     }
                    657: 
                    658:     obt->nchannels = nchannels;
                    659:     obt->freq = freq;
                    660:     obt->samples = obt_buffer_size;
1.1.1.4   root      661: 
1.1       root      662:     *handlep = handle;
                    663: 
1.1.1.4   root      664:     if (conf.verbose &&
                    665:         (obt->fmt != req->fmt ||
                    666:          obt->nchannels != req->nchannels ||
                    667:          obt->freq != req->freq)) {
                    668:         dolog ("Audio paramters for %s\n", typ);
1.1       root      669:         alsa_dump_info (req, obt);
                    670:     }
                    671: 
                    672: #ifdef DEBUG
                    673:     alsa_dump_info (req, obt);
                    674: #endif
                    675:     return 0;
                    676: 
                    677:  err:
1.1.1.6 ! root      678:     alsa_anal_close1 (&handle);
1.1       root      679:     return -1;
                    680: }
                    681: 
                    682: static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
                    683: {
                    684:     snd_pcm_sframes_t avail;
                    685: 
                    686:     avail = snd_pcm_avail_update (handle);
                    687:     if (avail < 0) {
                    688:         if (avail == -EPIPE) {
                    689:             if (!alsa_recover (handle)) {
                    690:                 avail = snd_pcm_avail_update (handle);
                    691:             }
                    692:         }
                    693: 
                    694:         if (avail < 0) {
                    695:             alsa_logerr (avail,
                    696:                          "Could not obtain number of available frames\n");
                    697:             return -1;
                    698:         }
                    699:     }
                    700: 
                    701:     return avail;
                    702: }
                    703: 
1.1.1.6 ! root      704: static void alsa_write_pending (ALSAVoiceOut *alsa)
1.1       root      705: {
1.1.1.6 ! root      706:     HWVoiceOut *hw = &alsa->hw;
1.1       root      707: 
1.1.1.6 ! root      708:     while (alsa->pending) {
        !           709:         int left_till_end_samples = hw->samples - alsa->wpos;
        !           710:         int len = audio_MIN (alsa->pending, left_till_end_samples);
        !           711:         char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
1.1       root      712: 
                    713:         while (len) {
1.1.1.6 ! root      714:             snd_pcm_sframes_t written;
        !           715: 
        !           716:             written = snd_pcm_writei (alsa->handle, src, len);
1.1       root      717: 
                    718:             if (written <= 0) {
                    719:                 switch (written) {
                    720:                 case 0:
                    721:                     if (conf.verbose) {
                    722:                         dolog ("Failed to write %d frames (wrote zero)\n", len);
                    723:                     }
1.1.1.6 ! root      724:                     return;
1.1       root      725: 
                    726:                 case -EPIPE:
                    727:                     if (alsa_recover (alsa->handle)) {
                    728:                         alsa_logerr (written, "Failed to write %d frames\n",
                    729:                                      len);
1.1.1.6 ! root      730:                         return;
1.1       root      731:                     }
                    732:                     if (conf.verbose) {
                    733:                         dolog ("Recovering from playback xrun\n");
                    734:                     }
                    735:                     continue;
                    736: 
1.1.1.6 ! root      737:                 case -ESTRPIPE:
        !           738:                     /* stream is suspended and waiting for an
        !           739:                        application recovery */
        !           740:                     if (alsa_resume (alsa->handle)) {
        !           741:                         alsa_logerr (written, "Failed to write %d frames\n",
        !           742:                                      len);
        !           743:                         return;
        !           744:                     }
        !           745:                     if (conf.verbose) {
        !           746:                         dolog ("Resuming suspended output stream\n");
        !           747:                     }
        !           748:                     continue;
        !           749: 
1.1       root      750:                 case -EAGAIN:
1.1.1.6 ! root      751:                     return;
1.1       root      752: 
                    753:                 default:
1.1.1.6 ! root      754:                     alsa_logerr (written, "Failed to write %d frames from %p\n",
        !           755:                                  len, src);
        !           756:                     return;
1.1       root      757:                 }
                    758:             }
                    759: 
1.1.1.6 ! root      760:             alsa->wpos = (alsa->wpos + written) % hw->samples;
        !           761:             alsa->pending -= written;
1.1       root      762:             len -= written;
                    763:         }
                    764:     }
1.1.1.6 ! root      765: }
1.1       root      766: 
1.1.1.6 ! root      767: static int alsa_run_out (HWVoiceOut *hw, int live)
        !           768: {
        !           769:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
        !           770:     int decr;
        !           771:     snd_pcm_sframes_t avail;
        !           772: 
        !           773:     avail = alsa_get_avail (alsa->handle);
        !           774:     if (avail < 0) {
        !           775:         dolog ("Could not get number of available playback frames\n");
        !           776:         return 0;
        !           777:     }
        !           778: 
        !           779:     decr = audio_MIN (live, avail);
        !           780:     decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
        !           781:     alsa->pending += decr;
        !           782:     alsa_write_pending (alsa);
1.1       root      783:     return decr;
                    784: }
                    785: 
                    786: static void alsa_fini_out (HWVoiceOut *hw)
                    787: {
                    788:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    789: 
                    790:     ldebug ("alsa_fini\n");
1.1.1.6 ! root      791:     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1.1       root      792: 
                    793:     if (alsa->pcm_buf) {
                    794:         qemu_free (alsa->pcm_buf);
                    795:         alsa->pcm_buf = NULL;
                    796:     }
                    797: }
                    798: 
1.1.1.4   root      799: static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
1.1       root      800: {
                    801:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    802:     struct alsa_params_req req;
                    803:     struct alsa_params_obt obt;
                    804:     snd_pcm_t *handle;
1.1.1.4   root      805:     struct audsettings obt_as;
1.1       root      806: 
                    807:     req.fmt = aud_to_alsafmt (as->fmt);
                    808:     req.freq = as->freq;
                    809:     req.nchannels = as->nchannels;
                    810:     req.period_size = conf.period_size_out;
                    811:     req.buffer_size = conf.buffer_size_out;
1.1.1.4   root      812:     req.size_in_usec = conf.size_in_usec_out;
1.1.1.5   root      813:     req.override_mask =
                    814:         (conf.period_size_out_overridden ? 1 : 0) |
                    815:         (conf.buffer_size_out_overridden ? 2 : 0);
1.1       root      816: 
                    817:     if (alsa_open (0, &req, &obt, &handle)) {
                    818:         return -1;
                    819:     }
                    820: 
                    821:     obt_as.freq = obt.freq;
                    822:     obt_as.nchannels = obt.nchannels;
1.1.1.4   root      823:     obt_as.fmt = obt.fmt;
                    824:     obt_as.endianness = obt.endianness;
1.1       root      825: 
1.1.1.2   root      826:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      827:     hw->samples = obt.samples;
                    828: 
                    829:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
                    830:     if (!alsa->pcm_buf) {
                    831:         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    832:                hw->samples, 1 << hw->info.shift);
1.1.1.6 ! root      833:         alsa_anal_close1 (&handle);
1.1       root      834:         return -1;
                    835:     }
                    836: 
                    837:     alsa->handle = handle;
                    838:     return 0;
                    839: }
                    840: 
                    841: static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
                    842: {
                    843:     int err;
                    844: 
                    845:     if (pause) {
                    846:         err = snd_pcm_drop (handle);
                    847:         if (err < 0) {
                    848:             alsa_logerr (err, "Could not stop %s\n", typ);
                    849:             return -1;
                    850:         }
                    851:     }
                    852:     else {
                    853:         err = snd_pcm_prepare (handle);
                    854:         if (err < 0) {
                    855:             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
                    856:             return -1;
                    857:         }
                    858:     }
                    859: 
                    860:     return 0;
                    861: }
                    862: 
                    863: static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    864: {
                    865:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    866: 
                    867:     switch (cmd) {
                    868:     case VOICE_ENABLE:
1.1.1.6 ! root      869:         {
        !           870:             va_list ap;
        !           871:             int poll_mode;
        !           872: 
        !           873:             va_start (ap, cmd);
        !           874:             poll_mode = va_arg (ap, int);
        !           875:             va_end (ap);
        !           876: 
        !           877:             ldebug ("enabling voice\n");
        !           878:             if (poll_mode && alsa_poll_out (hw)) {
        !           879:                 poll_mode = 0;
        !           880:             }
        !           881:             hw->poll_mode = poll_mode;
        !           882:             return alsa_voice_ctl (alsa->handle, "playback", 0);
        !           883:         }
1.1       root      884: 
                    885:     case VOICE_DISABLE:
                    886:         ldebug ("disabling voice\n");
                    887:         return alsa_voice_ctl (alsa->handle, "playback", 1);
                    888:     }
                    889: 
                    890:     return -1;
                    891: }
                    892: 
1.1.1.4   root      893: static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
1.1       root      894: {
                    895:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    896:     struct alsa_params_req req;
                    897:     struct alsa_params_obt obt;
                    898:     snd_pcm_t *handle;
1.1.1.4   root      899:     struct audsettings obt_as;
1.1       root      900: 
                    901:     req.fmt = aud_to_alsafmt (as->fmt);
                    902:     req.freq = as->freq;
                    903:     req.nchannels = as->nchannels;
                    904:     req.period_size = conf.period_size_in;
                    905:     req.buffer_size = conf.buffer_size_in;
1.1.1.4   root      906:     req.size_in_usec = conf.size_in_usec_in;
1.1.1.5   root      907:     req.override_mask =
                    908:         (conf.period_size_in_overridden ? 1 : 0) |
                    909:         (conf.buffer_size_in_overridden ? 2 : 0);
1.1       root      910: 
                    911:     if (alsa_open (1, &req, &obt, &handle)) {
                    912:         return -1;
                    913:     }
                    914: 
                    915:     obt_as.freq = obt.freq;
                    916:     obt_as.nchannels = obt.nchannels;
1.1.1.4   root      917:     obt_as.fmt = obt.fmt;
                    918:     obt_as.endianness = obt.endianness;
1.1       root      919: 
1.1.1.2   root      920:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      921:     hw->samples = obt.samples;
                    922: 
                    923:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    924:     if (!alsa->pcm_buf) {
                    925:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    926:                hw->samples, 1 << hw->info.shift);
1.1.1.6 ! root      927:         alsa_anal_close1 (&handle);
1.1       root      928:         return -1;
                    929:     }
                    930: 
                    931:     alsa->handle = handle;
                    932:     return 0;
                    933: }
                    934: 
                    935: static void alsa_fini_in (HWVoiceIn *hw)
                    936: {
                    937:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    938: 
1.1.1.6 ! root      939:     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
1.1       root      940: 
                    941:     if (alsa->pcm_buf) {
                    942:         qemu_free (alsa->pcm_buf);
                    943:         alsa->pcm_buf = NULL;
                    944:     }
                    945: }
                    946: 
                    947: static int alsa_run_in (HWVoiceIn *hw)
                    948: {
                    949:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    950:     int hwshift = hw->info.shift;
                    951:     int i;
                    952:     int live = audio_pcm_hw_get_live_in (hw);
                    953:     int dead = hw->samples - live;
                    954:     int decr;
                    955:     struct {
                    956:         int add;
                    957:         int len;
                    958:     } bufs[2] = {
1.1.1.6 ! root      959:         { .add = hw->wpos, .len = 0 },
        !           960:         { .add = 0,        .len = 0 }
1.1       root      961:     };
                    962:     snd_pcm_sframes_t avail;
                    963:     snd_pcm_uframes_t read_samples = 0;
                    964: 
                    965:     if (!dead) {
                    966:         return 0;
                    967:     }
                    968: 
                    969:     avail = alsa_get_avail (alsa->handle);
                    970:     if (avail < 0) {
                    971:         dolog ("Could not get number of captured frames\n");
                    972:         return 0;
                    973:     }
                    974: 
1.1.1.6 ! root      975:     if (!avail) {
        !           976:         snd_pcm_state_t state;
        !           977: 
        !           978:         state = snd_pcm_state (alsa->handle);
        !           979:         switch (state) {
        !           980:         case SND_PCM_STATE_PREPARED:
        !           981:             avail = hw->samples;
        !           982:             break;
        !           983:         case SND_PCM_STATE_SUSPENDED:
        !           984:             /* stream is suspended and waiting for an application recovery */
        !           985:             if (alsa_resume (alsa->handle)) {
        !           986:                 dolog ("Failed to resume suspended input stream\n");
        !           987:                 return 0;
        !           988:             }
        !           989:             if (conf.verbose) {
        !           990:                 dolog ("Resuming suspended input stream\n");
        !           991:             }
        !           992:             break;
        !           993:         default:
        !           994:             if (conf.verbose) {
        !           995:                 dolog ("No frames available and ALSA state is %d\n", state);
        !           996:             }
        !           997:             return 0;
        !           998:         }
1.1       root      999:     }
                   1000: 
                   1001:     decr = audio_MIN (dead, avail);
                   1002:     if (!decr) {
                   1003:         return 0;
                   1004:     }
                   1005: 
                   1006:     if (hw->wpos + decr > hw->samples) {
                   1007:         bufs[0].len = (hw->samples - hw->wpos);
                   1008:         bufs[1].len = (decr - (hw->samples - hw->wpos));
                   1009:     }
                   1010:     else {
                   1011:         bufs[0].len = decr;
                   1012:     }
                   1013: 
                   1014:     for (i = 0; i < 2; ++i) {
                   1015:         void *src;
1.1.1.4   root     1016:         struct st_sample *dst;
1.1       root     1017:         snd_pcm_sframes_t nread;
                   1018:         snd_pcm_uframes_t len;
                   1019: 
                   1020:         len = bufs[i].len;
                   1021: 
                   1022:         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
                   1023:         dst = hw->conv_buf + bufs[i].add;
                   1024: 
                   1025:         while (len) {
                   1026:             nread = snd_pcm_readi (alsa->handle, src, len);
                   1027: 
                   1028:             if (nread <= 0) {
                   1029:                 switch (nread) {
                   1030:                 case 0:
                   1031:                     if (conf.verbose) {
                   1032:                         dolog ("Failed to read %ld frames (read zero)\n", len);
                   1033:                     }
                   1034:                     goto exit;
                   1035: 
                   1036:                 case -EPIPE:
                   1037:                     if (alsa_recover (alsa->handle)) {
                   1038:                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
                   1039:                         goto exit;
                   1040:                     }
                   1041:                     if (conf.verbose) {
                   1042:                         dolog ("Recovering from capture xrun\n");
                   1043:                     }
                   1044:                     continue;
                   1045: 
                   1046:                 case -EAGAIN:
                   1047:                     goto exit;
                   1048: 
                   1049:                 default:
                   1050:                     alsa_logerr (
                   1051:                         nread,
                   1052:                         "Failed to read %ld frames from %p\n",
                   1053:                         len,
                   1054:                         src
                   1055:                         );
                   1056:                     goto exit;
                   1057:                 }
                   1058:             }
                   1059: 
                   1060:             hw->conv (dst, src, nread, &nominal_volume);
                   1061: 
                   1062:             src = advance (src, nread << hwshift);
                   1063:             dst += nread;
                   1064: 
                   1065:             read_samples += nread;
                   1066:             len -= nread;
                   1067:         }
                   1068:     }
                   1069: 
                   1070:  exit:
                   1071:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                   1072:     return read_samples;
                   1073: }
                   1074: 
                   1075: static int alsa_read (SWVoiceIn *sw, void *buf, int size)
                   1076: {
                   1077:     return audio_pcm_sw_read (sw, buf, size);
                   1078: }
                   1079: 
                   1080: static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
                   1081: {
                   1082:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                   1083: 
                   1084:     switch (cmd) {
                   1085:     case VOICE_ENABLE:
1.1.1.6 ! root     1086:         {
        !          1087:             va_list ap;
        !          1088:             int poll_mode;
        !          1089: 
        !          1090:             va_start (ap, cmd);
        !          1091:             poll_mode = va_arg (ap, int);
        !          1092:             va_end (ap);
        !          1093: 
        !          1094:             ldebug ("enabling voice\n");
        !          1095:             if (poll_mode && alsa_poll_in (hw)) {
        !          1096:                 poll_mode = 0;
        !          1097:             }
        !          1098:             hw->poll_mode = poll_mode;
        !          1099: 
        !          1100:             return alsa_voice_ctl (alsa->handle, "capture", 0);
        !          1101:         }
1.1       root     1102: 
                   1103:     case VOICE_DISABLE:
                   1104:         ldebug ("disabling voice\n");
1.1.1.6 ! root     1105:         if (hw->poll_mode) {
        !          1106:             hw->poll_mode = 0;
        !          1107:             alsa_fini_poll (&alsa->pollhlp);
        !          1108:         }
1.1       root     1109:         return alsa_voice_ctl (alsa->handle, "capture", 1);
                   1110:     }
                   1111: 
                   1112:     return -1;
                   1113: }
                   1114: 
                   1115: static void *alsa_audio_init (void)
                   1116: {
                   1117:     return &conf;
                   1118: }
                   1119: 
                   1120: static void alsa_audio_fini (void *opaque)
                   1121: {
                   1122:     (void) opaque;
                   1123: }
                   1124: 
                   1125: static struct audio_option alsa_options[] = {
1.1.1.6 ! root     1126:     {
        !          1127:         .name        = "DAC_SIZE_IN_USEC",
        !          1128:         .tag         = AUD_OPT_BOOL,
        !          1129:         .valp        = &conf.size_in_usec_out,
        !          1130:         .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
        !          1131:     },
        !          1132:     {
        !          1133:         .name        = "DAC_PERIOD_SIZE",
        !          1134:         .tag         = AUD_OPT_INT,
        !          1135:         .valp        = &conf.period_size_out,
        !          1136:         .descr       = "DAC period size (0 to go with system default)",
        !          1137:         .overriddenp = &conf.period_size_out_overridden
        !          1138:     },
        !          1139:     {
        !          1140:         .name        = "DAC_BUFFER_SIZE",
        !          1141:         .tag         = AUD_OPT_INT,
        !          1142:         .valp        = &conf.buffer_size_out,
        !          1143:         .descr       = "DAC buffer size (0 to go with system default)",
        !          1144:         .overriddenp = &conf.buffer_size_out_overridden
        !          1145:     },
        !          1146:     {
        !          1147:         .name        = "ADC_SIZE_IN_USEC",
        !          1148:         .tag         = AUD_OPT_BOOL,
        !          1149:         .valp        = &conf.size_in_usec_in,
        !          1150:         .descr       =
        !          1151:         "ADC period/buffer size in microseconds (otherwise in frames)"
        !          1152:     },
        !          1153:     {
        !          1154:         .name        = "ADC_PERIOD_SIZE",
        !          1155:         .tag         = AUD_OPT_INT,
        !          1156:         .valp        = &conf.period_size_in,
        !          1157:         .descr       = "ADC period size (0 to go with system default)",
        !          1158:         .overriddenp = &conf.period_size_in_overridden
        !          1159:     },
        !          1160:     {
        !          1161:         .name        = "ADC_BUFFER_SIZE",
        !          1162:         .tag         = AUD_OPT_INT,
        !          1163:         .valp        = &conf.buffer_size_in,
        !          1164:         .descr       = "ADC buffer size (0 to go with system default)",
        !          1165:         .overriddenp = &conf.buffer_size_in_overridden
        !          1166:     },
        !          1167:     {
        !          1168:         .name        = "THRESHOLD",
        !          1169:         .tag         = AUD_OPT_INT,
        !          1170:         .valp        = &conf.threshold,
        !          1171:         .descr       = "(undocumented)"
        !          1172:     },
        !          1173:     {
        !          1174:         .name        = "DAC_DEV",
        !          1175:         .tag         = AUD_OPT_STR,
        !          1176:         .valp        = &conf.pcm_name_out,
        !          1177:         .descr       = "DAC device name (for instance dmix)"
        !          1178:     },
        !          1179:     {
        !          1180:         .name        = "ADC_DEV",
        !          1181:         .tag         = AUD_OPT_STR,
        !          1182:         .valp        = &conf.pcm_name_in,
        !          1183:         .descr       = "ADC device name"
        !          1184:     },
        !          1185:     {
        !          1186:         .name        = "VERBOSE",
        !          1187:         .tag         = AUD_OPT_BOOL,
        !          1188:         .valp        = &conf.verbose,
        !          1189:         .descr       = "Behave in a more verbose way"
        !          1190:     },
        !          1191:     { /* End of list */ }
1.1       root     1192: };
                   1193: 
                   1194: static struct audio_pcm_ops alsa_pcm_ops = {
1.1.1.6 ! root     1195:     .init_out = alsa_init_out,
        !          1196:     .fini_out = alsa_fini_out,
        !          1197:     .run_out  = alsa_run_out,
        !          1198:     .write    = alsa_write,
        !          1199:     .ctl_out  = alsa_ctl_out,
        !          1200: 
        !          1201:     .init_in  = alsa_init_in,
        !          1202:     .fini_in  = alsa_fini_in,
        !          1203:     .run_in   = alsa_run_in,
        !          1204:     .read     = alsa_read,
        !          1205:     .ctl_in   = alsa_ctl_in,
1.1       root     1206: };
                   1207: 
                   1208: struct audio_driver alsa_audio_driver = {
1.1.1.6 ! root     1209:     .name           = "alsa",
        !          1210:     .descr          = "ALSA http://www.alsa-project.org",
        !          1211:     .options        = alsa_options,
        !          1212:     .init           = alsa_audio_init,
        !          1213:     .fini           = alsa_audio_fini,
        !          1214:     .pcm_ops        = &alsa_pcm_ops,
        !          1215:     .can_be_default = 1,
        !          1216:     .max_voices_out = INT_MAX,
        !          1217:     .max_voices_in  = INT_MAX,
        !          1218:     .voice_size_out = sizeof (ALSAVoiceOut),
        !          1219:     .voice_size_in  = sizeof (ALSAVoiceIn)
1.1       root     1220: };

unix.superglobalmegacorp.com

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