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

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

unix.superglobalmegacorp.com

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