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

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"
        !            26: #include "audio.h"
1.1       root       27: 
                     28: #define AUDIO_CAP "alsa"
                     29: #include "audio_int.h"
                     30: 
                     31: typedef struct ALSAVoiceOut {
                     32:     HWVoiceOut hw;
                     33:     void *pcm_buf;
                     34:     snd_pcm_t *handle;
                     35: } ALSAVoiceOut;
                     36: 
                     37: typedef struct ALSAVoiceIn {
                     38:     HWVoiceIn hw;
                     39:     snd_pcm_t *handle;
                     40:     void *pcm_buf;
                     41: } ALSAVoiceIn;
                     42: 
                     43: static struct {
                     44:     int size_in_usec_in;
                     45:     int size_in_usec_out;
                     46:     const char *pcm_name_in;
                     47:     const char *pcm_name_out;
                     48:     unsigned int buffer_size_in;
                     49:     unsigned int period_size_in;
                     50:     unsigned int buffer_size_out;
                     51:     unsigned int period_size_out;
                     52:     unsigned int threshold;
                     53: 
1.1.1.3 ! root       54:     int buffer_size_in_overridden;
        !            55:     int period_size_in_overridden;
1.1       root       56: 
1.1.1.3 ! root       57:     int buffer_size_out_overridden;
        !            58:     int period_size_out_overridden;
1.1       root       59:     int verbose;
                     60: } conf = {
1.1.1.3 ! root       61: #define DEFAULT_BUFFER_SIZE 1024
        !            62: #define DEFAULT_PERIOD_SIZE 256
1.1       root       63: #ifdef HIGH_LATENCY
                     64:     .size_in_usec_in = 1,
                     65:     .size_in_usec_out = 1,
                     66: #endif
1.1.1.2   root       67:     .pcm_name_out = "default",
                     68:     .pcm_name_in = "default",
1.1       root       69: #ifdef HIGH_LATENCY
                     70:     .buffer_size_in = 400000,
                     71:     .period_size_in = 400000 / 4,
                     72:     .buffer_size_out = 400000,
                     73:     .period_size_out = 400000 / 4,
                     74: #else
                     75:     .buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
                     76:     .period_size_in = DEFAULT_PERIOD_SIZE * 4,
                     77:     .buffer_size_out = DEFAULT_BUFFER_SIZE,
                     78:     .period_size_out = DEFAULT_PERIOD_SIZE,
1.1.1.3 ! root       79:     .buffer_size_in_overridden = 0,
        !            80:     .buffer_size_out_overridden = 0,
        !            81:     .period_size_in_overridden = 0,
        !            82:     .period_size_out_overridden = 0,
1.1       root       83: #endif
                     84:     .threshold = 0,
                     85:     .verbose = 0
                     86: };
                     87: 
                     88: struct alsa_params_req {
1.1.1.3 ! root       89:     unsigned int freq;
1.1       root       90:     audfmt_e fmt;
1.1.1.3 ! root       91:     unsigned int nchannels;
1.1       root       92:     unsigned int buffer_size;
                     93:     unsigned int period_size;
                     94: };
                     95: 
                     96: struct alsa_params_obt {
                     97:     int freq;
                     98:     audfmt_e fmt;
                     99:     int nchannels;
                    100:     snd_pcm_uframes_t samples;
                    101: };
                    102: 
                    103: static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
                    104: {
                    105:     va_list ap;
                    106: 
                    107:     va_start (ap, fmt);
                    108:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    109:     va_end (ap);
                    110: 
                    111:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
                    112: }
                    113: 
                    114: static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
                    115:     int err,
                    116:     const char *typ,
                    117:     const char *fmt,
                    118:     ...
                    119:     )
                    120: {
                    121:     va_list ap;
                    122: 
                    123:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
                    124: 
                    125:     va_start (ap, fmt);
                    126:     AUD_vlog (AUDIO_CAP, fmt, ap);
                    127:     va_end (ap);
                    128: 
                    129:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
                    130: }
                    131: 
                    132: static void alsa_anal_close (snd_pcm_t **handlep)
                    133: {
                    134:     int err = snd_pcm_close (*handlep);
                    135:     if (err) {
                    136:         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
                    137:     }
                    138:     *handlep = NULL;
                    139: }
                    140: 
                    141: static int alsa_write (SWVoiceOut *sw, void *buf, int len)
                    142: {
                    143:     return audio_pcm_sw_write (sw, buf, len);
                    144: }
                    145: 
                    146: static int aud_to_alsafmt (audfmt_e fmt)
                    147: {
                    148:     switch (fmt) {
                    149:     case AUD_FMT_S8:
                    150:         return SND_PCM_FORMAT_S8;
                    151: 
                    152:     case AUD_FMT_U8:
                    153:         return SND_PCM_FORMAT_U8;
                    154: 
                    155:     case AUD_FMT_S16:
                    156:         return SND_PCM_FORMAT_S16_LE;
                    157: 
                    158:     case AUD_FMT_U16:
                    159:         return SND_PCM_FORMAT_U16_LE;
                    160: 
1.1.1.3 ! root      161:     case AUD_FMT_S32:
        !           162:         return SND_PCM_FORMAT_S32_LE;
        !           163: 
        !           164:     case AUD_FMT_U32:
        !           165:         return SND_PCM_FORMAT_U32_LE;
        !           166: 
1.1       root      167:     default:
                    168:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
                    169: #ifdef DEBUG_AUDIO
                    170:         abort ();
                    171: #endif
                    172:         return SND_PCM_FORMAT_U8;
                    173:     }
                    174: }
                    175: 
                    176: static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
                    177: {
                    178:     switch (alsafmt) {
                    179:     case SND_PCM_FORMAT_S8:
                    180:         *endianness = 0;
                    181:         *fmt = AUD_FMT_S8;
                    182:         break;
                    183: 
                    184:     case SND_PCM_FORMAT_U8:
                    185:         *endianness = 0;
                    186:         *fmt = AUD_FMT_U8;
                    187:         break;
                    188: 
                    189:     case SND_PCM_FORMAT_S16_LE:
                    190:         *endianness = 0;
                    191:         *fmt = AUD_FMT_S16;
                    192:         break;
                    193: 
                    194:     case SND_PCM_FORMAT_U16_LE:
                    195:         *endianness = 0;
                    196:         *fmt = AUD_FMT_U16;
                    197:         break;
                    198: 
                    199:     case SND_PCM_FORMAT_S16_BE:
                    200:         *endianness = 1;
                    201:         *fmt = AUD_FMT_S16;
                    202:         break;
                    203: 
                    204:     case SND_PCM_FORMAT_U16_BE:
                    205:         *endianness = 1;
                    206:         *fmt = AUD_FMT_U16;
                    207:         break;
                    208: 
1.1.1.3 ! root      209:     case SND_PCM_FORMAT_S32_LE:
        !           210:         *endianness = 0;
        !           211:         *fmt = AUD_FMT_S32;
        !           212:         break;
        !           213: 
        !           214:     case SND_PCM_FORMAT_U32_LE:
        !           215:         *endianness = 0;
        !           216:         *fmt = AUD_FMT_U32;
        !           217:         break;
        !           218: 
        !           219:     case SND_PCM_FORMAT_S32_BE:
        !           220:         *endianness = 1;
        !           221:         *fmt = AUD_FMT_S32;
        !           222:         break;
        !           223: 
        !           224:     case SND_PCM_FORMAT_U32_BE:
        !           225:         *endianness = 1;
        !           226:         *fmt = AUD_FMT_U32;
        !           227:         break;
        !           228: 
1.1       root      229:     default:
                    230:         dolog ("Unrecognized audio format %d\n", alsafmt);
                    231:         return -1;
                    232:     }
                    233: 
                    234:     return 0;
                    235: }
                    236: 
                    237: #if defined DEBUG_MISMATCHES || defined DEBUG
                    238: static void alsa_dump_info (struct alsa_params_req *req,
                    239:                             struct alsa_params_obt *obt)
                    240: {
                    241:     dolog ("parameter | requested value | obtained value\n");
                    242:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
                    243:     dolog ("channels  |      %10d |     %10d\n",
                    244:            req->nchannels, obt->nchannels);
                    245:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
                    246:     dolog ("============================================\n");
                    247:     dolog ("requested: buffer size %d period size %d\n",
                    248:            req->buffer_size, req->period_size);
                    249:     dolog ("obtained: samples %ld\n", obt->samples);
                    250: }
                    251: #endif
                    252: 
                    253: static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
                    254: {
                    255:     int err;
                    256:     snd_pcm_sw_params_t *sw_params;
                    257: 
                    258:     snd_pcm_sw_params_alloca (&sw_params);
                    259: 
                    260:     err = snd_pcm_sw_params_current (handle, sw_params);
                    261:     if (err < 0) {
                    262:         dolog ("Could not fully initialize DAC\n");
                    263:         alsa_logerr (err, "Failed to get current software parameters\n");
                    264:         return;
                    265:     }
                    266: 
                    267:     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
                    268:     if (err < 0) {
                    269:         dolog ("Could not fully initialize DAC\n");
                    270:         alsa_logerr (err, "Failed to set software threshold to %ld\n",
                    271:                      threshold);
                    272:         return;
                    273:     }
                    274: 
                    275:     err = snd_pcm_sw_params (handle, sw_params);
                    276:     if (err < 0) {
                    277:         dolog ("Could not fully initialize DAC\n");
                    278:         alsa_logerr (err, "Failed to set software parameters\n");
                    279:         return;
                    280:     }
                    281: }
                    282: 
                    283: static int alsa_open (int in, struct alsa_params_req *req,
                    284:                       struct alsa_params_obt *obt, snd_pcm_t **handlep)
                    285: {
                    286:     snd_pcm_t *handle;
                    287:     snd_pcm_hw_params_t *hw_params;
1.1.1.3 ! root      288:     int err;
        !           289:     unsigned int freq, nchannels;
1.1       root      290:     const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
                    291:     unsigned int period_size, buffer_size;
                    292:     snd_pcm_uframes_t obt_buffer_size;
                    293:     const char *typ = in ? "ADC" : "DAC";
                    294: 
                    295:     freq = req->freq;
                    296:     period_size = req->period_size;
                    297:     buffer_size = req->buffer_size;
                    298:     nchannels = req->nchannels;
                    299: 
                    300:     snd_pcm_hw_params_alloca (&hw_params);
                    301: 
                    302:     err = snd_pcm_open (
                    303:         &handle,
                    304:         pcm_name,
                    305:         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
                    306:         SND_PCM_NONBLOCK
                    307:         );
                    308:     if (err < 0) {
                    309:         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
                    310:         return -1;
                    311:     }
                    312: 
                    313:     err = snd_pcm_hw_params_any (handle, hw_params);
                    314:     if (err < 0) {
                    315:         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
                    316:         goto err;
                    317:     }
                    318: 
                    319:     err = snd_pcm_hw_params_set_access (
                    320:         handle,
                    321:         hw_params,
                    322:         SND_PCM_ACCESS_RW_INTERLEAVED
                    323:         );
                    324:     if (err < 0) {
                    325:         alsa_logerr2 (err, typ, "Failed to set access type\n");
                    326:         goto err;
                    327:     }
                    328: 
                    329:     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
                    330:     if (err < 0) {
                    331:         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
                    332:         goto err;
                    333:     }
                    334: 
                    335:     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
                    336:     if (err < 0) {
                    337:         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
                    338:         goto err;
                    339:     }
                    340: 
                    341:     err = snd_pcm_hw_params_set_channels_near (
                    342:         handle,
                    343:         hw_params,
                    344:         &nchannels
                    345:         );
                    346:     if (err < 0) {
                    347:         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
                    348:                       req->nchannels);
                    349:         goto err;
                    350:     }
                    351: 
                    352:     if (nchannels != 1 && nchannels != 2) {
                    353:         alsa_logerr2 (err, typ,
                    354:                       "Can not handle obtained number of channels %d\n",
                    355:                       nchannels);
                    356:         goto err;
                    357:     }
                    358: 
                    359:     if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
                    360:         if (!buffer_size) {
                    361:             buffer_size = DEFAULT_BUFFER_SIZE;
                    362:             period_size= DEFAULT_PERIOD_SIZE;
                    363:         }
                    364:     }
                    365: 
                    366:     if (buffer_size) {
                    367:         if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
                    368:             if (period_size) {
                    369:                 err = snd_pcm_hw_params_set_period_time_near (
                    370:                     handle,
                    371:                     hw_params,
                    372:                     &period_size,
                    373:                     0
                    374:                     );
                    375:                 if (err < 0) {
                    376:                     alsa_logerr2 (err, typ,
                    377:                                   "Failed to set period time %d\n",
                    378:                                   req->period_size);
                    379:                     goto err;
                    380:                 }
                    381:             }
                    382: 
                    383:             err = snd_pcm_hw_params_set_buffer_time_near (
                    384:                 handle,
                    385:                 hw_params,
                    386:                 &buffer_size,
                    387:                 0
                    388:                 );
                    389: 
                    390:             if (err < 0) {
                    391:                 alsa_logerr2 (err, typ,
                    392:                               "Failed to set buffer time %d\n",
                    393:                               req->buffer_size);
                    394:                 goto err;
                    395:             }
                    396:         }
                    397:         else {
                    398:             int dir;
                    399:             snd_pcm_uframes_t minval;
                    400: 
                    401:             if (period_size) {
                    402:                 minval = period_size;
                    403:                 dir = 0;
                    404: 
                    405:                 err = snd_pcm_hw_params_get_period_size_min (
                    406:                     hw_params,
                    407:                     &minval,
                    408:                     &dir
                    409:                     );
                    410:                 if (err < 0) {
                    411:                     alsa_logerr (
                    412:                         err,
                    413:                         "Could not get minmal period size for %s\n",
                    414:                         typ
                    415:                         );
                    416:                 }
                    417:                 else {
                    418:                     if (period_size < minval) {
1.1.1.3 ! root      419:                         if ((in && conf.period_size_in_overridden)
        !           420:                             || (!in && conf.period_size_out_overridden)) {
1.1       root      421:                             dolog ("%s period size(%d) is less "
                    422:                                    "than minmal period size(%ld)\n",
                    423:                                    typ,
                    424:                                    period_size,
                    425:                                    minval);
                    426:                         }
                    427:                         period_size = minval;
                    428:                     }
                    429:                 }
                    430: 
                    431:                 err = snd_pcm_hw_params_set_period_size (
                    432:                     handle,
                    433:                     hw_params,
                    434:                     period_size,
                    435:                     0
                    436:                     );
                    437:                 if (err < 0) {
                    438:                     alsa_logerr2 (err, typ, "Failed to set period size %d\n",
                    439:                                   req->period_size);
                    440:                     goto err;
                    441:                 }
                    442:             }
                    443: 
                    444:             minval = buffer_size;
                    445:             err = snd_pcm_hw_params_get_buffer_size_min (
                    446:                 hw_params,
                    447:                 &minval
                    448:                 );
                    449:             if (err < 0) {
                    450:                 alsa_logerr (err, "Could not get minmal buffer size for %s\n",
                    451:                              typ);
                    452:             }
                    453:             else {
                    454:                 if (buffer_size < minval) {
1.1.1.3 ! root      455:                     if ((in && conf.buffer_size_in_overridden)
        !           456:                         || (!in && conf.buffer_size_out_overridden)) {
1.1       root      457:                         dolog (
                    458:                             "%s buffer size(%d) is less "
                    459:                             "than minimal buffer size(%ld)\n",
                    460:                             typ,
                    461:                             buffer_size,
                    462:                             minval
                    463:                             );
                    464:                     }
                    465:                     buffer_size = minval;
                    466:                 }
                    467:             }
                    468: 
                    469:             err = snd_pcm_hw_params_set_buffer_size (
                    470:                 handle,
                    471:                 hw_params,
                    472:                 buffer_size
                    473:                 );
                    474:             if (err < 0) {
                    475:                 alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
                    476:                               req->buffer_size);
                    477:                 goto err;
                    478:             }
                    479:         }
                    480:     }
                    481:     else {
                    482:         dolog ("warning: Buffer size is not set\n");
                    483:     }
                    484: 
                    485:     err = snd_pcm_hw_params (handle, hw_params);
                    486:     if (err < 0) {
                    487:         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
                    488:         goto err;
                    489:     }
                    490: 
                    491:     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
                    492:     if (err < 0) {
                    493:         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
                    494:         goto err;
                    495:     }
                    496: 
                    497:     err = snd_pcm_prepare (handle);
                    498:     if (err < 0) {
                    499:         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
                    500:         goto err;
                    501:     }
                    502: 
                    503:     if (!in && conf.threshold) {
                    504:         snd_pcm_uframes_t threshold;
                    505:         int bytes_per_sec;
                    506: 
                    507:         bytes_per_sec = freq
                    508:             << (nchannels == 2)
                    509:             << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
                    510: 
                    511:         threshold = (conf.threshold * bytes_per_sec) / 1000;
                    512:         alsa_set_threshold (handle, threshold);
                    513:     }
                    514: 
                    515:     obt->fmt = req->fmt;
                    516:     obt->nchannels = nchannels;
                    517:     obt->freq = freq;
                    518:     obt->samples = obt_buffer_size;
                    519:     *handlep = handle;
                    520: 
                    521: #if defined DEBUG_MISMATCHES || defined DEBUG
                    522:     if (obt->fmt != req->fmt ||
                    523:         obt->nchannels != req->nchannels ||
                    524:         obt->freq != req->freq) {
                    525:         dolog ("Audio paramters mismatch for %s\n", typ);
                    526:         alsa_dump_info (req, obt);
                    527:     }
                    528: #endif
                    529: 
                    530: #ifdef DEBUG
                    531:     alsa_dump_info (req, obt);
                    532: #endif
                    533:     return 0;
                    534: 
                    535:  err:
                    536:     alsa_anal_close (&handle);
                    537:     return -1;
                    538: }
                    539: 
                    540: static int alsa_recover (snd_pcm_t *handle)
                    541: {
                    542:     int err = snd_pcm_prepare (handle);
                    543:     if (err < 0) {
                    544:         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
                    545:         return -1;
                    546:     }
                    547:     return 0;
                    548: }
                    549: 
                    550: static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
                    551: {
                    552:     snd_pcm_sframes_t avail;
                    553: 
                    554:     avail = snd_pcm_avail_update (handle);
                    555:     if (avail < 0) {
                    556:         if (avail == -EPIPE) {
                    557:             if (!alsa_recover (handle)) {
                    558:                 avail = snd_pcm_avail_update (handle);
                    559:             }
                    560:         }
                    561: 
                    562:         if (avail < 0) {
                    563:             alsa_logerr (avail,
                    564:                          "Could not obtain number of available frames\n");
                    565:             return -1;
                    566:         }
                    567:     }
                    568: 
                    569:     return avail;
                    570: }
                    571: 
                    572: static int alsa_run_out (HWVoiceOut *hw)
                    573: {
                    574:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    575:     int rpos, live, decr;
                    576:     int samples;
                    577:     uint8_t *dst;
                    578:     st_sample_t *src;
                    579:     snd_pcm_sframes_t avail;
                    580: 
                    581:     live = audio_pcm_hw_get_live_out (hw);
                    582:     if (!live) {
                    583:         return 0;
                    584:     }
                    585: 
                    586:     avail = alsa_get_avail (alsa->handle);
                    587:     if (avail < 0) {
                    588:         dolog ("Could not get number of available playback frames\n");
                    589:         return 0;
                    590:     }
                    591: 
                    592:     decr = audio_MIN (live, avail);
                    593:     samples = decr;
                    594:     rpos = hw->rpos;
                    595:     while (samples) {
                    596:         int left_till_end_samples = hw->samples - rpos;
                    597:         int len = audio_MIN (samples, left_till_end_samples);
                    598:         snd_pcm_sframes_t written;
                    599: 
                    600:         src = hw->mix_buf + rpos;
                    601:         dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
                    602: 
                    603:         hw->clip (dst, src, len);
                    604: 
                    605:         while (len) {
                    606:             written = snd_pcm_writei (alsa->handle, dst, len);
                    607: 
                    608:             if (written <= 0) {
                    609:                 switch (written) {
                    610:                 case 0:
                    611:                     if (conf.verbose) {
                    612:                         dolog ("Failed to write %d frames (wrote zero)\n", len);
                    613:                     }
                    614:                     goto exit;
                    615: 
                    616:                 case -EPIPE:
                    617:                     if (alsa_recover (alsa->handle)) {
                    618:                         alsa_logerr (written, "Failed to write %d frames\n",
                    619:                                      len);
                    620:                         goto exit;
                    621:                     }
                    622:                     if (conf.verbose) {
                    623:                         dolog ("Recovering from playback xrun\n");
                    624:                     }
                    625:                     continue;
                    626: 
                    627:                 case -EAGAIN:
                    628:                     goto exit;
                    629: 
                    630:                 default:
                    631:                     alsa_logerr (written, "Failed to write %d frames to %p\n",
                    632:                                  len, dst);
                    633:                     goto exit;
                    634:                 }
                    635:             }
                    636: 
                    637:             rpos = (rpos + written) % hw->samples;
                    638:             samples -= written;
                    639:             len -= written;
                    640:             dst = advance (dst, written << hw->info.shift);
                    641:             src += written;
                    642:         }
                    643:     }
                    644: 
                    645:  exit:
                    646:     hw->rpos = rpos;
                    647:     return decr;
                    648: }
                    649: 
                    650: static void alsa_fini_out (HWVoiceOut *hw)
                    651: {
                    652:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    653: 
                    654:     ldebug ("alsa_fini\n");
                    655:     alsa_anal_close (&alsa->handle);
                    656: 
                    657:     if (alsa->pcm_buf) {
                    658:         qemu_free (alsa->pcm_buf);
                    659:         alsa->pcm_buf = NULL;
                    660:     }
                    661: }
                    662: 
                    663: static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
                    664: {
                    665:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    666:     struct alsa_params_req req;
                    667:     struct alsa_params_obt obt;
                    668:     audfmt_e effective_fmt;
                    669:     int endianness;
                    670:     int err;
                    671:     snd_pcm_t *handle;
                    672:     audsettings_t obt_as;
                    673: 
                    674:     req.fmt = aud_to_alsafmt (as->fmt);
                    675:     req.freq = as->freq;
                    676:     req.nchannels = as->nchannels;
                    677:     req.period_size = conf.period_size_out;
                    678:     req.buffer_size = conf.buffer_size_out;
                    679: 
                    680:     if (alsa_open (0, &req, &obt, &handle)) {
                    681:         return -1;
                    682:     }
                    683: 
                    684:     err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    685:     if (err) {
                    686:         alsa_anal_close (&handle);
                    687:         return -1;
                    688:     }
                    689: 
                    690:     obt_as.freq = obt.freq;
                    691:     obt_as.nchannels = obt.nchannels;
                    692:     obt_as.fmt = effective_fmt;
1.1.1.2   root      693:     obt_as.endianness = endianness;
1.1       root      694: 
1.1.1.2   root      695:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      696:     hw->samples = obt.samples;
                    697: 
                    698:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
                    699:     if (!alsa->pcm_buf) {
                    700:         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    701:                hw->samples, 1 << hw->info.shift);
                    702:         alsa_anal_close (&handle);
                    703:         return -1;
                    704:     }
                    705: 
                    706:     alsa->handle = handle;
                    707:     return 0;
                    708: }
                    709: 
                    710: static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
                    711: {
                    712:     int err;
                    713: 
                    714:     if (pause) {
                    715:         err = snd_pcm_drop (handle);
                    716:         if (err < 0) {
                    717:             alsa_logerr (err, "Could not stop %s\n", typ);
                    718:             return -1;
                    719:         }
                    720:     }
                    721:     else {
                    722:         err = snd_pcm_prepare (handle);
                    723:         if (err < 0) {
                    724:             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
                    725:             return -1;
                    726:         }
                    727:     }
                    728: 
                    729:     return 0;
                    730: }
                    731: 
                    732: static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    733: {
                    734:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    735: 
                    736:     switch (cmd) {
                    737:     case VOICE_ENABLE:
                    738:         ldebug ("enabling voice\n");
                    739:         return alsa_voice_ctl (alsa->handle, "playback", 0);
                    740: 
                    741:     case VOICE_DISABLE:
                    742:         ldebug ("disabling voice\n");
                    743:         return alsa_voice_ctl (alsa->handle, "playback", 1);
                    744:     }
                    745: 
                    746:     return -1;
                    747: }
                    748: 
                    749: static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
                    750: {
                    751:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    752:     struct alsa_params_req req;
                    753:     struct alsa_params_obt obt;
                    754:     int endianness;
                    755:     int err;
                    756:     audfmt_e effective_fmt;
                    757:     snd_pcm_t *handle;
                    758:     audsettings_t obt_as;
                    759: 
                    760:     req.fmt = aud_to_alsafmt (as->fmt);
                    761:     req.freq = as->freq;
                    762:     req.nchannels = as->nchannels;
                    763:     req.period_size = conf.period_size_in;
                    764:     req.buffer_size = conf.buffer_size_in;
                    765: 
                    766:     if (alsa_open (1, &req, &obt, &handle)) {
                    767:         return -1;
                    768:     }
                    769: 
                    770:     err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    771:     if (err) {
                    772:         alsa_anal_close (&handle);
                    773:         return -1;
                    774:     }
                    775: 
                    776:     obt_as.freq = obt.freq;
                    777:     obt_as.nchannels = obt.nchannels;
                    778:     obt_as.fmt = effective_fmt;
1.1.1.2   root      779:     obt_as.endianness = endianness;
1.1       root      780: 
1.1.1.2   root      781:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      782:     hw->samples = obt.samples;
                    783: 
                    784:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    785:     if (!alsa->pcm_buf) {
                    786:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    787:                hw->samples, 1 << hw->info.shift);
                    788:         alsa_anal_close (&handle);
                    789:         return -1;
                    790:     }
                    791: 
                    792:     alsa->handle = handle;
                    793:     return 0;
                    794: }
                    795: 
                    796: static void alsa_fini_in (HWVoiceIn *hw)
                    797: {
                    798:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    799: 
                    800:     alsa_anal_close (&alsa->handle);
                    801: 
                    802:     if (alsa->pcm_buf) {
                    803:         qemu_free (alsa->pcm_buf);
                    804:         alsa->pcm_buf = NULL;
                    805:     }
                    806: }
                    807: 
                    808: static int alsa_run_in (HWVoiceIn *hw)
                    809: {
                    810:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    811:     int hwshift = hw->info.shift;
                    812:     int i;
                    813:     int live = audio_pcm_hw_get_live_in (hw);
                    814:     int dead = hw->samples - live;
                    815:     int decr;
                    816:     struct {
                    817:         int add;
                    818:         int len;
                    819:     } bufs[2] = {
                    820:         { hw->wpos, 0 },
                    821:         { 0, 0 }
                    822:     };
                    823:     snd_pcm_sframes_t avail;
                    824:     snd_pcm_uframes_t read_samples = 0;
                    825: 
                    826:     if (!dead) {
                    827:         return 0;
                    828:     }
                    829: 
                    830:     avail = alsa_get_avail (alsa->handle);
                    831:     if (avail < 0) {
                    832:         dolog ("Could not get number of captured frames\n");
                    833:         return 0;
                    834:     }
                    835: 
                    836:     if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
                    837:         avail = hw->samples;
                    838:     }
                    839: 
                    840:     decr = audio_MIN (dead, avail);
                    841:     if (!decr) {
                    842:         return 0;
                    843:     }
                    844: 
                    845:     if (hw->wpos + decr > hw->samples) {
                    846:         bufs[0].len = (hw->samples - hw->wpos);
                    847:         bufs[1].len = (decr - (hw->samples - hw->wpos));
                    848:     }
                    849:     else {
                    850:         bufs[0].len = decr;
                    851:     }
                    852: 
                    853:     for (i = 0; i < 2; ++i) {
                    854:         void *src;
                    855:         st_sample_t *dst;
                    856:         snd_pcm_sframes_t nread;
                    857:         snd_pcm_uframes_t len;
                    858: 
                    859:         len = bufs[i].len;
                    860: 
                    861:         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
                    862:         dst = hw->conv_buf + bufs[i].add;
                    863: 
                    864:         while (len) {
                    865:             nread = snd_pcm_readi (alsa->handle, src, len);
                    866: 
                    867:             if (nread <= 0) {
                    868:                 switch (nread) {
                    869:                 case 0:
                    870:                     if (conf.verbose) {
                    871:                         dolog ("Failed to read %ld frames (read zero)\n", len);
                    872:                     }
                    873:                     goto exit;
                    874: 
                    875:                 case -EPIPE:
                    876:                     if (alsa_recover (alsa->handle)) {
                    877:                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
                    878:                         goto exit;
                    879:                     }
                    880:                     if (conf.verbose) {
                    881:                         dolog ("Recovering from capture xrun\n");
                    882:                     }
                    883:                     continue;
                    884: 
                    885:                 case -EAGAIN:
                    886:                     goto exit;
                    887: 
                    888:                 default:
                    889:                     alsa_logerr (
                    890:                         nread,
                    891:                         "Failed to read %ld frames from %p\n",
                    892:                         len,
                    893:                         src
                    894:                         );
                    895:                     goto exit;
                    896:                 }
                    897:             }
                    898: 
                    899:             hw->conv (dst, src, nread, &nominal_volume);
                    900: 
                    901:             src = advance (src, nread << hwshift);
                    902:             dst += nread;
                    903: 
                    904:             read_samples += nread;
                    905:             len -= nread;
                    906:         }
                    907:     }
                    908: 
                    909:  exit:
                    910:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                    911:     return read_samples;
                    912: }
                    913: 
                    914: static int alsa_read (SWVoiceIn *sw, void *buf, int size)
                    915: {
                    916:     return audio_pcm_sw_read (sw, buf, size);
                    917: }
                    918: 
                    919: static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    920: {
                    921:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    922: 
                    923:     switch (cmd) {
                    924:     case VOICE_ENABLE:
                    925:         ldebug ("enabling voice\n");
                    926:         return alsa_voice_ctl (alsa->handle, "capture", 0);
                    927: 
                    928:     case VOICE_DISABLE:
                    929:         ldebug ("disabling voice\n");
                    930:         return alsa_voice_ctl (alsa->handle, "capture", 1);
                    931:     }
                    932: 
                    933:     return -1;
                    934: }
                    935: 
                    936: static void *alsa_audio_init (void)
                    937: {
                    938:     return &conf;
                    939: }
                    940: 
                    941: static void alsa_audio_fini (void *opaque)
                    942: {
                    943:     (void) opaque;
                    944: }
                    945: 
                    946: static struct audio_option alsa_options[] = {
                    947:     {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
                    948:      "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
                    949:     {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
1.1.1.3 ! root      950:      "DAC period size", &conf.period_size_out_overridden, 0},
1.1       root      951:     {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
1.1.1.3 ! root      952:      "DAC buffer size", &conf.buffer_size_out_overridden, 0},
1.1       root      953: 
                    954:     {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
                    955:      "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
                    956:     {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
1.1.1.3 ! root      957:      "ADC period size", &conf.period_size_in_overridden, 0},
1.1       root      958:     {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
1.1.1.3 ! root      959:      "ADC buffer size", &conf.buffer_size_in_overridden, 0},
1.1       root      960: 
                    961:     {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
                    962:      "(undocumented)", NULL, 0},
                    963: 
                    964:     {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
                    965:      "DAC device name (for instance dmix)", NULL, 0},
                    966: 
                    967:     {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
                    968:      "ADC device name", NULL, 0},
                    969: 
                    970:     {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
                    971:      "Behave in a more verbose way", NULL, 0},
                    972: 
                    973:     {NULL, 0, NULL, NULL, NULL, 0}
                    974: };
                    975: 
                    976: static struct audio_pcm_ops alsa_pcm_ops = {
                    977:     alsa_init_out,
                    978:     alsa_fini_out,
                    979:     alsa_run_out,
                    980:     alsa_write,
                    981:     alsa_ctl_out,
                    982: 
                    983:     alsa_init_in,
                    984:     alsa_fini_in,
                    985:     alsa_run_in,
                    986:     alsa_read,
                    987:     alsa_ctl_in
                    988: };
                    989: 
                    990: struct audio_driver alsa_audio_driver = {
                    991:     INIT_FIELD (name           = ) "alsa",
                    992:     INIT_FIELD (descr          = ) "ALSA http://www.alsa-project.org",
                    993:     INIT_FIELD (options        = ) alsa_options,
                    994:     INIT_FIELD (init           = ) alsa_audio_init,
                    995:     INIT_FIELD (fini           = ) alsa_audio_fini,
                    996:     INIT_FIELD (pcm_ops        = ) &alsa_pcm_ops,
                    997:     INIT_FIELD (can_be_default = ) 1,
                    998:     INIT_FIELD (max_voices_out = ) INT_MAX,
                    999:     INIT_FIELD (max_voices_in  = ) INT_MAX,
                   1000:     INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
                   1001:     INIT_FIELD (voice_size_in  = ) sizeof (ALSAVoiceIn)
                   1002: };

unix.superglobalmegacorp.com

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