qemu/audio/alsaaudio.c
<<
>>
Prefs
   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 "qemu/osdep.h"
  25#include <alsa/asoundlib.h>
  26#include "qemu-common.h"
  27#include "qemu/main-loop.h"
  28#include "audio.h"
  29#include "trace.h"
  30
  31#if QEMU_GNUC_PREREQ(4, 3)
  32#pragma GCC diagnostic ignored "-Waddress"
  33#endif
  34
  35#define AUDIO_CAP "alsa"
  36#include "audio_int.h"
  37
  38typedef struct ALSAConf {
  39    int size_in_usec_in;
  40    int size_in_usec_out;
  41    const char *pcm_name_in;
  42    const char *pcm_name_out;
  43    unsigned int buffer_size_in;
  44    unsigned int period_size_in;
  45    unsigned int buffer_size_out;
  46    unsigned int period_size_out;
  47    unsigned int threshold;
  48
  49    int buffer_size_in_overridden;
  50    int period_size_in_overridden;
  51
  52    int buffer_size_out_overridden;
  53    int period_size_out_overridden;
  54} ALSAConf;
  55
  56struct pollhlp {
  57    snd_pcm_t *handle;
  58    struct pollfd *pfds;
  59    ALSAConf *conf;
  60    int count;
  61    int mask;
  62};
  63
  64typedef struct ALSAVoiceOut {
  65    HWVoiceOut hw;
  66    int wpos;
  67    int pending;
  68    void *pcm_buf;
  69    snd_pcm_t *handle;
  70    struct pollhlp pollhlp;
  71} ALSAVoiceOut;
  72
  73typedef struct ALSAVoiceIn {
  74    HWVoiceIn hw;
  75    snd_pcm_t *handle;
  76    void *pcm_buf;
  77    struct pollhlp pollhlp;
  78} ALSAVoiceIn;
  79
  80struct alsa_params_req {
  81    int freq;
  82    snd_pcm_format_t fmt;
  83    int nchannels;
  84    int size_in_usec;
  85    int override_mask;
  86    unsigned int buffer_size;
  87    unsigned int period_size;
  88};
  89
  90struct alsa_params_obt {
  91    int freq;
  92    audfmt_e fmt;
  93    int endianness;
  94    int nchannels;
  95    snd_pcm_uframes_t samples;
  96};
  97
  98static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
  99{
 100    va_list ap;
 101
 102    va_start (ap, fmt);
 103    AUD_vlog (AUDIO_CAP, fmt, ap);
 104    va_end (ap);
 105
 106    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
 107}
 108
 109static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
 110    int err,
 111    const char *typ,
 112    const char *fmt,
 113    ...
 114    )
 115{
 116    va_list ap;
 117
 118    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
 119
 120    va_start (ap, fmt);
 121    AUD_vlog (AUDIO_CAP, fmt, ap);
 122    va_end (ap);
 123
 124    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
 125}
 126
 127static void alsa_fini_poll (struct pollhlp *hlp)
 128{
 129    int i;
 130    struct pollfd *pfds = hlp->pfds;
 131
 132    if (pfds) {
 133        for (i = 0; i < hlp->count; ++i) {
 134            qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
 135        }
 136        g_free (pfds);
 137    }
 138    hlp->pfds = NULL;
 139    hlp->count = 0;
 140    hlp->handle = NULL;
 141}
 142
 143static void alsa_anal_close1 (snd_pcm_t **handlep)
 144{
 145    int err = snd_pcm_close (*handlep);
 146    if (err) {
 147        alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
 148    }
 149    *handlep = NULL;
 150}
 151
 152static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
 153{
 154    alsa_fini_poll (hlp);
 155    alsa_anal_close1 (handlep);
 156}
 157
 158static int alsa_recover (snd_pcm_t *handle)
 159{
 160    int err = snd_pcm_prepare (handle);
 161    if (err < 0) {
 162        alsa_logerr (err, "Failed to prepare handle %p\n", handle);
 163        return -1;
 164    }
 165    return 0;
 166}
 167
 168static int alsa_resume (snd_pcm_t *handle)
 169{
 170    int err = snd_pcm_resume (handle);
 171    if (err < 0) {
 172        alsa_logerr (err, "Failed to resume handle %p\n", handle);
 173        return -1;
 174    }
 175    return 0;
 176}
 177
 178static void alsa_poll_handler (void *opaque)
 179{
 180    int err, count;
 181    snd_pcm_state_t state;
 182    struct pollhlp *hlp = opaque;
 183    unsigned short revents;
 184
 185    count = poll (hlp->pfds, hlp->count, 0);
 186    if (count < 0) {
 187        dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
 188        return;
 189    }
 190
 191    if (!count) {
 192        return;
 193    }
 194
 195    /* XXX: ALSA example uses initial count, not the one returned by
 196       poll, correct? */
 197    err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
 198                                            hlp->count, &revents);
 199    if (err < 0) {
 200        alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
 201        return;
 202    }
 203
 204    if (!(revents & hlp->mask)) {
 205        trace_alsa_revents(revents);
 206        return;
 207    }
 208
 209    state = snd_pcm_state (hlp->handle);
 210    switch (state) {
 211    case SND_PCM_STATE_SETUP:
 212        alsa_recover (hlp->handle);
 213        break;
 214
 215    case SND_PCM_STATE_XRUN:
 216        alsa_recover (hlp->handle);
 217        break;
 218
 219    case SND_PCM_STATE_SUSPENDED:
 220        alsa_resume (hlp->handle);
 221        break;
 222
 223    case SND_PCM_STATE_PREPARED:
 224        audio_run ("alsa run (prepared)");
 225        break;
 226
 227    case SND_PCM_STATE_RUNNING:
 228        audio_run ("alsa run (running)");
 229        break;
 230
 231    default:
 232        dolog ("Unexpected state %d\n", state);
 233    }
 234}
 235
 236static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
 237{
 238    int i, count, err;
 239    struct pollfd *pfds;
 240
 241    count = snd_pcm_poll_descriptors_count (handle);
 242    if (count <= 0) {
 243        dolog ("Could not initialize poll mode\n"
 244               "Invalid number of poll descriptors %d\n", count);
 245        return -1;
 246    }
 247
 248    pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
 249    if (!pfds) {
 250        dolog ("Could not initialize poll mode\n");
 251        return -1;
 252    }
 253
 254    err = snd_pcm_poll_descriptors (handle, pfds, count);
 255    if (err < 0) {
 256        alsa_logerr (err, "Could not initialize poll mode\n"
 257                     "Could not obtain poll descriptors\n");
 258        g_free (pfds);
 259        return -1;
 260    }
 261
 262    for (i = 0; i < count; ++i) {
 263        if (pfds[i].events & POLLIN) {
 264            qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp);
 265        }
 266        if (pfds[i].events & POLLOUT) {
 267            trace_alsa_pollout(i, pfds[i].fd);
 268            qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp);
 269        }
 270        trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err);
 271
 272    }
 273    hlp->pfds = pfds;
 274    hlp->count = count;
 275    hlp->handle = handle;
 276    hlp->mask = mask;
 277    return 0;
 278}
 279
 280static int alsa_poll_out (HWVoiceOut *hw)
 281{
 282    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 283
 284    return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
 285}
 286
 287static int alsa_poll_in (HWVoiceIn *hw)
 288{
 289    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
 290
 291    return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
 292}
 293
 294static int alsa_write (SWVoiceOut *sw, void *buf, int len)
 295{
 296    return audio_pcm_sw_write (sw, buf, len);
 297}
 298
 299static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)
 300{
 301    switch (fmt) {
 302    case AUD_FMT_S8:
 303        return SND_PCM_FORMAT_S8;
 304
 305    case AUD_FMT_U8:
 306        return SND_PCM_FORMAT_U8;
 307
 308    case AUD_FMT_S16:
 309        if (endianness) {
 310            return SND_PCM_FORMAT_S16_BE;
 311        }
 312        else {
 313            return SND_PCM_FORMAT_S16_LE;
 314        }
 315
 316    case AUD_FMT_U16:
 317        if (endianness) {
 318            return SND_PCM_FORMAT_U16_BE;
 319        }
 320        else {
 321            return SND_PCM_FORMAT_U16_LE;
 322        }
 323
 324    case AUD_FMT_S32:
 325        if (endianness) {
 326            return SND_PCM_FORMAT_S32_BE;
 327        }
 328        else {
 329            return SND_PCM_FORMAT_S32_LE;
 330        }
 331
 332    case AUD_FMT_U32:
 333        if (endianness) {
 334            return SND_PCM_FORMAT_U32_BE;
 335        }
 336        else {
 337            return SND_PCM_FORMAT_U32_LE;
 338        }
 339
 340    default:
 341        dolog ("Internal logic error: Bad audio format %d\n", fmt);
 342#ifdef DEBUG_AUDIO
 343        abort ();
 344#endif
 345        return SND_PCM_FORMAT_U8;
 346    }
 347}
 348
 349static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt,
 350                           int *endianness)
 351{
 352    switch (alsafmt) {
 353    case SND_PCM_FORMAT_S8:
 354        *endianness = 0;
 355        *fmt = AUD_FMT_S8;
 356        break;
 357
 358    case SND_PCM_FORMAT_U8:
 359        *endianness = 0;
 360        *fmt = AUD_FMT_U8;
 361        break;
 362
 363    case SND_PCM_FORMAT_S16_LE:
 364        *endianness = 0;
 365        *fmt = AUD_FMT_S16;
 366        break;
 367
 368    case SND_PCM_FORMAT_U16_LE:
 369        *endianness = 0;
 370        *fmt = AUD_FMT_U16;
 371        break;
 372
 373    case SND_PCM_FORMAT_S16_BE:
 374        *endianness = 1;
 375        *fmt = AUD_FMT_S16;
 376        break;
 377
 378    case SND_PCM_FORMAT_U16_BE:
 379        *endianness = 1;
 380        *fmt = AUD_FMT_U16;
 381        break;
 382
 383    case SND_PCM_FORMAT_S32_LE:
 384        *endianness = 0;
 385        *fmt = AUD_FMT_S32;
 386        break;
 387
 388    case SND_PCM_FORMAT_U32_LE:
 389        *endianness = 0;
 390        *fmt = AUD_FMT_U32;
 391        break;
 392
 393    case SND_PCM_FORMAT_S32_BE:
 394        *endianness = 1;
 395        *fmt = AUD_FMT_S32;
 396        break;
 397
 398    case SND_PCM_FORMAT_U32_BE:
 399        *endianness = 1;
 400        *fmt = AUD_FMT_U32;
 401        break;
 402
 403    default:
 404        dolog ("Unrecognized audio format %d\n", alsafmt);
 405        return -1;
 406    }
 407
 408    return 0;
 409}
 410
 411static void alsa_dump_info (struct alsa_params_req *req,
 412                            struct alsa_params_obt *obt,
 413                            snd_pcm_format_t obtfmt)
 414{
 415    dolog ("parameter | requested value | obtained value\n");
 416    dolog ("format    |      %10d |     %10d\n", req->fmt, obtfmt);
 417    dolog ("channels  |      %10d |     %10d\n",
 418           req->nchannels, obt->nchannels);
 419    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
 420    dolog ("============================================\n");
 421    dolog ("requested: buffer size %d period size %d\n",
 422           req->buffer_size, req->period_size);
 423    dolog ("obtained: samples %ld\n", obt->samples);
 424}
 425
 426static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
 427{
 428    int err;
 429    snd_pcm_sw_params_t *sw_params;
 430
 431    snd_pcm_sw_params_alloca (&sw_params);
 432
 433    err = snd_pcm_sw_params_current (handle, sw_params);
 434    if (err < 0) {
 435        dolog ("Could not fully initialize DAC\n");
 436        alsa_logerr (err, "Failed to get current software parameters\n");
 437        return;
 438    }
 439
 440    err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
 441    if (err < 0) {
 442        dolog ("Could not fully initialize DAC\n");
 443        alsa_logerr (err, "Failed to set software threshold to %ld\n",
 444                     threshold);
 445        return;
 446    }
 447
 448    err = snd_pcm_sw_params (handle, sw_params);
 449    if (err < 0) {
 450        dolog ("Could not fully initialize DAC\n");
 451        alsa_logerr (err, "Failed to set software parameters\n");
 452        return;
 453    }
 454}
 455
 456static int alsa_open (int in, struct alsa_params_req *req,
 457                      struct alsa_params_obt *obt, snd_pcm_t **handlep,
 458                      ALSAConf *conf)
 459{
 460    snd_pcm_t *handle;
 461    snd_pcm_hw_params_t *hw_params;
 462    int err;
 463    int size_in_usec;
 464    unsigned int freq, nchannels;
 465    const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out;
 466    snd_pcm_uframes_t obt_buffer_size;
 467    const char *typ = in ? "ADC" : "DAC";
 468    snd_pcm_format_t obtfmt;
 469
 470    freq = req->freq;
 471    nchannels = req->nchannels;
 472    size_in_usec = req->size_in_usec;
 473
 474    snd_pcm_hw_params_alloca (&hw_params);
 475
 476    err = snd_pcm_open (
 477        &handle,
 478        pcm_name,
 479        in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
 480        SND_PCM_NONBLOCK
 481        );
 482    if (err < 0) {
 483        alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
 484        return -1;
 485    }
 486
 487    err = snd_pcm_hw_params_any (handle, hw_params);
 488    if (err < 0) {
 489        alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
 490        goto err;
 491    }
 492
 493    err = snd_pcm_hw_params_set_access (
 494        handle,
 495        hw_params,
 496        SND_PCM_ACCESS_RW_INTERLEAVED
 497        );
 498    if (err < 0) {
 499        alsa_logerr2 (err, typ, "Failed to set access type\n");
 500        goto err;
 501    }
 502
 503    err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
 504    if (err < 0) {
 505        alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
 506    }
 507
 508    err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
 509    if (err < 0) {
 510        alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
 511        goto err;
 512    }
 513
 514    err = snd_pcm_hw_params_set_channels_near (
 515        handle,
 516        hw_params,
 517        &nchannels
 518        );
 519    if (err < 0) {
 520        alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
 521                      req->nchannels);
 522        goto err;
 523    }
 524
 525    if (nchannels != 1 && nchannels != 2) {
 526        alsa_logerr2 (err, typ,
 527                      "Can not handle obtained number of channels %d\n",
 528                      nchannels);
 529        goto err;
 530    }
 531
 532    if (req->buffer_size) {
 533        unsigned long obt;
 534
 535        if (size_in_usec) {
 536            int dir = 0;
 537            unsigned int btime = req->buffer_size;
 538
 539            err = snd_pcm_hw_params_set_buffer_time_near (
 540                handle,
 541                hw_params,
 542                &btime,
 543                &dir
 544                );
 545            obt = btime;
 546        }
 547        else {
 548            snd_pcm_uframes_t bsize = req->buffer_size;
 549
 550            err = snd_pcm_hw_params_set_buffer_size_near (
 551                handle,
 552                hw_params,
 553                &bsize
 554                );
 555            obt = bsize;
 556        }
 557        if (err < 0) {
 558            alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n",
 559                          size_in_usec ? "time" : "size", req->buffer_size);
 560            goto err;
 561        }
 562
 563        if ((req->override_mask & 2) && (obt - req->buffer_size))
 564            dolog ("Requested buffer %s %u was rejected, using %lu\n",
 565                   size_in_usec ? "time" : "size", req->buffer_size, obt);
 566    }
 567
 568    if (req->period_size) {
 569        unsigned long obt;
 570
 571        if (size_in_usec) {
 572            int dir = 0;
 573            unsigned int ptime = req->period_size;
 574
 575            err = snd_pcm_hw_params_set_period_time_near (
 576                handle,
 577                hw_params,
 578                &ptime,
 579                &dir
 580                );
 581            obt = ptime;
 582        }
 583        else {
 584            int dir = 0;
 585            snd_pcm_uframes_t psize = req->period_size;
 586
 587            err = snd_pcm_hw_params_set_period_size_near (
 588                handle,
 589                hw_params,
 590                &psize,
 591                &dir
 592                );
 593            obt = psize;
 594        }
 595
 596        if (err < 0) {
 597            alsa_logerr2 (err, typ, "Failed to set period %s to %d\n",
 598                          size_in_usec ? "time" : "size", req->period_size);
 599            goto err;
 600        }
 601
 602        if (((req->override_mask & 1) && (obt - req->period_size)))
 603            dolog ("Requested period %s %u was rejected, using %lu\n",
 604                   size_in_usec ? "time" : "size", req->period_size, obt);
 605    }
 606
 607    err = snd_pcm_hw_params (handle, hw_params);
 608    if (err < 0) {
 609        alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
 610        goto err;
 611    }
 612
 613    err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
 614    if (err < 0) {
 615        alsa_logerr2 (err, typ, "Failed to get buffer size\n");
 616        goto err;
 617    }
 618
 619    err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
 620    if (err < 0) {
 621        alsa_logerr2 (err, typ, "Failed to get format\n");
 622        goto err;
 623    }
 624
 625    if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
 626        dolog ("Invalid format was returned %d\n", obtfmt);
 627        goto err;
 628    }
 629
 630    err = snd_pcm_prepare (handle);
 631    if (err < 0) {
 632        alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
 633        goto err;
 634    }
 635
 636    if (!in && conf->threshold) {
 637        snd_pcm_uframes_t threshold;
 638        int bytes_per_sec;
 639
 640        bytes_per_sec = freq << (nchannels == 2);
 641
 642        switch (obt->fmt) {
 643        case AUD_FMT_S8:
 644        case AUD_FMT_U8:
 645            break;
 646
 647        case AUD_FMT_S16:
 648        case AUD_FMT_U16:
 649            bytes_per_sec <<= 1;
 650            break;
 651
 652        case AUD_FMT_S32:
 653        case AUD_FMT_U32:
 654            bytes_per_sec <<= 2;
 655            break;
 656        }
 657
 658        threshold = (conf->threshold * bytes_per_sec) / 1000;
 659        alsa_set_threshold (handle, threshold);
 660    }
 661
 662    obt->nchannels = nchannels;
 663    obt->freq = freq;
 664    obt->samples = obt_buffer_size;
 665
 666    *handlep = handle;
 667
 668    if (obtfmt != req->fmt ||
 669         obt->nchannels != req->nchannels ||
 670         obt->freq != req->freq) {
 671        dolog ("Audio parameters for %s\n", typ);
 672        alsa_dump_info (req, obt, obtfmt);
 673    }
 674
 675#ifdef DEBUG
 676    alsa_dump_info (req, obt, obtfmt);
 677#endif
 678    return 0;
 679
 680 err:
 681    alsa_anal_close1 (&handle);
 682    return -1;
 683}
 684
 685static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
 686{
 687    snd_pcm_sframes_t avail;
 688
 689    avail = snd_pcm_avail_update (handle);
 690    if (avail < 0) {
 691        if (avail == -EPIPE) {
 692            if (!alsa_recover (handle)) {
 693                avail = snd_pcm_avail_update (handle);
 694            }
 695        }
 696
 697        if (avail < 0) {
 698            alsa_logerr (avail,
 699                         "Could not obtain number of available frames\n");
 700            return -1;
 701        }
 702    }
 703
 704    return avail;
 705}
 706
 707static void alsa_write_pending (ALSAVoiceOut *alsa)
 708{
 709    HWVoiceOut *hw = &alsa->hw;
 710
 711    while (alsa->pending) {
 712        int left_till_end_samples = hw->samples - alsa->wpos;
 713        int len = audio_MIN (alsa->pending, left_till_end_samples);
 714        char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
 715
 716        while (len) {
 717            snd_pcm_sframes_t written;
 718
 719            written = snd_pcm_writei (alsa->handle, src, len);
 720
 721            if (written <= 0) {
 722                switch (written) {
 723                case 0:
 724                    trace_alsa_wrote_zero(len);
 725                    return;
 726
 727                case -EPIPE:
 728                    if (alsa_recover (alsa->handle)) {
 729                        alsa_logerr (written, "Failed to write %d frames\n",
 730                                     len);
 731                        return;
 732                    }
 733                    trace_alsa_xrun_out();
 734                    continue;
 735
 736                case -ESTRPIPE:
 737                    /* stream is suspended and waiting for an
 738                       application recovery */
 739                    if (alsa_resume (alsa->handle)) {
 740                        alsa_logerr (written, "Failed to write %d frames\n",
 741                                     len);
 742                        return;
 743                    }
 744                    trace_alsa_resume_out();
 745                    continue;
 746
 747                case -EAGAIN:
 748                    return;
 749
 750                default:
 751                    alsa_logerr (written, "Failed to write %d frames from %p\n",
 752                                 len, src);
 753                    return;
 754                }
 755            }
 756
 757            alsa->wpos = (alsa->wpos + written) % hw->samples;
 758            alsa->pending -= written;
 759            len -= written;
 760        }
 761    }
 762}
 763
 764static int alsa_run_out (HWVoiceOut *hw, int live)
 765{
 766    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 767    int decr;
 768    snd_pcm_sframes_t avail;
 769
 770    avail = alsa_get_avail (alsa->handle);
 771    if (avail < 0) {
 772        dolog ("Could not get number of available playback frames\n");
 773        return 0;
 774    }
 775
 776    decr = audio_MIN (live, avail);
 777    decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
 778    alsa->pending += decr;
 779    alsa_write_pending (alsa);
 780    return decr;
 781}
 782
 783static void alsa_fini_out (HWVoiceOut *hw)
 784{
 785    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 786
 787    ldebug ("alsa_fini\n");
 788    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 789
 790    g_free(alsa->pcm_buf);
 791    alsa->pcm_buf = NULL;
 792}
 793
 794static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
 795                         void *drv_opaque)
 796{
 797    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 798    struct alsa_params_req req;
 799    struct alsa_params_obt obt;
 800    snd_pcm_t *handle;
 801    struct audsettings obt_as;
 802    ALSAConf *conf = drv_opaque;
 803
 804    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
 805    req.freq = as->freq;
 806    req.nchannels = as->nchannels;
 807    req.period_size = conf->period_size_out;
 808    req.buffer_size = conf->buffer_size_out;
 809    req.size_in_usec = conf->size_in_usec_out;
 810    req.override_mask =
 811        (conf->period_size_out_overridden ? 1 : 0) |
 812        (conf->buffer_size_out_overridden ? 2 : 0);
 813
 814    if (alsa_open (0, &req, &obt, &handle, conf)) {
 815        return -1;
 816    }
 817
 818    obt_as.freq = obt.freq;
 819    obt_as.nchannels = obt.nchannels;
 820    obt_as.fmt = obt.fmt;
 821    obt_as.endianness = obt.endianness;
 822
 823    audio_pcm_init_info (&hw->info, &obt_as);
 824    hw->samples = obt.samples;
 825
 826    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
 827    if (!alsa->pcm_buf) {
 828        dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
 829               hw->samples, 1 << hw->info.shift);
 830        alsa_anal_close1 (&handle);
 831        return -1;
 832    }
 833
 834    alsa->handle = handle;
 835    alsa->pollhlp.conf = conf;
 836    return 0;
 837}
 838
 839#define VOICE_CTL_PAUSE 0
 840#define VOICE_CTL_PREPARE 1
 841#define VOICE_CTL_START 2
 842
 843static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
 844{
 845    int err;
 846
 847    if (ctl == VOICE_CTL_PAUSE) {
 848        err = snd_pcm_drop (handle);
 849        if (err < 0) {
 850            alsa_logerr (err, "Could not stop %s\n", typ);
 851            return -1;
 852        }
 853    }
 854    else {
 855        err = snd_pcm_prepare (handle);
 856        if (err < 0) {
 857            alsa_logerr (err, "Could not prepare handle for %s\n", typ);
 858            return -1;
 859        }
 860        if (ctl == VOICE_CTL_START) {
 861            err = snd_pcm_start(handle);
 862            if (err < 0) {
 863                alsa_logerr (err, "Could not start handle for %s\n", typ);
 864                return -1;
 865            }
 866        }
 867    }
 868
 869    return 0;
 870}
 871
 872static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 873{
 874    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
 875
 876    switch (cmd) {
 877    case VOICE_ENABLE:
 878        {
 879            va_list ap;
 880            int poll_mode;
 881
 882            va_start (ap, cmd);
 883            poll_mode = va_arg (ap, int);
 884            va_end (ap);
 885
 886            ldebug ("enabling voice\n");
 887            if (poll_mode && alsa_poll_out (hw)) {
 888                poll_mode = 0;
 889            }
 890            hw->poll_mode = poll_mode;
 891            return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE);
 892        }
 893
 894    case VOICE_DISABLE:
 895        ldebug ("disabling voice\n");
 896        if (hw->poll_mode) {
 897            hw->poll_mode = 0;
 898            alsa_fini_poll (&alsa->pollhlp);
 899        }
 900        return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE);
 901    }
 902
 903    return -1;
 904}
 905
 906static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
 907{
 908    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
 909    struct alsa_params_req req;
 910    struct alsa_params_obt obt;
 911    snd_pcm_t *handle;
 912    struct audsettings obt_as;
 913    ALSAConf *conf = drv_opaque;
 914
 915    req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
 916    req.freq = as->freq;
 917    req.nchannels = as->nchannels;
 918    req.period_size = conf->period_size_in;
 919    req.buffer_size = conf->buffer_size_in;
 920    req.size_in_usec = conf->size_in_usec_in;
 921    req.override_mask =
 922        (conf->period_size_in_overridden ? 1 : 0) |
 923        (conf->buffer_size_in_overridden ? 2 : 0);
 924
 925    if (alsa_open (1, &req, &obt, &handle, conf)) {
 926        return -1;
 927    }
 928
 929    obt_as.freq = obt.freq;
 930    obt_as.nchannels = obt.nchannels;
 931    obt_as.fmt = obt.fmt;
 932    obt_as.endianness = obt.endianness;
 933
 934    audio_pcm_init_info (&hw->info, &obt_as);
 935    hw->samples = obt.samples;
 936
 937    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 938    if (!alsa->pcm_buf) {
 939        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
 940               hw->samples, 1 << hw->info.shift);
 941        alsa_anal_close1 (&handle);
 942        return -1;
 943    }
 944
 945    alsa->handle = handle;
 946    alsa->pollhlp.conf = conf;
 947    return 0;
 948}
 949
 950static void alsa_fini_in (HWVoiceIn *hw)
 951{
 952    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
 953
 954    alsa_anal_close (&alsa->handle, &alsa->pollhlp);
 955
 956    g_free(alsa->pcm_buf);
 957    alsa->pcm_buf = NULL;
 958}
 959
 960static int alsa_run_in (HWVoiceIn *hw)
 961{
 962    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
 963    int hwshift = hw->info.shift;
 964    int i;
 965    int live = audio_pcm_hw_get_live_in (hw);
 966    int dead = hw->samples - live;
 967    int decr;
 968    struct {
 969        int add;
 970        int len;
 971    } bufs[2] = {
 972        { .add = hw->wpos, .len = 0 },
 973        { .add = 0,        .len = 0 }
 974    };
 975    snd_pcm_sframes_t avail;
 976    snd_pcm_uframes_t read_samples = 0;
 977
 978    if (!dead) {
 979        return 0;
 980    }
 981
 982    avail = alsa_get_avail (alsa->handle);
 983    if (avail < 0) {
 984        dolog ("Could not get number of captured frames\n");
 985        return 0;
 986    }
 987
 988    if (!avail) {
 989        snd_pcm_state_t state;
 990
 991        state = snd_pcm_state (alsa->handle);
 992        switch (state) {
 993        case SND_PCM_STATE_PREPARED:
 994            avail = hw->samples;
 995            break;
 996        case SND_PCM_STATE_SUSPENDED:
 997            /* stream is suspended and waiting for an application recovery */
 998            if (alsa_resume (alsa->handle)) {
 999                dolog ("Failed to resume suspended input stream\n");
1000                return 0;
1001            }
1002            trace_alsa_resume_in();
1003            break;
1004        default:
1005            trace_alsa_no_frames(state);
1006            return 0;
1007        }
1008    }
1009
1010    decr = audio_MIN (dead, avail);
1011    if (!decr) {
1012        return 0;
1013    }
1014
1015    if (hw->wpos + decr > hw->samples) {
1016        bufs[0].len = (hw->samples - hw->wpos);
1017        bufs[1].len = (decr - (hw->samples - hw->wpos));
1018    }
1019    else {
1020        bufs[0].len = decr;
1021    }
1022
1023    for (i = 0; i < 2; ++i) {
1024        void *src;
1025        struct st_sample *dst;
1026        snd_pcm_sframes_t nread;
1027        snd_pcm_uframes_t len;
1028
1029        len = bufs[i].len;
1030
1031        src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
1032        dst = hw->conv_buf + bufs[i].add;
1033
1034        while (len) {
1035            nread = snd_pcm_readi (alsa->handle, src, len);
1036
1037            if (nread <= 0) {
1038                switch (nread) {
1039                case 0:
1040                    trace_alsa_read_zero(len);
1041                    goto exit;
1042
1043                case -EPIPE:
1044                    if (alsa_recover (alsa->handle)) {
1045                        alsa_logerr (nread, "Failed to read %ld frames\n", len);
1046                        goto exit;
1047                    }
1048                    trace_alsa_xrun_in();
1049                    continue;
1050
1051                case -EAGAIN:
1052                    goto exit;
1053
1054                default:
1055                    alsa_logerr (
1056                        nread,
1057                        "Failed to read %ld frames from %p\n",
1058                        len,
1059                        src
1060                        );
1061                    goto exit;
1062                }
1063            }
1064
1065            hw->conv (dst, src, nread);
1066
1067            src = advance (src, nread << hwshift);
1068            dst += nread;
1069
1070            read_samples += nread;
1071            len -= nread;
1072        }
1073    }
1074
1075 exit:
1076    hw->wpos = (hw->wpos + read_samples) % hw->samples;
1077    return read_samples;
1078}
1079
1080static int alsa_read (SWVoiceIn *sw, void *buf, int size)
1081{
1082    return audio_pcm_sw_read (sw, buf, size);
1083}
1084
1085static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
1086{
1087    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
1088
1089    switch (cmd) {
1090    case VOICE_ENABLE:
1091        {
1092            va_list ap;
1093            int poll_mode;
1094
1095            va_start (ap, cmd);
1096            poll_mode = va_arg (ap, int);
1097            va_end (ap);
1098
1099            ldebug ("enabling voice\n");
1100            if (poll_mode && alsa_poll_in (hw)) {
1101                poll_mode = 0;
1102            }
1103            hw->poll_mode = poll_mode;
1104
1105            return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START);
1106        }
1107
1108    case VOICE_DISABLE:
1109        ldebug ("disabling voice\n");
1110        if (hw->poll_mode) {
1111            hw->poll_mode = 0;
1112            alsa_fini_poll (&alsa->pollhlp);
1113        }
1114        return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE);
1115    }
1116
1117    return -1;
1118}
1119
1120static ALSAConf glob_conf = {
1121    .buffer_size_out = 4096,
1122    .period_size_out = 1024,
1123    .pcm_name_out = "default",
1124    .pcm_name_in = "default",
1125};
1126
1127static void *alsa_audio_init (void)
1128{
1129    ALSAConf *conf = g_malloc(sizeof(ALSAConf));
1130    *conf = glob_conf;
1131    return conf;
1132}
1133
1134static void alsa_audio_fini (void *opaque)
1135{
1136    g_free(opaque);
1137}
1138
1139static struct audio_option alsa_options[] = {
1140    {
1141        .name        = "DAC_SIZE_IN_USEC",
1142        .tag         = AUD_OPT_BOOL,
1143        .valp        = &glob_conf.size_in_usec_out,
1144        .descr       = "DAC period/buffer size in microseconds (otherwise in frames)"
1145    },
1146    {
1147        .name        = "DAC_PERIOD_SIZE",
1148        .tag         = AUD_OPT_INT,
1149        .valp        = &glob_conf.period_size_out,
1150        .descr       = "DAC period size (0 to go with system default)",
1151        .overriddenp = &glob_conf.period_size_out_overridden
1152    },
1153    {
1154        .name        = "DAC_BUFFER_SIZE",
1155        .tag         = AUD_OPT_INT,
1156        .valp        = &glob_conf.buffer_size_out,
1157        .descr       = "DAC buffer size (0 to go with system default)",
1158        .overriddenp = &glob_conf.buffer_size_out_overridden
1159    },
1160    {
1161        .name        = "ADC_SIZE_IN_USEC",
1162        .tag         = AUD_OPT_BOOL,
1163        .valp        = &glob_conf.size_in_usec_in,
1164        .descr       =
1165        "ADC period/buffer size in microseconds (otherwise in frames)"
1166    },
1167    {
1168        .name        = "ADC_PERIOD_SIZE",
1169        .tag         = AUD_OPT_INT,
1170        .valp        = &glob_conf.period_size_in,
1171        .descr       = "ADC period size (0 to go with system default)",
1172        .overriddenp = &glob_conf.period_size_in_overridden
1173    },
1174    {
1175        .name        = "ADC_BUFFER_SIZE",
1176        .tag         = AUD_OPT_INT,
1177        .valp        = &glob_conf.buffer_size_in,
1178        .descr       = "ADC buffer size (0 to go with system default)",
1179        .overriddenp = &glob_conf.buffer_size_in_overridden
1180    },
1181    {
1182        .name        = "THRESHOLD",
1183        .tag         = AUD_OPT_INT,
1184        .valp        = &glob_conf.threshold,
1185        .descr       = "(undocumented)"
1186    },
1187    {
1188        .name        = "DAC_DEV",
1189        .tag         = AUD_OPT_STR,
1190        .valp        = &glob_conf.pcm_name_out,
1191        .descr       = "DAC device name (for instance dmix)"
1192    },
1193    {
1194        .name        = "ADC_DEV",
1195        .tag         = AUD_OPT_STR,
1196        .valp        = &glob_conf.pcm_name_in,
1197        .descr       = "ADC device name"
1198    },
1199    { /* End of list */ }
1200};
1201
1202static struct audio_pcm_ops alsa_pcm_ops = {
1203    .init_out = alsa_init_out,
1204    .fini_out = alsa_fini_out,
1205    .run_out  = alsa_run_out,
1206    .write    = alsa_write,
1207    .ctl_out  = alsa_ctl_out,
1208
1209    .init_in  = alsa_init_in,
1210    .fini_in  = alsa_fini_in,
1211    .run_in   = alsa_run_in,
1212    .read     = alsa_read,
1213    .ctl_in   = alsa_ctl_in,
1214};
1215
1216struct audio_driver alsa_audio_driver = {
1217    .name           = "alsa",
1218    .descr          = "ALSA http://www.alsa-project.org",
1219    .options        = alsa_options,
1220    .init           = alsa_audio_init,
1221    .fini           = alsa_audio_fini,
1222    .pcm_ops        = &alsa_pcm_ops,
1223    .can_be_default = 1,
1224    .max_voices_out = INT_MAX,
1225    .max_voices_in  = INT_MAX,
1226    .voice_size_out = sizeof (ALSAVoiceOut),
1227    .voice_size_in  = sizeof (ALSAVoiceIn)
1228};
1229