(linenum→info "unix/slp.c:2238")

qemu/0.9.1/audio/alsaaudio.c

    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 "qemu-common.h"
   26: #include "audio.h"
   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: 
   54:     int buffer_size_in_overridden;
   55:     int period_size_in_overridden;
   56: 
   57:     int buffer_size_out_overridden;
   58:     int period_size_out_overridden;
   59:     int verbose;
   60: } conf = {
   61: #define DEFAULT_BUFFER_SIZE 1024
   62: #define DEFAULT_PERIOD_SIZE 256
   63: #ifdef HIGH_LATENCY
   64:     .size_in_usec_in = 1,
   65:     .size_in_usec_out = 1,
   66: #endif
   67:     .pcm_name_out = "default",
   68:     .pcm_name_in = "default",
   69: #ifdef HIGH_LATENCY
   70:     .buffer_size_in = 400000,
   71:     .period_size_in = 400000 / 4,
   72:     .buffer_size_out = 400000,
   73:     .period_size_out = 400000 / 4,
   74: #else
   75:     .buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
   76:     .period_size_in = DEFAULT_PERIOD_SIZE * 4,
   77:     .buffer_size_out = DEFAULT_BUFFER_SIZE,
   78:     .period_size_out = DEFAULT_PERIOD_SIZE,
   79:     .buffer_size_in_overridden = 0,
   80:     .buffer_size_out_overridden = 0,
   81:     .period_size_in_overridden = 0,
   82:     .period_size_out_overridden = 0,
   83: #endif
   84:     .threshold = 0,
   85:     .verbose = 0
   86: };
   87: 
   88: struct alsa_params_req {
   89:     unsigned int freq;
   90:     audfmt_e fmt;
   91:     unsigned int nchannels;
   92:     unsigned int buffer_size;
   93:     unsigned int period_size;
   94: };
   95: 
   96: struct alsa_params_obt {
   97:     int freq;
   98:     audfmt_e fmt;
   99:     int nchannels;
  100:     snd_pcm_uframes_t samples;
  101: };
  102: 
  103: static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
  104: {
  105:     va_list ap;
  106: 
  107:     va_start (ap, fmt);
  108:     AUD_vlog (AUDIO_CAP, fmt, ap);
  109:     va_end (ap);
  110: 
  111:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
  112: }
  113: 
  114: static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
  115:     int err,
  116:     const char *typ,
  117:     const char *fmt,
  118:     ...
  119:     )
  120: {
  121:     va_list ap;
  122: 
  123:     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
  124: 
  125:     va_start (ap, fmt);
  126:     AUD_vlog (AUDIO_CAP, fmt, ap);
  127:     va_end (ap);
  128: 
  129:     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
  130: }
  131: 
  132: static void alsa_anal_close (snd_pcm_t **handlep)
  133: {
  134:     int err = snd_pcm_close (*handlep);
  135:     if (err) {
  136:         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
  137:     }
  138:     *handlep = NULL;
  139: }
  140: 
  141: static int alsa_write (SWVoiceOut *sw, void *buf, int len)
  142: {
  143:     return audio_pcm_sw_write (sw, buf, len);
  144: }
  145: 
  146: static int aud_to_alsafmt (audfmt_e fmt)
  147: {
  148:     switch (fmt) {
  149:     case AUD_FMT_S8:
  150:         return SND_PCM_FORMAT_S8;
  151: 
  152:     case AUD_FMT_U8:
  153:         return SND_PCM_FORMAT_U8;
  154: 
  155:     case AUD_FMT_S16:
  156:         return SND_PCM_FORMAT_S16_LE;
  157: 
  158:     case AUD_FMT_U16:
  159:         return SND_PCM_FORMAT_U16_LE;
  160: 
  161:     case AUD_FMT_S32:
  162:         return SND_PCM_FORMAT_S32_LE;
  163: 
  164:     case AUD_FMT_U32:
  165:         return SND_PCM_FORMAT_U32_LE;
  166: 
  167:     default:
  168:         dolog ("Internal logic error: Bad audio format %d\n", fmt);
  169: #ifdef DEBUG_AUDIO
  170:         abort ();
  171: #endif
  172:         return SND_PCM_FORMAT_U8;
  173:     }
  174: }
  175: 
  176: static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
  177: {
  178:     switch (alsafmt) {
  179:     case SND_PCM_FORMAT_S8:
  180:         *endianness = 0;
  181:         *fmt = AUD_FMT_S8;
  182:         break;
  183: 
  184:     case SND_PCM_FORMAT_U8:
  185:         *endianness = 0;
  186:         *fmt = AUD_FMT_U8;
  187:         break;
  188: 
  189:     case SND_PCM_FORMAT_S16_LE:
  190:         *endianness = 0;
  191:         *fmt = AUD_FMT_S16;
  192:         break;
  193: 
  194:     case SND_PCM_FORMAT_U16_LE:
  195:         *endianness = 0;
  196:         *fmt = AUD_FMT_U16;
  197:         break;
  198: 
  199:     case SND_PCM_FORMAT_S16_BE:
  200:         *endianness = 1;
  201:         *fmt = AUD_FMT_S16;
  202:         break;
  203: 
  204:     case SND_PCM_FORMAT_U16_BE:
  205:         *endianness = 1;
  206:         *fmt = AUD_FMT_U16;
  207:         break;
  208: 
  209:     case SND_PCM_FORMAT_S32_LE:
  210:         *endianness = 0;
  211:         *fmt = AUD_FMT_S32;
  212:         break;
  213: 
  214:     case SND_PCM_FORMAT_U32_LE:
  215:         *endianness = 0;
  216:         *fmt = AUD_FMT_U32;
  217:         break;
  218: 
  219:     case SND_PCM_FORMAT_S32_BE:
  220:         *endianness = 1;
  221:         *fmt = AUD_FMT_S32;
  222:         break;
  223: 
  224:     case SND_PCM_FORMAT_U32_BE:
  225:         *endianness = 1;
  226:         *fmt = AUD_FMT_U32;
  227:         break;
  228: 
  229:     default:
  230:         dolog ("Unrecognized audio format %d\n", alsafmt);
  231:         return -1;
  232:     }
  233: 
  234:     return 0;
  235: }
  236: 
  237: #if defined DEBUG_MISMATCHES || defined DEBUG
  238: static void alsa_dump_info (struct alsa_params_req *req,
  239:                             struct alsa_params_obt *obt)
  240: {
  241:     dolog ("parameter | requested value | obtained value\n");
  242:     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
  243:     dolog ("channels  |      %10d |     %10d\n",
  244:            req->nchannels, obt->nchannels);
  245:     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
  246:     dolog ("============================================\n");
  247:     dolog ("requested: buffer size %d period size %d\n",
  248:            req->buffer_size, req->period_size);
  249:     dolog ("obtained: samples %ld\n", obt->samples);
  250: }
  251: #endif
  252: 
  253: static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
  254: {
  255:     int err;
  256:     snd_pcm_sw_params_t *sw_params;
  257: 
  258:     snd_pcm_sw_params_alloca (&sw_params);
  259: 
  260:     err = snd_pcm_sw_params_current (handle, sw_params);
  261:     if (err < 0) {
  262:         dolog ("Could not fully initialize DAC\n");
  263:         alsa_logerr (err, "Failed to get current software parameters\n");
  264:         return;
  265:     }
  266: 
  267:     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
  268:     if (err < 0) {
  269:         dolog ("Could not fully initialize DAC\n");
  270:         alsa_logerr (err, "Failed to set software threshold to %ld\n",
  271:                      threshold);
  272:         return;
  273:     }
  274: 
  275:     err = snd_pcm_sw_params (handle, sw_params);
  276:     if (err < 0) {
  277:         dolog ("Could not fully initialize DAC\n");
  278:         alsa_logerr (err, "Failed to set software parameters\n");
  279:         return;
  280:     }
  281: }
  282: 
  283: static int alsa_open (int in, struct alsa_params_req *req,
  284:                       struct alsa_params_obt *obt, snd_pcm_t **handlep)
  285: {
  286:     snd_pcm_t *handle;
  287:     snd_pcm_hw_params_t *hw_params;
  288:     int err;
  289:     unsigned int freq, nchannels;
  290:     const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
  291:     unsigned int period_size, buffer_size;
  292:     snd_pcm_uframes_t obt_buffer_size;
  293:     const char *typ = in ? "ADC" : "DAC";
  294: 
  295:     freq = req->freq;
  296:     period_size = req->period_size;
  297:     buffer_size = req->buffer_size;
  298:     nchannels = req->nchannels;
  299: 
  300:     snd_pcm_hw_params_alloca (&hw_params);
  301: 
  302:     err = snd_pcm_open (
  303:         &handle,
  304:         pcm_name,
  305:         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
  306:         SND_PCM_NONBLOCK
  307:         );
  308:     if (err < 0) {
  309:         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
  310:         return -1;
  311:     }
  312: 
  313:     err = snd_pcm_hw_params_any (handle, hw_params);
  314:     if (err < 0) {
  315:         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
  316:         goto err;
  317:     }
  318: 
  319:     err = snd_pcm_hw_params_set_access (
  320:         handle,
  321:         hw_params,
  322:         SND_PCM_ACCESS_RW_INTERLEAVED
  323:         );
  324:     if (err < 0) {
  325:         alsa_logerr2 (err, typ, "Failed to set access type\n");
  326:         goto err;
  327:     }
  328: 
  329:     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
  330:     if (err < 0) {
  331:         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
  332:         goto err;
  333:     }
  334: 
  335:     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
  336:     if (err < 0) {
  337:         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
  338:         goto err;
  339:     }
  340: 
  341:     err = snd_pcm_hw_params_set_channels_near (
  342:         handle,
  343:         hw_params,
  344:         &nchannels
  345:         );
  346:     if (err < 0) {
  347:         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
  348:                       req->nchannels);
  349:         goto err;
  350:     }
  351: 
  352:     if (nchannels != 1 && nchannels != 2) {
  353:         alsa_logerr2 (err, typ,
  354:                       "Can not handle obtained number of channels %d\n",
  355:                       nchannels);
  356:         goto err;
  357:     }
  358: 
  359:     if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
  360:         if (!buffer_size) {
  361:             buffer_size = DEFAULT_BUFFER_SIZE;
  362:             period_size= DEFAULT_PERIOD_SIZE;
  363:         }
  364:     }
  365: 
  366:     if (buffer_size) {
  367:         if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
  368:             if (period_size) {
  369:                 err = snd_pcm_hw_params_set_period_time_near (
  370:                     handle,
  371:                     hw_params,
  372:                     &period_size,
  373:                     0
  374:                     );
  375:                 if (err < 0) {
  376:                     alsa_logerr2 (err, typ,
  377:                                   "Failed to set period time %d\n",
  378:                                   req->period_size);
  379:                     goto err;
  380:                 }
  381:             }
  382: 
  383:             err = snd_pcm_hw_params_set_buffer_time_near (
  384:                 handle,
  385:                 hw_params,
  386:                 &buffer_size,
  387:                 0
  388:                 );
  389: 
  390:             if (err < 0) {
  391:                 alsa_logerr2 (err, typ,
  392:                               "Failed to set buffer time %d\n",
  393:                               req->buffer_size);
  394:                 goto err;
  395:             }
  396:         }
  397:         else {
  398:             int dir;
  399:             snd_pcm_uframes_t minval;
  400: 
  401:             if (period_size) {
  402:                 minval = period_size;
  403:                 dir = 0;
  404: 
  405:                 err = snd_pcm_hw_params_get_period_size_min (
  406:                     hw_params,
  407:                     &minval,
  408:                     &dir
  409:                     );
  410:                 if (err < 0) {
  411:                     alsa_logerr (
  412:                         err,
  413:                         "Could not get minmal period size for %s\n",
  414:                         typ
  415:                         );
  416:                 }
  417:                 else {
  418:                     if (period_size < minval) {
  419:                         if ((in && conf.period_size_in_overridden)
  420:                             || (!in && conf.period_size_out_overridden)) {
  421:                             dolog ("%s period size(%d) is less "
  422:                                    "than minmal period size(%ld)\n",
  423:                                    typ,
  424:                                    period_size,
  425:                                    minval);
  426:                         }
  427:                         period_size = minval;
  428:                     }
  429:                 }
  430: 
  431:                 err = snd_pcm_hw_params_set_period_size (
  432:                     handle,
  433:                     hw_params,
  434:                     period_size,
  435:                     0
  436:                     );
  437:                 if (err < 0) {
  438:                     alsa_logerr2 (err, typ, "Failed to set period size %d\n",
  439:                                   req->period_size);
  440:                     goto err;
  441:                 }
  442:             }
  443: 
  444:             minval = buffer_size;
  445:             err = snd_pcm_hw_params_get_buffer_size_min (
  446:                 hw_params,
  447:                 &minval
  448:                 );
  449:             if (err < 0) {
  450:                 alsa_logerr (err, "Could not get minmal buffer size for %s\n",
  451:                              typ);
  452:             }
  453:             else {
  454:                 if (buffer_size < minval) {
  455:                     if ((in && conf.buffer_size_in_overridden)
  456:                         || (!in && conf.buffer_size_out_overridden)) {
  457:                         dolog (
  458:                             "%s buffer size(%d) is less "
  459:                             "than minimal buffer size(%ld)\n",
  460:                             typ,
  461:                             buffer_size,
  462:                             minval
  463:                             );
  464:                     }
  465:                     buffer_size = minval;
  466:                 }
  467:             }
  468: 
  469:             err = snd_pcm_hw_params_set_buffer_size (
  470:                 handle,
  471:                 hw_params,
  472:                 buffer_size
  473:                 );
  474:             if (err < 0) {
  475:                 alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
  476:                               req->buffer_size);
  477:                 goto err;
  478:             }
  479:         }
  480:     }
  481:     else {
  482:         dolog ("warning: Buffer size is not set\n");
  483:     }
  484: 
  485:     err = snd_pcm_hw_params (handle, hw_params);
  486:     if (err < 0) {
  487:         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
  488:         goto err;
  489:     }
  490: 
  491:     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
  492:     if (err < 0) {
  493:         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
  494:         goto err;
  495:     }
  496: 
  497:     err = snd_pcm_prepare (handle);
  498:     if (err < 0) {
  499:         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
  500:         goto err;
  501:     }
  502: 
  503:     if (!in && conf.threshold) {
  504:         snd_pcm_uframes_t threshold;
  505:         int bytes_per_sec;
  506: 
  507:         bytes_per_sec = freq
  508:             << (nchannels == 2)
  509:             << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
  510: 
  511:         threshold = (conf.threshold * bytes_per_sec) / 1000;
  512:         alsa_set_threshold (handle, threshold);
  513:     }
  514: 
  515:     obt->fmt = req->fmt;
  516:     obt->nchannels = nchannels;
  517:     obt->freq = freq;
  518:     obt->samples = obt_buffer_size;
  519:     *handlep = handle;
  520: 
  521: #if defined DEBUG_MISMATCHES || defined DEBUG
  522:     if (obt->fmt != req->fmt ||
  523:         obt->nchannels != req->nchannels ||
  524:         obt->freq != req->freq) {
  525:         dolog ("Audio paramters mismatch for %s\n", typ);
  526:         alsa_dump_info (req, obt);
  527:     }
  528: #endif
  529: 
  530: #ifdef DEBUG
  531:     alsa_dump_info (req, obt);
  532: #endif
  533:     return 0;
  534: 
  535:  err:
  536:     alsa_anal_close (&handle);
  537:     return -1;
  538: }
  539: 
  540: static int alsa_recover (snd_pcm_t *handle)
  541: {
  542:     int err = snd_pcm_prepare (handle);
  543:     if (err < 0) {
  544:         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
  545:         return -1;
  546:     }
  547:     return 0;
  548: }
  549: 
  550: static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
  551: {
  552:     snd_pcm_sframes_t avail;
  553: 
  554:     avail = snd_pcm_avail_update (handle);
  555:     if (avail < 0) {
  556:         if (avail == -EPIPE) {
  557:             if (!alsa_recover (handle)) {
  558:                 avail = snd_pcm_avail_update (handle);
  559:             }
  560:         }
  561: 
  562:         if (avail < 0) {
  563:             alsa_logerr (avail,
  564:                          "Could not obtain number of available frames\n");
  565:             return -1;
  566:         }
  567:     }
  568: 
  569:     return avail;
  570: }
  571: 
  572: static int alsa_run_out (HWVoiceOut *hw)
  573: {
  574:     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
  575:     int rpos, live, decr;
  576:     int samples;
  577:     uint8_t *dst;
  578:     st_sample_t *src;
  579:     snd_pcm_sframes_t avail;
  580: 
  581:     live = audio_pcm_hw_get_live_out (hw);
  582:     if (!live) {
  583:         return 0;
  584:     }
  585: 
  586:     avail = alsa_get_avail (alsa->handle);
  587:     if (avail < 0) {
  588:         dolog ("Could not get number of available playback frames\n");
  589:         return 0;
  590:     }
  591: 
  592:     decr = audio_MIN (live, avail);
  593:     samples = decr;
  594:     rpos = hw->rpos;
  595:     while (samples) {
  596:         int left_till_end_samples = hw->samples - rpos;
  597:         int len = audio_MIN (samples, left_till_end_samples);
  598:         snd_pcm_sframes_t written;
  599: 
  600:         src = hw->mix_buf + rpos;
  601:         dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
  602: 
  603:         hw->clip (dst, src, len);
  604: 
  605:         while (len) {
  606:             written = snd_pcm_writei (alsa->handle, dst, len);
  607: 
  608:             if (written <= 0) {
  609:                 switch (written) {