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

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

unix.superglobalmegacorp.com

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