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