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