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    size_t l;
 211    int r;
 212
 213    pa_threaded_mainloop_lock(c->mainloop);
 214
 215    CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
 216                    "pa_threaded_mainloop_lock failed\n");
 217    if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
 218        /* wait for stream to become ready */
 219        l = 0;
 220        ret = NULL;
 221        goto unlock;
 222    }
 223
 224    l = pa_stream_writable_size(p->stream);
 225    CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
 226                       "pa_stream_writable_size failed\n");
 227
 228    *size = -1;
 229    r = pa_stream_begin_write(p->stream, &ret, size);
 230    CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
 231                       "pa_stream_begin_write failed\n");
 232
 233unlock:
 234    pa_threaded_mainloop_unlock(c->mainloop);
 235    if (*size > l) {
 236        *size = l;
 237    }
 238    return ret;
 239
 240unlock_and_fail:
 241    pa_threaded_mainloop_unlock(c->mainloop);
 242    *size = 0;
 243    return NULL;
 244}
 245
 246static size_t qpa_put_buffer_out(HWVoiceOut *hw, void *data, size_t length)
 247{
 248    PAVoiceOut *p = (PAVoiceOut *)hw;
 249    PAConnection *c = p->g->conn;
 250    int r;
 251
 252    pa_threaded_mainloop_lock(c->mainloop);
 253
 254    CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
 255                    "pa_threaded_mainloop_lock failed\n");
 256
 257    r = pa_stream_write(p->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
 258    CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
 259
 260    pa_threaded_mainloop_unlock(c->mainloop);
 261    return length;
 262
 263unlock_and_fail:
 264    pa_threaded_mainloop_unlock(c->mainloop);
 265    return 0;
 266}
 267
 268static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
 269{
 270    PAVoiceOut *p = (PAVoiceOut *) hw;
 271    PAConnection *c = p->g->conn;
 272    size_t l;
 273    int r;
 274
 275    pa_threaded_mainloop_lock(c->mainloop);
 276
 277    CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
 278                    "pa_threaded_mainloop_lock failed\n");
 279    if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
 280        /* wait for stream to become ready */
 281        l = 0;
 282        goto unlock;
 283    }
 284
 285    l = pa_stream_writable_size(p->stream);
 286
 287    CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
 288                       "pa_stream_writable_size failed\n");
 289
 290    if (l > length) {
 291        l = length;
 292    }
 293
 294    r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
 295    CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
 296
 297unlock:
 298    pa_threaded_mainloop_unlock(c->mainloop);
 299    return l;
 300
 301unlock_and_fail:
 302    pa_threaded_mainloop_unlock(c->mainloop);
 303    return 0;
 304}
 305
 306static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
 307{
 308    int format;
 309
 310    switch (afmt) {
 311    case AUDIO_FORMAT_S8:
 312    case AUDIO_FORMAT_U8:
 313        format = PA_SAMPLE_U8;
 314        break;
 315    case AUDIO_FORMAT_S16:
 316    case AUDIO_FORMAT_U16:
 317        format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
 318        break;
 319    case AUDIO_FORMAT_S32:
 320    case AUDIO_FORMAT_U32:
 321        format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
 322        break;
 323    case AUDIO_FORMAT_F32:
 324        format = endianness ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
 325        break;
 326    default:
 327        dolog ("Internal logic error: Bad audio format %d\n", afmt);
 328        format = PA_SAMPLE_U8;
 329        break;
 330    }
 331    return format;
 332}
 333
 334static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
 335{
 336    switch (fmt) {
 337    case PA_SAMPLE_U8:
 338        return AUDIO_FORMAT_U8;
 339    case PA_SAMPLE_S16BE:
 340        *endianness = 1;
 341        return AUDIO_FORMAT_S16;
 342    case PA_SAMPLE_S16LE:
 343        *endianness = 0;
 344        return AUDIO_FORMAT_S16;
 345    case PA_SAMPLE_S32BE:
 346        *endianness = 1;
 347        return AUDIO_FORMAT_S32;
 348    case PA_SAMPLE_S32LE:
 349        *endianness = 0;
 350        return AUDIO_FORMAT_S32;
 351    case PA_SAMPLE_FLOAT32BE:
 352        *endianness = 1;
 353        return AUDIO_FORMAT_F32;
 354    case PA_SAMPLE_FLOAT32LE:
 355        *endianness = 0;
 356        return AUDIO_FORMAT_F32;
 357    default:
 358        dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
 359        return AUDIO_FORMAT_U8;
 360    }
 361}
 362
 363static void context_state_cb (pa_context *c, void *userdata)
 364{
 365    PAConnection *conn = userdata;
 366
 367    switch (pa_context_get_state(c)) {
 368    case PA_CONTEXT_READY:
 369    case PA_CONTEXT_TERMINATED:
 370    case PA_CONTEXT_FAILED:
 371        pa_threaded_mainloop_signal(conn->mainloop, 0);
 372        break;
 373
 374    case PA_CONTEXT_UNCONNECTED:
 375    case PA_CONTEXT_CONNECTING:
 376    case PA_CONTEXT_AUTHORIZING:
 377    case PA_CONTEXT_SETTING_NAME:
 378        break;
 379    }
 380}
 381
 382static void stream_state_cb (pa_stream *s, void * userdata)
 383{
 384    PAConnection *c = userdata;
 385
 386    switch (pa_stream_get_state (s)) {
 387
 388    case PA_STREAM_READY:
 389    case PA_STREAM_FAILED:
 390    case PA_STREAM_TERMINATED:
 391        pa_threaded_mainloop_signal(c->mainloop, 0);
 392        break;
 393
 394    case PA_STREAM_UNCONNECTED:
 395    case PA_STREAM_CREATING:
 396        break;
 397    }
 398}
 399
 400static pa_stream *qpa_simple_new (
 401        PAConnection *c,
 402        const char *name,
 403        pa_stream_direction_t dir,
 404        const char *dev,
 405        const pa_sample_spec *ss,
 406        const pa_buffer_attr *attr,
 407        int *rerror)
 408{
 409    int r;
 410    pa_stream *stream = NULL;
 411    pa_stream_flags_t flags;
 412    pa_channel_map map;
 413
 414    pa_threaded_mainloop_lock(c->mainloop);
 415
 416    pa_channel_map_init(&map);
 417    map.channels = ss->channels;
 418
 419    /*
 420     * TODO: This currently expects the only frontend supporting more than 2
 421     * channels is the usb-audio.  We will need some means to set channel
 422     * order when a new frontend gains multi-channel support.
 423     */
 424    switch (ss->channels) {
 425    case 1:
 426        map.map[0] = PA_CHANNEL_POSITION_MONO;
 427        break;
 428
 429    case 2:
 430        map.map[0] = PA_CHANNEL_POSITION_LEFT;
 431        map.map[1] = PA_CHANNEL_POSITION_RIGHT;
 432        break;
 433
 434    case 6:
 435        map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
 436        map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
 437        map.map[2] = PA_CHANNEL_POSITION_CENTER;
 438        map.map[3] = PA_CHANNEL_POSITION_LFE;
 439        map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
 440        map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
 441        break;
 442
 443    case 8:
 444        map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT;
 445        map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT;
 446        map.map[2] = PA_CHANNEL_POSITION_CENTER;
 447        map.map[3] = PA_CHANNEL_POSITION_LFE;
 448        map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT;
 449        map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT;
 450        map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT;
 451        map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT;
 452        break;
 453
 454    default:
 455        dolog("Internal error: unsupported channel count %d\n", ss->channels);
 456        goto fail;
 457    }
 458
 459    stream = pa_stream_new(c->context, name, ss, &map);
 460    if (!stream) {
 461        goto fail;
 462    }
 463
 464    pa_stream_set_state_callback(stream, stream_state_cb, c);
 465
 466    flags =
 467        PA_STREAM_INTERPOLATE_TIMING
 468        | PA_STREAM_AUTO_TIMING_UPDATE
 469        | PA_STREAM_EARLY_REQUESTS;
 470
 471    if (dev) {
 472        /* don't move the stream if the user specified a sink/source */
 473        flags |= PA_STREAM_DONT_MOVE;
 474    }
 475
 476    if (dir == PA_STREAM_PLAYBACK) {
 477        r = pa_stream_connect_playback(stream, dev, attr, flags, NULL, NULL);
 478    } else {
 479        r = pa_stream_connect_record(stream, dev, attr, flags);
 480    }
 481
 482    if (r < 0) {
 483        goto fail;
 484    }
 485
 486    pa_threaded_mainloop_unlock(c->mainloop);
 487
 488    return stream;
 489
 490fail:
 491    pa_threaded_mainloop_unlock(c->mainloop);
 492
 493    if (stream) {
 494        pa_stream_unref (stream);
 495    }
 496
 497    *rerror = pa_context_errno(c->context);
 498
 499    return NULL;
 500}
 501
 502static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
 503                        void *drv_opaque)
 504{
 505    int error;
 506    pa_sample_spec ss;
 507    pa_buffer_attr ba;
 508    struct audsettings obt_as = *as;
 509    PAVoiceOut *pa = (PAVoiceOut *) hw;
 510    paaudio *g = pa->g = drv_opaque;
 511    AudiodevPaOptions *popts = &g->dev->u.pa;
 512    AudiodevPaPerDirectionOptions *ppdo = popts->out;
 513    PAConnection *c = g->conn;
 514
 515    ss.format = audfmt_to_pa (as->fmt, as->endianness);
 516    ss.channels = as->nchannels;
 517    ss.rate = as->freq;
 518
 519    ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
 520    ba.minreq = pa_usec_to_bytes(MIN(ppdo->latency >> 2,
 521                                     (g->dev->timer_period >> 2) * 3), &ss);
 522    ba.maxlength = -1;
 523    ba.prebuf = -1;
 524
 525    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 526
 527    pa->stream = qpa_simple_new (
 528        c,
 529        ppdo->has_stream_name ? ppdo->stream_name : g->dev->id,
 530        PA_STREAM_PLAYBACK,
 531        ppdo->has_name ? ppdo->name : NULL,
 532        &ss,
 533        &ba,                    /* buffering attributes */
 534        &error
 535        );
 536    if (!pa->stream) {
 537        qpa_logerr (error, "pa_simple_new for playback failed\n");
 538        goto fail1;
 539    }
 540
 541    audio_pcm_init_info (&hw->info, &obt_as);
 542    /*
 543     * This is wrong. hw->samples counts in frames. hw->samples will be
 544     * number of channels times larger than expected.
 545     */
 546    hw->samples = audio_buffer_samples(
 547        qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
 548
 549    return 0;
 550
 551 fail1:
 552    return -1;
 553}
 554
 555static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
 556{
 557    int error;
 558    pa_sample_spec ss;
 559    pa_buffer_attr ba;
 560    struct audsettings obt_as = *as;
 561    PAVoiceIn *pa = (PAVoiceIn *) hw;
 562    paaudio *g = pa->g = drv_opaque;
 563    AudiodevPaOptions *popts = &g->dev->u.pa;
 564    AudiodevPaPerDirectionOptions *ppdo = popts->in;
 565    PAConnection *c = g->conn;
 566
 567    ss.format = audfmt_to_pa (as->fmt, as->endianness);
 568    ss.channels = as->nchannels;
 569    ss.rate = as->freq;
 570
 571    ba.fragsize = pa_usec_to_bytes((g->dev->timer_period >> 1) * 3, &ss);
 572    ba.maxlength = pa_usec_to_bytes(
 573        MAX(ppdo->latency, g->dev->timer_period * 3), &ss);
 574    ba.minreq = -1;
 575    ba.prebuf = -1;
 576
 577    obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
 578
 579    pa->stream = qpa_simple_new (
 580        c,
 581        ppdo->has_stream_name ? ppdo->stream_name : g->dev->id,
 582        PA_STREAM_RECORD,
 583        ppdo->has_name ? ppdo->name : NULL,
 584        &ss,
 585        &ba,                    /* buffering attributes */
 586        &error
 587        );
 588    if (!pa->stream) {
 589        qpa_logerr (error, "pa_simple_new for capture failed\n");
 590        goto fail1;
 591    }
 592
 593    audio_pcm_init_info (&hw->info, &obt_as);
 594    /*
 595     * This is wrong. hw->samples counts in frames. hw->samples will be
 596     * number of channels times larger than expected.
 597     */
 598    hw->samples = audio_buffer_samples(
 599        qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
 600
 601    return 0;
 602
 603 fail1:
 604    return -1;
 605}
 606
 607static void qpa_simple_disconnect(PAConnection *c, pa_stream *stream)
 608{
 609    int err;
 610
 611    /*
 612     * wait until actually connects. workaround pa bug #247
 613     * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
 614     */
 615    while (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
 616        pa_threaded_mainloop_wait(c->mainloop);
 617    }
 618
 619    err = pa_stream_disconnect(stream);
 620    if (err != 0) {
 621        dolog("Failed to disconnect! err=%d\n", err);
 622    }
 623    pa_stream_unref(stream);
 624}
 625
 626static void qpa_fini_out (HWVoiceOut *hw)
 627{
 628    PAVoiceOut *pa = (PAVoiceOut *) hw;
 629
 630    if (pa->stream) {
 631        PAConnection *c = pa->g->conn;
 632
 633        pa_threaded_mainloop_lock(c->mainloop);
 634        qpa_simple_disconnect(c, pa->stream);
 635        pa->stream = NULL;
 636        pa_threaded_mainloop_unlock(c->mainloop);
 637    }
 638}
 639
 640static void qpa_fini_in (HWVoiceIn *hw)
 641{
 642    PAVoiceIn *pa = (PAVoiceIn *) hw;
 643
 644    if (pa->stream) {
 645        PAConnection *c = pa->g->conn;
 646
 647        pa_threaded_mainloop_lock(c->mainloop);
 648        if (pa->read_length) {
 649            int r = pa_stream_drop(pa->stream);
 650            if (r) {
 651                qpa_logerr(pa_context_errno(c->context),
 652                           "pa_stream_drop failed\n");
 653            }
 654            pa->read_length = 0;
 655        }
 656        qpa_simple_disconnect(c, pa->stream);
 657        pa->stream = NULL;
 658        pa_threaded_mainloop_unlock(c->mainloop);
 659    }
 660}
 661
 662static void qpa_volume_out(HWVoiceOut *hw, Volume *vol)
 663{
 664    PAVoiceOut *pa = (PAVoiceOut *) hw;
 665    pa_operation *op;
 666    pa_cvolume v;
 667    PAConnection *c = pa->g->conn;
 668    int i;
 669
 670#ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
 671    pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
 672#endif
 673
 674    v.channels = vol->channels;
 675    for (i = 0; i < vol->channels; ++i) {
 676        v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255;
 677    }
 678
 679    pa_threaded_mainloop_lock(c->mainloop);
 680
 681    op = pa_context_set_sink_input_volume(c->context,
 682                                          pa_stream_get_index(pa->stream),
 683                                          &v, NULL, NULL);
 684    if (!op) {
 685        qpa_logerr(pa_context_errno(c->context),
 686                   "set_sink_input_volume() failed\n");
 687    } else {
 688        pa_operation_unref(op);
 689    }
 690
 691    op = pa_context_set_sink_input_mute(c->context,
 692                                        pa_stream_get_index(pa->stream),
 693                                        vol->mute, NULL, NULL);
 694    if (!op) {
 695        qpa_logerr(pa_context_errno(c->context),
 696                   "set_sink_input_mute() failed\n");
 697    } else {
 698        pa_operation_unref(op);
 699    }
 700
 701    pa_threaded_mainloop_unlock(c->mainloop);
 702}
 703
 704static void qpa_volume_in(HWVoiceIn *hw, Volume *vol)
 705{
 706    PAVoiceIn *pa = (PAVoiceIn *) hw;
 707    pa_operation *op;
 708    pa_cvolume v;
 709    PAConnection *c = pa->g->conn;
 710    int i;
 711
 712#ifdef PA_CHECK_VERSION
 713    pa_cvolume_init (&v);
 714#endif
 715
 716    v.channels = vol->channels;
 717    for (i = 0; i < vol->channels; ++i) {
 718        v.values[i] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * vol->vol[i]) / 255;
 719    }
 720
 721    pa_threaded_mainloop_lock(c->mainloop);
 722
 723    op = pa_context_set_source_output_volume(c->context,
 724        pa_stream_get_index(pa->stream),
 725        &v, NULL, NULL);
 726    if (!op) {
 727        qpa_logerr(pa_context_errno(c->context),
 728                   "set_source_output_volume() failed\n");
 729    } else {
 730        pa_operation_unref(op);
 731    }
 732
 733    op = pa_context_set_source_output_mute(c->context,
 734        pa_stream_get_index(pa->stream),
 735        vol->mute, NULL, NULL);
 736    if (!op) {
 737        qpa_logerr(pa_context_errno(c->context),
 738                   "set_source_output_mute() failed\n");
 739    } else {
 740        pa_operation_unref(op);
 741    }
 742
 743    pa_threaded_mainloop_unlock(c->mainloop);
 744}
 745
 746static int qpa_validate_per_direction_opts(Audiodev *dev,
 747                                           AudiodevPaPerDirectionOptions *pdo)
 748{
 749    if (!pdo->has_latency) {
 750        pdo->has_latency = true;
 751        pdo->latency = 15000;
 752    }
 753    return 1;
 754}
 755
 756/* common */
 757static void *qpa_conn_init(const char *server)
 758{
 759    const char *vm_name;
 760    PAConnection *c = g_malloc0(sizeof(PAConnection));
 761    QTAILQ_INSERT_TAIL(&pa_conns, c, list);
 762
 763    c->mainloop = pa_threaded_mainloop_new();
 764    if (!c->mainloop) {
 765        goto fail;
 766    }
 767
 768    vm_name = qemu_get_vm_name();
 769    c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop),
 770                                vm_name ? vm_name : "qemu");
 771    if (!c->context) {
 772        goto fail;
 773    }
 774
 775    pa_context_set_state_callback(c->context, context_state_cb, c);
 776
 777    if (pa_context_connect(c->context, server, 0, NULL) < 0) {
 778        qpa_logerr(pa_context_errno(c->context),
 779                   "pa_context_connect() failed\n");
 780        goto fail;
 781    }
 782
 783    pa_threaded_mainloop_lock(c->mainloop);
 784
 785    if (pa_threaded_mainloop_start(c->mainloop) < 0) {
 786        goto unlock_and_fail;
 787    }
 788
 789    for (;;) {
 790        pa_context_state_t state;
 791
 792        state = pa_context_get_state(c->context);
 793
 794        if (state == PA_CONTEXT_READY) {
 795            break;
 796        }
 797
 798        if (!PA_CONTEXT_IS_GOOD(state)) {
 799            qpa_logerr(pa_context_errno(c->context),
 800                       "Wrong context state\n");
 801            goto unlock_and_fail;
 802        }
 803
 804        /* Wait until the context is ready */
 805        pa_threaded_mainloop_wait(c->mainloop);
 806    }
 807
 808    pa_threaded_mainloop_unlock(c->mainloop);
 809    return c;
 810
 811unlock_and_fail:
 812    pa_threaded_mainloop_unlock(c->mainloop);
 813fail:
 814    AUD_log (AUDIO_CAP, "Failed to initialize PA context");
 815    qpa_conn_fini(c);
 816    return NULL;
 817}
 818
 819static void *qpa_audio_init(Audiodev *dev)
 820{
 821    paaudio *g;
 822    AudiodevPaOptions *popts = &dev->u.pa;
 823    const char *server;
 824    PAConnection *c;
 825
 826    assert(dev->driver == AUDIODEV_DRIVER_PA);
 827
 828    if (!popts->has_server) {
 829        char pidfile[64];
 830        char *runtime;
 831        struct stat st;
 832
 833        runtime = getenv("XDG_RUNTIME_DIR");
 834        if (!runtime) {
 835            return NULL;
 836        }
 837        snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
 838        if (stat(pidfile, &st) != 0) {
 839            return NULL;
 840        }
 841    }
 842
 843    if (!qpa_validate_per_direction_opts(dev, popts->in)) {
 844        return NULL;
 845    }
 846    if (!qpa_validate_per_direction_opts(dev, popts->out)) {
 847        return NULL;
 848    }
 849
 850    g = g_malloc0(sizeof(paaudio));
 851    server = popts->has_server ? popts->server : NULL;
 852
 853    g->dev = dev;
 854
 855    QTAILQ_FOREACH(c, &pa_conns, list) {
 856        if (server == NULL || c->server == NULL ?
 857            server == c->server :
 858            strcmp(server, c->server) == 0) {
 859            g->conn = c;
 860            break;
 861        }
 862    }
 863    if (!g->conn) {
 864        g->conn = qpa_conn_init(server);
 865    }
 866    if (!g->conn) {
 867        g_free(g);
 868        return NULL;
 869    }
 870
 871    ++g->conn->refcount;
 872    return g;
 873}
 874
 875static void qpa_conn_fini(PAConnection *c)
 876{
 877    if (c->mainloop) {
 878        pa_threaded_mainloop_stop(c->mainloop);
 879    }
 880
 881    if (c->context) {
 882        pa_context_disconnect(c->context);
 883        pa_context_unref(c->context);
 884    }
 885
 886    if (c->mainloop) {
 887        pa_threaded_mainloop_free(c->mainloop);
 888    }
 889
 890    QTAILQ_REMOVE(&pa_conns, c, list);
 891    g_free(c);
 892}
 893
 894static void qpa_audio_fini (void *opaque)
 895{
 896    paaudio *g = opaque;
 897    PAConnection *c = g->conn;
 898
 899    if (--c->refcount == 0) {
 900        qpa_conn_fini(c);
 901    }
 902
 903    g_free(g);
 904}
 905
 906static struct audio_pcm_ops qpa_pcm_ops = {
 907    .init_out = qpa_init_out,
 908    .fini_out = qpa_fini_out,
 909    .write    = qpa_write,
 910    .get_buffer_out = qpa_get_buffer_out,
 911    .put_buffer_out = qpa_put_buffer_out,
 912    .volume_out = qpa_volume_out,
 913
 914    .init_in  = qpa_init_in,
 915    .fini_in  = qpa_fini_in,
 916    .read     = qpa_read,
 917    .get_buffer_in = qpa_get_buffer_in,
 918    .put_buffer_in = qpa_put_buffer_in,
 919    .volume_in = qpa_volume_in
 920};
 921
 922static struct audio_driver pa_audio_driver = {
 923    .name           = "pa",
 924    .descr          = "http://www.pulseaudio.org/",
 925    .init           = qpa_audio_init,
 926    .fini           = qpa_audio_fini,
 927    .pcm_ops        = &qpa_pcm_ops,
 928    .can_be_default = 1,
 929    .max_voices_out = INT_MAX,
 930    .max_voices_in  = INT_MAX,
 931    .voice_size_out = sizeof (PAVoiceOut),
 932    .voice_size_in  = sizeof (PAVoiceIn),
 933};
 934
 935static void register_audio_pa(void)
 936{
 937    audio_driver_register(&pa_audio_driver);
 938}
 939type_init(register_audio_pa);
 940