qemu/audio/paaudio.c
<<
>>
Prefs
   1/* public domain */
   2#include "qemu/osdep.h"
   3#include "qemu-common.h"
   4#include "audio.h"
   5
   6#include <pulse/pulseaudio.h>
   7
   8#define AUDIO_CAP "pulseaudio"
   9#include "audio_int.h"
  10#include "audio_pt_int.h"
  11
  12typedef struct {
  13    int samples;
  14    char *server;
  15    char *sink;
  16    char *source;
  17} PAConf;
  18
  19typedef struct {
  20    PAConf conf;
  21    pa_threaded_mainloop *mainloop;
  22    pa_context *context;
  23} paaudio;
  24
  25typedef struct {
  26    HWVoiceOut hw;
  27    int done;
  28    int live;
  29    int decr;
  30    int rpos;
  31    pa_stream *stream;
  32    void *pcm_buf;
  33    struct audio_pt pt;
  34    paaudio *g;
  35} PAVoiceOut;
  36
  37typedef struct {
  38    HWVoiceIn hw;
  39    int done;
  40    int dead;
  41    int incr;
  42    int wpos;
  43    pa_stream *stream;
  44    void *pcm_buf;
  45    struct audio_pt pt;
  46    const void *read_data;
  47    size_t read_index, read_length;
  48    paaudio *g;
  49} PAVoiceIn;
  50
  51static void qpa_audio_fini(void *opaque);
  52
  53static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
  54{
  55    va_list ap;
  56
  57    va_start (ap, fmt);
  58    AUD_vlog (AUDIO_CAP, fmt, ap);
  59    va_end (ap);
  60
  61    AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
  62}
  63
  64#ifndef PA_CONTEXT_IS_GOOD
  65static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
  66{
  67    return
  68        x == PA_CONTEXT_CONNECTING ||
  69        x == PA_CONTEXT_AUTHORIZING ||
  70        x == PA_CONTEXT_SETTING_NAME ||
  71        x == PA_CONTEXT_READY;
  72}
  73#endif
  74
  75#ifndef PA_STREAM_IS_GOOD
  76static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
  77{
  78    return
  79        x == PA_STREAM_CREATING ||
  80        x == PA_STREAM_READY;
  81}
  82#endif
  83
  84#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
  85    do {                                                        \
  86        if (!(expression)) {                                    \
  87            if (rerror) {                                       \
  88                *(rerror) = pa_context_errno ((c)->context);    \
  89            }                                                   \
  90            goto label;                                         \
  91        }                                                       \
  92    } while (0);
  93
  94#define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
  95    do {                                                                \
  96        if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
  97            !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
  98            if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
  99                ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
 100                if (rerror) {                                           \
 101                    *(rerror) = pa_context_errno ((c)->context);        \
 102                }                                                       \
 103            } else {                                                    \
 104                if (rerror) {                                           \
 105                    *(rerror) = PA_ERR_BADSTATE;                        \
 106                }                                                       \
 107            }                                                           \
 108            goto label;                                                 \
 109        }                                                               \
 110    } while (0);
 111
 112static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
 113{
 114    paaudio *g = p->g;
 115
 116    pa_threaded_mainloop_lock (g->mainloop);
 117
 118    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 119
 120    while (length > 0) {
 121        size_t l;
 122
 123        while (!p->read_data) {
 124            int r;
 125
 126            r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
 127            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
 128
 129            if (!p->read_data) {
 130                pa_threaded_mainloop_wait (g->mainloop);
 131                CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 132            } else {
 133                p->read_index = 0;
 134            }
 135        }
 136
 137        l = p->read_length < length ? p->read_length : length;
 138        memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
 139
 140        data = (uint8_t *) data + l;
 141        length -= l;
 142
 143        p->read_index += l;
 144        p->read_length -= l;
 145
 146        if (!p->read_length) {
 147            int r;
 148
 149            r = pa_stream_drop (p->stream);
 150            p->read_data = NULL;
 151            p->read_length = 0;
 152            p->read_index = 0;
 153
 154            CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
 155        }
 156    }
 157
 158    pa_threaded_mainloop_unlock (g->mainloop);
 159    return 0;
 160
 161unlock_and_fail:
 162    pa_threaded_mainloop_unlock (g->mainloop);
 163    return -1;
 164}
 165
 166static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
 167{
 168    paaudio *g = p->g;
 169
 170    pa_threaded_mainloop_lock (g->mainloop);
 171
 172    CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 173
 174    while (length > 0) {
 175        size_t l;
 176        int r;
 177
 178        while (!(l = pa_stream_writable_size (p->stream))) {
 179            pa_threaded_mainloop_wait (g->mainloop);
 180            CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
 181        }
 182
 183        CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
 184
 185        if (l > length) {
 186            l = length;
 187        }
 188
 189        r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
 190        CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
 191
 192        data = (const uint8_t *) data + l;
 193        length -= l;
 194    }
 195
 196    pa_threaded_mainloop_unlock (g->mainloop);
 197    return 0;
 198
 199unlock_and_fail:
 200    pa_threaded_mainloop_unlock (g->mainloop);
 201    return -1;
 202}
 203
 204static void *qpa_thread_out (void *arg)
 205{
 206    PAVoiceOut *pa = arg;
 207    HWVoiceOut *hw = &pa->hw;
 208
 209    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 210        return NULL;
 211    }
 212
 213    for (;;) {
 214        int decr, to_mix, rpos;
 215
 216        for (;;) {
 217            if (pa->done) {
 218                goto exit;
 219            }
 220
 221            if (pa->live > 0) {
 222                break;
 223            }
 224
 225            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
 226                goto exit;
 227            }
 228        }
 229
 230        decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
 231        rpos = pa->rpos;
 232
 233        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 234            return NULL;
 235        }
 236
 237        while (to_mix) {
 238            int error;
 239            int chunk = audio_MIN (to_mix, hw->samples - rpos);
 240            struct st_sample *src = hw->mix_buf + rpos;
 241
 242            hw->clip (pa->pcm_buf, src, chunk);
 243
 244            if (qpa_simple_write (pa, pa->pcm_buf,
 245                                  chunk << hw->info.shift, &error) < 0) {
 246                qpa_logerr (error, "pa_simple_write failed\n");
 247                return NULL;
 248            }
 249
 250            rpos = (rpos + chunk) % hw->samples;
 251            to_mix -= chunk;
 252        }
 253
 254        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 255            return NULL;
 256        }
 257
 258        pa->rpos = rpos;
 259        pa->live -= decr;
 260        pa->decr += decr;
 261    }
 262
 263 exit:
 264    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
 265    return NULL;
 266}
 267
 268static int qpa_run_out (HWVoiceOut *hw, int live)
 269{
 270    int decr;
 271    PAVoiceOut *pa = (PAVoiceOut *) hw;
 272
 273    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 274        return 0;
 275    }
 276
 277    decr = audio_MIN (live, pa->decr);
 278    pa->decr -= decr;
 279    pa->live = live - decr;
 280    hw->rpos = pa->rpos;
 281    if (pa->live > 0) {
 282        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 283    }
 284    else {
 285        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
 286    }
 287    return decr;
 288}
 289
 290static int qpa_write (SWVoiceOut *sw, void *buf, int len)
 291{
 292    return audio_pcm_sw_write (sw, buf, len);
 293}
 294
 295/* capture */
 296static void *qpa_thread_in (void *arg)
 297{
 298    PAVoiceIn *pa = arg;
 299    HWVoiceIn *hw = &pa->hw;
 300
 301    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 302        return NULL;
 303    }
 304
 305    for (;;) {
 306        int incr, to_grab, wpos;
 307
 308        for (;;) {
 309            if (pa->done) {
 310                goto exit;
 311            }
 312
 313            if (pa->dead > 0) {
 314                break;
 315            }
 316
 317            if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
 318                goto exit;
 319            }
 320        }
 321
 322        incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
 323        wpos = pa->wpos;
 324
 325        if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
 326            return NULL;
 327        }
 328
 329        while (to_grab) {
 330            int error;
 331            int chunk = audio_MIN (to_grab, hw->samples - wpos);
 332            void *buf = advance (pa->pcm_buf, wpos);
 333
 334            if (qpa_simple_read (pa, buf,
 335                                 chunk << hw->info.shift, &error) < 0) {
 336                qpa_logerr (error, "pa_simple_read failed\n");
 337                return NULL;
 338            }
 339
 340            hw->conv (hw->conv_buf + wpos, buf, chunk);
 341            wpos = (wpos + chunk) % hw->samples;
 342            to_grab -= chunk;
 343        }
 344
 345        if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 346            return NULL;
 347        }
 348
 349        pa->wpos = wpos;
 350        pa->dead -= incr;
 351        pa->incr += incr;
 352    }
 353
 354 exit:
 355    audio_pt_unlock (&pa->pt, AUDIO_FUNC);
 356    return NULL;
 357}
 358
 359static int qpa_run_in (HWVoiceIn *hw)
 360{
 361    int live, incr, dead;
 362    PAVoiceIn *pa = (PAVoiceIn *) hw;
 363
 364    if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
 365        return 0;
 366    }
 367
 368    live = audio_pcm_hw_get_live_in (hw);
 369    dead = hw->samples - live;
 370    incr = audio_MIN (dead, pa->incr);
 371    pa->incr -= incr;
 372    pa->dead = dead - incr;
 373    hw->wpos = pa->wpos;
 374    if (pa->dead > 0) {
 375        audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 376    }
 377    else {
 378        audio_pt_unlock (&pa->pt, AUDIO_FUNC);
 379    }
 380    return incr;
 381}
 382
 383static int qpa_read (SWVoiceIn *sw, void *buf, int len)
 384{
 385    return audio_pcm_sw_read (sw, buf, len);
 386}
 387
 388static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
 389{
 390    int format;
 391
 392    switch (afmt) {
 393    case AUD_FMT_S8:
 394    case AUD_FMT_U8:
 395        format = PA_SAMPLE_U8;
 396        break;
 397    case AUD_FMT_S16:
 398    case AUD_FMT_U16:
 399        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
 400        break;
 401    case AUD_FMT_S32:
 402    case AUD_FMT_U32:
 403        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
 404        break;
 405    default:
 406        dolog ("Internal logic error: Bad audio format %d\n", afmt);
 407        format = PA_SAMPLE_U8;
 408        break;
 409    }
 410    return format;
 411}
 412
 413static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
 414{
 415    switch (fmt) {
 416    case PA_SAMPLE_U8:
 417        return AUD_FMT_U8;
 418    case PA_SAMPLE_S16BE:
 419        *endianness = 1;
 420        return AUD_FMT_S16;
 421    case PA_SAMPLE_S16LE:
 422        *endianness = 0;
 423        return AUD_FMT_S16;
 424    case PA_SAMPLE_S32BE:
 425        *endianness = 1;
 426        return AUD_FMT_S32;
 427    case PA_SAMPLE_S32LE:
 428        *endianness = 0;
 429        return AUD_FMT_S32;
 430    default:
 431        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
 432        return AUD_FMT_U8;
 433    }
 434}
 435
 436static void context_state_cb (pa_context *c, void *userdata)
 437{
 438    paaudio *g = userdata;
 439
 440    switch (pa_context_get_state(c)) {
 441    case PA_CONTEXT_READY:
 442    case PA_CONTEXT_TERMINATED:
 443    case PA_CONTEXT_FAILED:
 444        pa_threaded_mainloop_signal (g->mainloop, 0);
 445        break;
 446
 447    case PA_CONTEXT_UNCONNECTED:
 448    case PA_CONTEXT_CONNECTING:
 449    case PA_CONTEXT_AUTHORIZING:
 450    case PA_CONTEXT_SETTING_NAME:
 451        break;
 452    }
 453}
 454
 455static void stream_state_cb (pa_stream *s, void * userdata)
 456{
 457    paaudio *g = userdata;
 458
 459    switch (pa_stream_get_state (s)) {
 460
 461    case PA_STREAM_READY:
 462    case PA_STREAM_FAILED:
 463    case PA_STREAM_TERMINATED:
 464        pa_threaded_mainloop_signal (g->mainloop, 0);
 465        break;
 466
 467    case PA_STREAM_UNCONNECTED:
 468    case PA_STREAM_CREATING:
 469        break;
 470    }
 471}
 472
 473static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
 474{
 475    paaudio *g = userdata;
 476
 477    pa_threaded_mainloop_signal (g->mainloop, 0);
 478}
 479
 480static pa_stream *qpa_simple_new (
 481        paaudio *g,
 482        const char *name,
 483        pa_stream_direction_t dir,
 484        const char *dev,
 485        const pa_sample_spec *ss,
 486        const pa_channel_map *map,
 487        const pa_buffer_attr *attr,
 488        int *rerror)
 489{
 490    int r;
 491    pa_stream *stream;
 492
 493    pa_threaded_mainloop_lock (g->mainloop);
 494
 495    stream = pa_stream_new (g->context, name, ss, map);
 496    if (!stream) {
 497        goto fail;
 498    }
 499
 500    pa_stream_set_state_callback (stream, stream_state_cb, g);
 501    pa_stream_set_read_callback (stream, stream_request_cb, g);
 502    pa_stream_set_write_callback (stream, stream_request_cb, g);
 503
 504    if (dir == PA_STREAM_PLAYBACK) {
 505        r = pa_stream_connect_playback (stream, dev, attr,
 506                                        PA_STREAM_INTERPOLATE_TIMING
 507#ifdef PA_STREAM_ADJUST_LATENCY
 508                                        |PA_STREAM_ADJUST_LATENCY
 509#endif
 510                                        |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
 511    } else {
 512        r = pa_stream_connect_record (stream, dev, attr,
 513                                      PA_STREAM_INTERPOLATE_TIMING
 514#ifdef PA_STREAM_ADJUST_LATENCY
 515                                      |PA_STREAM_ADJUST_LATENCY
 516#endif
 517                                      |PA_STREAM_AUTO_TIMING_UPDATE);
 518    }
 519
 520    if (r < 0) {
 521      goto fail;
 522    }
 523
 524    pa_threaded_mainloop_unlock (g->mainloop);
 525
 526    return stream;
 527
 528fail:
 529    pa_threaded_mainloop_unlock (g->mainloop);
 530
 531    if (stream) {
 532        pa_stream_unref (stream);
 533    }
 534
 535    *rerror = pa_context_errno (g->context);
 536
 537    return NULL;
 538}
 539
 540static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
 541                        void *drv_opaque)
 542{
 543    int error;
 544    pa_sample_spec ss;
 545    pa_buffer_attr ba;
 546    struct audsettings obt_as = *as;
 547    PAVoiceOut *pa = (PAVoiceOut *) hw;
 548    paaudio *g = pa->g = drv_opaque;
 549
 550    ss.format = audfmt_to_pa (as->fmt, as->endianness);
 551    ss.channels = as->nchannels;
 552    ss.rate = as->freq;
 553
 554    /*
 555     * qemu audio tick runs at 100 Hz (by default), so processing
 556     * data chunks worth 10 ms of sound should be a good fit.
 557     */
 558    ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
 559    ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
 560    ba.maxlength = -1;
 561    ba.prebuf = -1;
 562
 563    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 564
 565    pa->stream = qpa_simple_new (
 566        g,
 567        "qemu",
 568        PA_STREAM_PLAYBACK,
 569        g->conf.sink,
 570        &ss,
 571        NULL,                   /* channel map */
 572        &ba,                    /* buffering attributes */
 573        &error
 574        );
 575    if (!pa->stream) {
 576        qpa_logerr (error, "pa_simple_new for playback failed\n");
 577        goto fail1;
 578    }
 579
 580    audio_pcm_init_info (&hw->info, &obt_as);
 581    hw->samples = g->conf.samples;
 582    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 583    pa->rpos = hw->rpos;
 584    if (!pa->pcm_buf) {
 585        dolog ("Could not allocate buffer (%d bytes)\n",
 586               hw->samples << hw->info.shift);
 587        goto fail2;
 588    }
 589
 590    if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
 591        goto fail3;
 592    }
 593
 594    return 0;
 595
 596 fail3:
 597    g_free (pa->pcm_buf);
 598    pa->pcm_buf = NULL;
 599 fail2:
 600    if (pa->stream) {
 601        pa_stream_unref (pa->stream);
 602        pa->stream = NULL;
 603    }
 604 fail1:
 605    return -1;
 606}
 607
 608static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
 609{
 610    int error;
 611    pa_sample_spec ss;
 612    struct audsettings obt_as = *as;
 613    PAVoiceIn *pa = (PAVoiceIn *) hw;
 614    paaudio *g = pa->g = drv_opaque;
 615
 616    ss.format = audfmt_to_pa (as->fmt, as->endianness);
 617    ss.channels = as->nchannels;
 618    ss.rate = as->freq;
 619
 620    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 621
 622    pa->stream = qpa_simple_new (
 623        g,
 624        "qemu",
 625        PA_STREAM_RECORD,
 626        g->conf.source,
 627        &ss,
 628        NULL,                   /* channel map */
 629        NULL,                   /* buffering attributes */
 630        &error
 631        );
 632    if (!pa->stream) {
 633        qpa_logerr (error, "pa_simple_new for capture failed\n");
 634        goto fail1;
 635    }
 636
 637    audio_pcm_init_info (&hw->info, &obt_as);
 638    hw->samples = g->conf.samples;
 639    pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
 640    pa->wpos = hw->wpos;
 641    if (!pa->pcm_buf) {
 642        dolog ("Could not allocate buffer (%d bytes)\n",
 643               hw->samples << hw->info.shift);
 644        goto fail2;
 645    }
 646
 647    if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
 648        goto fail3;
 649    }
 650
 651    return 0;
 652
 653 fail3:
 654    g_free (pa->pcm_buf);
 655    pa->pcm_buf = NULL;
 656 fail2:
 657    if (pa->stream) {
 658        pa_stream_unref (pa->stream);
 659        pa->stream = NULL;
 660    }
 661 fail1:
 662    return -1;
 663}
 664
 665static void qpa_fini_out (HWVoiceOut *hw)
 666{
 667    void *ret;
 668    PAVoiceOut *pa = (PAVoiceOut *) hw;
 669
 670    audio_pt_lock (&pa->pt, AUDIO_FUNC);
 671    pa->done = 1;
 672    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 673    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 674
 675    if (pa->stream) {
 676        pa_stream_unref (pa->stream);
 677        pa->stream = NULL;
 678    }
 679
 680    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 681    g_free (pa->pcm_buf);
 682    pa->pcm_buf = NULL;
 683}
 684
 685static void qpa_fini_in (HWVoiceIn *hw)
 686{
 687    void *ret;
 688    PAVoiceIn *pa = (PAVoiceIn *) hw;
 689
 690    audio_pt_lock (&pa->pt, AUDIO_FUNC);
 691    pa->done = 1;
 692    audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
 693    audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
 694
 695    if (pa->stream) {
 696        pa_stream_unref (pa->stream);
 697        pa->stream = NULL;
 698    }
 699
 700    audio_pt_fini (&pa->pt, AUDIO_FUNC);
 701    g_free (pa->pcm_buf);
 702    pa->pcm_buf = NULL;
 703}
 704
 705static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
 706{
 707    PAVoiceOut *pa = (PAVoiceOut *) hw;
 708    pa_operation *op;
 709    pa_cvolume v;
 710    paaudio *g = pa->g;
 711
 712#ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
 713    pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
 714#endif
 715
 716    switch (cmd) {
 717    case VOICE_VOLUME:
 718        {
 719            SWVoiceOut *sw;
 720            va_list ap;
 721
 722            va_start (ap, cmd);
 723            sw = va_arg (ap, SWVoiceOut *);
 724            va_end (ap);
 725
 726            v.channels = 2;
 727            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
 728            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
 729
 730            pa_threaded_mainloop_lock (g->mainloop);
 731
 732            op = pa_context_set_sink_input_volume (g->context,
 733                pa_stream_get_index (pa->stream),
 734                &v, NULL, NULL);
 735            if (!op)
 736                qpa_logerr (pa_context_errno (g->context),
 737                            "set_sink_input_volume() failed\n");
 738            else
 739                pa_operation_unref (op);
 740
 741            op = pa_context_set_sink_input_mute (g->context,
 742                pa_stream_get_index (pa->stream),
 743               sw->vol.mute, NULL, NULL);
 744            if (!op) {
 745                qpa_logerr (pa_context_errno (g->context),
 746                            "set_sink_input_mute() failed\n");
 747            } else {
 748                pa_operation_unref (op);
 749            }
 750
 751            pa_threaded_mainloop_unlock (g->mainloop);
 752        }
 753    }
 754    return 0;
 755}
 756
 757static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
 758{
 759    PAVoiceIn *pa = (PAVoiceIn *) hw;
 760    pa_operation *op;
 761    pa_cvolume v;
 762    paaudio *g = pa->g;
 763
 764#ifdef PA_CHECK_VERSION
 765    pa_cvolume_init (&v);
 766#endif
 767
 768    switch (cmd) {
 769    case VOICE_VOLUME:
 770        {
 771            SWVoiceIn *sw;
 772            va_list ap;
 773
 774            va_start (ap, cmd);
 775            sw = va_arg (ap, SWVoiceIn *);
 776            va_end (ap);
 777
 778            v.channels = 2;
 779            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
 780            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
 781
 782            pa_threaded_mainloop_lock (g->mainloop);
 783
 784            /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
 785            op = pa_context_set_source_volume_by_index (g->context,
 786                pa_stream_get_device_index (pa->stream),
 787                &v, NULL, NULL);
 788            if (!op) {
 789                qpa_logerr (pa_context_errno (g->context),
 790                            "set_source_volume() failed\n");
 791            } else {
 792                pa_operation_unref(op);
 793            }
 794
 795            op = pa_context_set_source_mute_by_index (g->context,
 796                pa_stream_get_index (pa->stream),
 797                sw->vol.mute, NULL, NULL);
 798            if (!op) {
 799                qpa_logerr (pa_context_errno (g->context),
 800                            "set_source_mute() failed\n");
 801            } else {
 802                pa_operation_unref (op);
 803            }
 804
 805            pa_threaded_mainloop_unlock (g->mainloop);
 806        }
 807    }
 808    return 0;
 809}
 810
 811/* common */
 812static PAConf glob_conf = {
 813    .samples = 4096,
 814};
 815
 816static void *qpa_audio_init (void)
 817{
 818    paaudio *g = g_malloc(sizeof(paaudio));
 819    g->conf = glob_conf;
 820    g->mainloop = NULL;
 821    g->context = NULL;
 822
 823    g->mainloop = pa_threaded_mainloop_new ();
 824    if (!g->mainloop) {
 825        goto fail;
 826    }
 827
 828    g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
 829                                 g->conf.server);
 830    if (!g->context) {
 831        goto fail;
 832    }
 833
 834    pa_context_set_state_callback (g->context, context_state_cb, g);
 835
 836    if (pa_context_connect (g->context, g->conf.server, 0, NULL) < 0) {
 837        qpa_logerr (pa_context_errno (g->context),
 838                    "pa_context_connect() failed\n");
 839        goto fail;
 840    }
 841
 842    pa_threaded_mainloop_lock (g->mainloop);
 843
 844    if (pa_threaded_mainloop_start (g->mainloop) < 0) {
 845        goto unlock_and_fail;
 846    }
 847
 848    for (;;) {
 849        pa_context_state_t state;
 850
 851        state = pa_context_get_state (g->context);
 852
 853        if (state == PA_CONTEXT_READY) {
 854            break;
 855        }
 856
 857        if (!PA_CONTEXT_IS_GOOD (state)) {
 858            qpa_logerr (pa_context_errno (g->context),
 859                        "Wrong context state\n");
 860            goto unlock_and_fail;
 861        }
 862
 863        /* Wait until the context is ready */
 864        pa_threaded_mainloop_wait (g->mainloop);
 865    }
 866
 867    pa_threaded_mainloop_unlock (g->mainloop);
 868
 869    return g;
 870
 871unlock_and_fail:
 872    pa_threaded_mainloop_unlock (g->mainloop);
 873fail:
 874    AUD_log (AUDIO_CAP, "Failed to initialize PA context");
 875    qpa_audio_fini(g);
 876    return NULL;
 877}
 878
 879static void qpa_audio_fini (void *opaque)
 880{
 881    paaudio *g = opaque;
 882
 883    if (g->mainloop) {
 884        pa_threaded_mainloop_stop (g->mainloop);
 885    }
 886
 887    if (g->context) {
 888        pa_context_disconnect (g->context);
 889        pa_context_unref (g->context);
 890    }
 891
 892    if (g->mainloop) {
 893        pa_threaded_mainloop_free (g->mainloop);
 894    }
 895
 896    g_free(g);
 897}
 898
 899struct audio_option qpa_options[] = {
 900    {
 901        .name  = "SAMPLES",
 902        .tag   = AUD_OPT_INT,
 903        .valp  = &glob_conf.samples,
 904        .descr = "buffer size in samples"
 905    },
 906    {
 907        .name  = "SERVER",
 908        .tag   = AUD_OPT_STR,
 909        .valp  = &glob_conf.server,
 910        .descr = "server address"
 911    },
 912    {
 913        .name  = "SINK",
 914        .tag   = AUD_OPT_STR,
 915        .valp  = &glob_conf.sink,
 916        .descr = "sink device name"
 917    },
 918    {
 919        .name  = "SOURCE",
 920        .tag   = AUD_OPT_STR,
 921        .valp  = &glob_conf.source,
 922        .descr = "source device name"
 923    },
 924    { /* End of list */ }
 925};
 926
 927static struct audio_pcm_ops qpa_pcm_ops = {
 928    .init_out = qpa_init_out,
 929    .fini_out = qpa_fini_out,
 930    .run_out  = qpa_run_out,
 931    .write    = qpa_write,
 932    .ctl_out  = qpa_ctl_out,
 933
 934    .init_in  = qpa_init_in,
 935    .fini_in  = qpa_fini_in,
 936    .run_in   = qpa_run_in,
 937    .read     = qpa_read,
 938    .ctl_in   = qpa_ctl_in
 939};
 940
 941struct audio_driver pa_audio_driver = {
 942    .name           = "pa",
 943    .descr          = "http://www.pulseaudio.org/",
 944    .options        = qpa_options,
 945    .init           = qpa_audio_init,
 946    .fini           = qpa_audio_fini,
 947    .pcm_ops        = &qpa_pcm_ops,
 948    .can_be_default = 1,
 949    .max_voices_out = INT_MAX,
 950    .max_voices_in  = INT_MAX,
 951    .voice_size_out = sizeof (PAVoiceOut),
 952    .voice_size_in  = sizeof (PAVoiceIn),
 953    .ctl_caps       = VOICE_VOLUME_CAP
 954};
 955