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

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
1.1.1.2 ! root       64:     .pcm_name_out = "default",
        !            65:     .pcm_name_in = "default",
1.1       root       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:             rpos = (rpos + written) % hw->samples;
                    610:             samples -= written;
                    611:             len -= written;
                    612:             dst = advance (dst, written << hw->info.shift);
                    613:             src += written;
                    614:         }
                    615:     }
                    616: 
                    617:  exit:
                    618:     hw->rpos = rpos;
                    619:     return decr;
                    620: }
                    621: 
                    622: static void alsa_fini_out (HWVoiceOut *hw)
                    623: {
                    624:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    625: 
                    626:     ldebug ("alsa_fini\n");
                    627:     alsa_anal_close (&alsa->handle);
                    628: 
                    629:     if (alsa->pcm_buf) {
                    630:         qemu_free (alsa->pcm_buf);
                    631:         alsa->pcm_buf = NULL;
                    632:     }
                    633: }
                    634: 
                    635: static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
                    636: {
                    637:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    638:     struct alsa_params_req req;
                    639:     struct alsa_params_obt obt;
                    640:     audfmt_e effective_fmt;
                    641:     int endianness;
                    642:     int err;
                    643:     snd_pcm_t *handle;
                    644:     audsettings_t obt_as;
                    645: 
                    646:     req.fmt = aud_to_alsafmt (as->fmt);
                    647:     req.freq = as->freq;
                    648:     req.nchannels = as->nchannels;
                    649:     req.period_size = conf.period_size_out;
                    650:     req.buffer_size = conf.buffer_size_out;
                    651: 
                    652:     if (alsa_open (0, &req, &obt, &handle)) {
                    653:         return -1;
                    654:     }
                    655: 
                    656:     err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    657:     if (err) {
                    658:         alsa_anal_close (&handle);
                    659:         return -1;
                    660:     }
                    661: 
                    662:     obt_as.freq = obt.freq;
                    663:     obt_as.nchannels = obt.nchannels;
                    664:     obt_as.fmt = effective_fmt;
1.1.1.2 ! root      665:     obt_as.endianness = endianness;
1.1       root      666: 
1.1.1.2 ! root      667:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      668:     hw->samples = obt.samples;
                    669: 
                    670:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
                    671:     if (!alsa->pcm_buf) {
                    672:         dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
                    673:                hw->samples, 1 << hw->info.shift);
                    674:         alsa_anal_close (&handle);
                    675:         return -1;
                    676:     }
                    677: 
                    678:     alsa->handle = handle;
                    679:     return 0;
                    680: }
                    681: 
                    682: static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
                    683: {
                    684:     int err;
                    685: 
                    686:     if (pause) {
                    687:         err = snd_pcm_drop (handle);
                    688:         if (err < 0) {
                    689:             alsa_logerr (err, "Could not stop %s\n", typ);
                    690:             return -1;
                    691:         }
                    692:     }
                    693:     else {
                    694:         err = snd_pcm_prepare (handle);
                    695:         if (err < 0) {
                    696:             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
                    697:             return -1;
                    698:         }
                    699:     }
                    700: 
                    701:     return 0;
                    702: }
                    703: 
                    704: static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    705: {
                    706:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
                    707: 
                    708:     switch (cmd) {
                    709:     case VOICE_ENABLE:
                    710:         ldebug ("enabling voice\n");
                    711:         return alsa_voice_ctl (alsa->handle, "playback", 0);
                    712: 
                    713:     case VOICE_DISABLE:
                    714:         ldebug ("disabling voice\n");
                    715:         return alsa_voice_ctl (alsa->handle, "playback", 1);
                    716:     }
                    717: 
                    718:     return -1;
                    719: }
                    720: 
                    721: static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
                    722: {
                    723:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    724:     struct alsa_params_req req;
                    725:     struct alsa_params_obt obt;
                    726:     int endianness;
                    727:     int err;
                    728:     audfmt_e effective_fmt;
                    729:     snd_pcm_t *handle;
                    730:     audsettings_t obt_as;
                    731: 
                    732:     req.fmt = aud_to_alsafmt (as->fmt);
                    733:     req.freq = as->freq;
                    734:     req.nchannels = as->nchannels;
                    735:     req.period_size = conf.period_size_in;
                    736:     req.buffer_size = conf.buffer_size_in;
                    737: 
                    738:     if (alsa_open (1, &req, &obt, &handle)) {
                    739:         return -1;
                    740:     }
                    741: 
                    742:     err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
                    743:     if (err) {
                    744:         alsa_anal_close (&handle);
                    745:         return -1;
                    746:     }
                    747: 
                    748:     obt_as.freq = obt.freq;
                    749:     obt_as.nchannels = obt.nchannels;
                    750:     obt_as.fmt = effective_fmt;
1.1.1.2 ! root      751:     obt_as.endianness = endianness;
1.1       root      752: 
1.1.1.2 ! root      753:     audio_pcm_init_info (&hw->info, &obt_as);
1.1       root      754:     hw->samples = obt.samples;
                    755: 
                    756:     alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    757:     if (!alsa->pcm_buf) {
                    758:         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                    759:                hw->samples, 1 << hw->info.shift);
                    760:         alsa_anal_close (&handle);
                    761:         return -1;
                    762:     }
                    763: 
                    764:     alsa->handle = handle;
                    765:     return 0;
                    766: }
                    767: 
                    768: static void alsa_fini_in (HWVoiceIn *hw)
                    769: {
                    770:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    771: 
                    772:     alsa_anal_close (&alsa->handle);
                    773: 
                    774:     if (alsa->pcm_buf) {
                    775:         qemu_free (alsa->pcm_buf);
                    776:         alsa->pcm_buf = NULL;
                    777:     }
                    778: }
                    779: 
                    780: static int alsa_run_in (HWVoiceIn *hw)
                    781: {
                    782:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    783:     int hwshift = hw->info.shift;
                    784:     int i;
                    785:     int live = audio_pcm_hw_get_live_in (hw);
                    786:     int dead = hw->samples - live;
                    787:     int decr;
                    788:     struct {
                    789:         int add;
                    790:         int len;
                    791:     } bufs[2] = {
                    792:         { hw->wpos, 0 },
                    793:         { 0, 0 }
                    794:     };
                    795:     snd_pcm_sframes_t avail;
                    796:     snd_pcm_uframes_t read_samples = 0;
                    797: 
                    798:     if (!dead) {
                    799:         return 0;
                    800:     }
                    801: 
                    802:     avail = alsa_get_avail (alsa->handle);
                    803:     if (avail < 0) {
                    804:         dolog ("Could not get number of captured frames\n");
                    805:         return 0;
                    806:     }
                    807: 
                    808:     if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
                    809:         avail = hw->samples;
                    810:     }
                    811: 
                    812:     decr = audio_MIN (dead, avail);
                    813:     if (!decr) {
                    814:         return 0;
                    815:     }
                    816: 
                    817:     if (hw->wpos + decr > hw->samples) {
                    818:         bufs[0].len = (hw->samples - hw->wpos);
                    819:         bufs[1].len = (decr - (hw->samples - hw->wpos));
                    820:     }
                    821:     else {
                    822:         bufs[0].len = decr;
                    823:     }
                    824: 
                    825:     for (i = 0; i < 2; ++i) {
                    826:         void *src;
                    827:         st_sample_t *dst;
                    828:         snd_pcm_sframes_t nread;
                    829:         snd_pcm_uframes_t len;
                    830: 
                    831:         len = bufs[i].len;
                    832: 
                    833:         src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
                    834:         dst = hw->conv_buf + bufs[i].add;
                    835: 
                    836:         while (len) {
                    837:             nread = snd_pcm_readi (alsa->handle, src, len);
                    838: 
                    839:             if (nread <= 0) {
                    840:                 switch (nread) {
                    841:                 case 0:
                    842:                     if (conf.verbose) {
                    843:                         dolog ("Failed to read %ld frames (read zero)\n", len);
                    844:                     }
                    845:                     goto exit;
                    846: 
                    847:                 case -EPIPE:
                    848:                     if (alsa_recover (alsa->handle)) {
                    849:                         alsa_logerr (nread, "Failed to read %ld frames\n", len);
                    850:                         goto exit;
                    851:                     }
                    852:                     if (conf.verbose) {
                    853:                         dolog ("Recovering from capture xrun\n");
                    854:                     }
                    855:                     continue;
                    856: 
                    857:                 case -EAGAIN:
                    858:                     goto exit;
                    859: 
                    860:                 default:
                    861:                     alsa_logerr (
                    862:                         nread,
                    863:                         "Failed to read %ld frames from %p\n",
                    864:                         len,
                    865:                         src
                    866:                         );
                    867:                     goto exit;
                    868:                 }
                    869:             }
                    870: 
                    871:             hw->conv (dst, src, nread, &nominal_volume);
                    872: 
                    873:             src = advance (src, nread << hwshift);
                    874:             dst += nread;
                    875: 
                    876:             read_samples += nread;
                    877:             len -= nread;
                    878:         }
                    879:     }
                    880: 
                    881:  exit:
                    882:     hw->wpos = (hw->wpos + read_samples) % hw->samples;
                    883:     return read_samples;
                    884: }
                    885: 
                    886: static int alsa_read (SWVoiceIn *sw, void *buf, int size)
                    887: {
                    888:     return audio_pcm_sw_read (sw, buf, size);
                    889: }
                    890: 
                    891: static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    892: {
                    893:     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
                    894: 
                    895:     switch (cmd) {
                    896:     case VOICE_ENABLE:
                    897:         ldebug ("enabling voice\n");
                    898:         return alsa_voice_ctl (alsa->handle, "capture", 0);
                    899: 
                    900:     case VOICE_DISABLE:
                    901:         ldebug ("disabling voice\n");
                    902:         return alsa_voice_ctl (alsa->handle, "capture", 1);
                    903:     }
                    904: 
                    905:     return -1;
                    906: }
                    907: 
                    908: static void *alsa_audio_init (void)
                    909: {
                    910:     return &conf;
                    911: }
                    912: 
                    913: static void alsa_audio_fini (void *opaque)
                    914: {
                    915:     (void) opaque;
                    916: }
                    917: 
                    918: static struct audio_option alsa_options[] = {
                    919:     {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
                    920:      "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
                    921:     {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
                    922:      "DAC period size", &conf.period_size_out_overriden, 0},
                    923:     {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
                    924:      "DAC buffer size", &conf.buffer_size_out_overriden, 0},
                    925: 
                    926:     {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
                    927:      "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
                    928:     {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
                    929:      "ADC period size", &conf.period_size_in_overriden, 0},
                    930:     {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
                    931:      "ADC buffer size", &conf.buffer_size_in_overriden, 0},
                    932: 
                    933:     {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
                    934:      "(undocumented)", NULL, 0},
                    935: 
                    936:     {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
                    937:      "DAC device name (for instance dmix)", NULL, 0},
                    938: 
                    939:     {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
                    940:      "ADC device name", NULL, 0},
                    941: 
                    942:     {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
                    943:      "Behave in a more verbose way", NULL, 0},
                    944: 
                    945:     {NULL, 0, NULL, NULL, NULL, 0}
                    946: };
                    947: 
                    948: static struct audio_pcm_ops alsa_pcm_ops = {
                    949:     alsa_init_out,
                    950:     alsa_fini_out,
                    951:     alsa_run_out,
                    952:     alsa_write,
                    953:     alsa_ctl_out,
                    954: 
                    955:     alsa_init_in,
                    956:     alsa_fini_in,
                    957:     alsa_run_in,
                    958:     alsa_read,
                    959:     alsa_ctl_in
                    960: };
                    961: 
                    962: struct audio_driver alsa_audio_driver = {
                    963:     INIT_FIELD (name           = ) "alsa",
                    964:     INIT_FIELD (descr          = ) "ALSA http://www.alsa-project.org",
                    965:     INIT_FIELD (options        = ) alsa_options,
                    966:     INIT_FIELD (init           = ) alsa_audio_init,
                    967:     INIT_FIELD (fini           = ) alsa_audio_fini,
                    968:     INIT_FIELD (pcm_ops        = ) &alsa_pcm_ops,
                    969:     INIT_FIELD (can_be_default = ) 1,
                    970:     INIT_FIELD (max_voices_out = ) INT_MAX,
                    971:     INIT_FIELD (max_voices_in  = ) INT_MAX,
                    972:     INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
                    973:     INIT_FIELD (voice_size_in  = ) sizeof (ALSAVoiceIn)
                    974: };

unix.superglobalmegacorp.com

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