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