pulse.c 32 KB
Newer Older
1 2 3
/*****************************************************************************
 * pulse.c : Pulseaudio output plugin for vlc
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2008 VLC authors and VideoLAN
5
 * Copyright (C) 2009-2011 Rémi Denis-Courmont
6 7 8
 *
 * Authors: Martin Hamrle <hamrle @ post . cz>
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

28
#include <assert.h>
29
#include <math.h>
30
#include <vlc_common.h>
31
#include <vlc_plugin.h>
32
#include <vlc_aout.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
33
#include <vlc_cpu.h>
34 35

#include <pulse/pulseaudio.h>
36
#include "audio_output/vlcpulse.h"
37 38 39 40

static int  Open        ( vlc_object_t * );
static void Close       ( vlc_object_t * );

41
vlc_module_begin ()
42
    set_shortname( "PulseAudio" )
43
    set_description( N_("Pulseaudio audio output") )
44
    set_capability( "audio output", 160 )
45 46
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_AOUT )
47
    add_shortcut( "pulseaudio", "pa" )
48 49
    set_callbacks( Open, Close )
vlc_module_end ()
50

51 52
/* NOTE:
 * Be careful what you do when the PulseAudio mainloop is held, which is to say
53
 * within PulseAudio callbacks, or after pa_threaded_mainloop_lock().
54 55
 * In particular, a VLC variable callback cannot be triggered nor deleted with
 * the PulseAudio mainloop lock held, if the callback acquires the lock. */
56

57 58 59 60 61 62 63
struct sink
{
    struct sink *next;
    uint32_t index;
    char name[1];
};

64 65 66 67
struct aout_sys_t
{
    pa_stream *stream; /**< PulseAudio playback stream object */
    pa_context *context; /**< PulseAudio connection context */
68
    pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
69
    pa_time_event *trigger; /**< Deferred stream trigger */
70
    pa_cvolume cvolume; /**< actual sink input volume */
71
    mtime_t first_pts; /**< Play time of buffer start */
72

73
    pa_volume_t volume_force; /**< Forced volume (stream must be NULL) */
74
    pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
75
    char *sink_force; /**< Forced sink name (stream must be NULL) */
76

77
    struct sink *sinks; /**< Locally-cached list of sinks */
78 79
};

80 81 82 83 84 85 86
static void VolumeReport(audio_output_t *aout)
{
    aout_sys_t *sys = aout->sys;
    pa_volume_t volume = pa_cvolume_max(&sys->cvolume);

    aout_VolumeReport(aout, (float)volume / PA_VOLUME_NORM);
}
87

88
/*** Sink ***/
89 90
static void sink_add_cb(pa_context *ctx, const pa_sink_info *i, int eol,
                        void *userdata)
91
{
92
    audio_output_t *aout = userdata;
93
    aout_sys_t *sys = aout->sys;
94 95

    if (eol)
96 97
    {
        pa_threaded_mainloop_signal(sys->mainloop, 0);
98
        return;
99
    }
100
    (void) ctx;
101

102
    msg_Dbg(aout, "adding sink %"PRIu32": %s (%s)", i->index, i->name,
103
            i->description);
104
    aout_HotplugReport(aout, i->name, i->description);
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

    size_t namelen = strlen(i->name);
    struct sink *sink = malloc(sizeof (*sink) + namelen);
    if (unlikely(sink == NULL))
        return;

    sink->next = sys->sinks;
    sink->index = i->index;
    memcpy(sink->name, i->name, namelen + 1);
    sys->sinks = sink;
}

static void sink_mod_cb(pa_context *ctx, const pa_sink_info *i, int eol,
                        void *userdata)
{
    audio_output_t *aout = userdata;

    if (eol)
        return;
    (void) ctx;

126 127 128
    msg_Dbg(aout, "changing sink %"PRIu32": %s (%s)", i->index, i->name,
            i->description);
    aout_HotplugReport(aout, i->name, i->description);
129 130 131 132 133 134 135
}

static void sink_del(uint32_t index, audio_output_t *aout)
{
    aout_sys_t *sys = aout->sys;
    struct sink **pp = &sys->sinks, *sink;

136 137
    msg_Dbg(aout, "removing sink %"PRIu32, index);

138 139 140 141
    while ((sink = *pp) != NULL)
        if (sink->index == index)
        {
            *pp = sink->next;
142
            aout_HotplugReport(aout, sink->name, NULL);
143 144 145 146
            free(sink);
        }
        else
            pp = &sink->next;
147 148
}

149 150 151
static void sink_event(pa_context *ctx, unsigned type, uint32_t idx,
                       audio_output_t *aout)
{
152
    pa_operation *op = NULL;
153 154 155 156

    switch (type)
    {
        case PA_SUBSCRIPTION_EVENT_NEW:
157 158 159
            op = pa_context_get_sink_info_by_index(ctx, idx, sink_add_cb,
                                                   aout);
            break;
160
        case PA_SUBSCRIPTION_EVENT_CHANGE:
161
            op = pa_context_get_sink_info_by_index(ctx, idx, sink_mod_cb,
162 163 164
                                                   aout);
            break;
        case PA_SUBSCRIPTION_EVENT_REMOVE:
165
            sink_del(idx, aout);
166 167
            break;
    }
168 169
    if (op != NULL)
        pa_operation_unref(op);
170 171
}

172 173

/*** Latency management and lip synchronization ***/
174
static void stream_start_now(pa_stream *s, audio_output_t *aout)
175 176 177
{
    pa_operation *op;

178
    assert (aout->sys->trigger == NULL);
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

    op = pa_stream_cork(s, 0, NULL, NULL);
    if (op != NULL)
        pa_operation_unref(op);
    op = pa_stream_trigger(s, NULL, NULL);
    if (likely(op != NULL))
        pa_operation_unref(op);
}

static void stream_stop(pa_stream *s, audio_output_t *aout)
{
    aout_sys_t *sys = aout->sys;
    pa_operation *op;

    if (sys->trigger != NULL) {
194
        vlc_pa_rttime_free(sys->mainloop, sys->trigger);
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
        sys->trigger = NULL;
    }

    op = pa_stream_cork(s, 1, NULL, NULL);
    if (op != NULL)
        pa_operation_unref(op);
}

static void stream_trigger_cb(pa_mainloop_api *api, pa_time_event *e,
                              const struct timeval *tv, void *userdata)
{
    audio_output_t *aout = userdata;
    aout_sys_t *sys = aout->sys;

    assert (sys->trigger == e);
210 211 212 213

    msg_Dbg(aout, "starting deferred");
    vlc_pa_rttime_free(sys->mainloop, sys->trigger);
    sys->trigger = NULL;
214
    stream_start_now(sys->stream, aout);
215 216 217
    (void) api; (void) e; (void) tv;
}

218 219 220 221 222 223
/**
 * Starts or resumes the playback stream.
 * Tries start playing back audio samples at the most accurate time
 * in order to minimize desync and resampling during early playback.
 * @note PulseAudio lock required.
 */
224
static void stream_start(pa_stream *s, audio_output_t *aout)
225
{
226 227 228
    aout_sys_t *sys = aout->sys;
    mtime_t delta;

229
    assert (sys->first_pts != VLC_TS_INVALID);
230

231 232 233 234 235
    if (sys->trigger != NULL) {
        vlc_pa_rttime_free(sys->mainloop, sys->trigger);
        sys->trigger = NULL;
    }

236
    delta = vlc_pa_get_latency(aout, sys->context, s);
237 238
    if (unlikely(delta == VLC_TS_INVALID)) {
        msg_Dbg(aout, "cannot synchronize start");
239
        delta = 0; /* screwed */
240
    }
241

242
    delta = (sys->first_pts - mdate()) - delta;
243
    if (delta > 0) {
244 245 246 247
        msg_Dbg(aout, "deferring start (%"PRId64" us)", delta);
        delta += pa_rtclock_now();
        sys->trigger = pa_context_rttime_new(sys->context, delta,
                                             stream_trigger_cb, aout);
248
    } else {
249
        msg_Warn(aout, "starting late (%"PRId64" us)", delta);
250
        stream_start_now(s, aout);
251
    }
252 253
}

254 255
static void stream_latency_cb(pa_stream *s, void *userdata)
{
256
    audio_output_t *aout = userdata;
257
    aout_sys_t *sys = aout->sys;
258

259
    /* This callback is _never_ called while paused. */
260 261 262
    if (sys->first_pts == VLC_TS_INVALID)
        return; /* nothing to do if buffers are (still) empty */
    if (pa_stream_is_corked(s) > 0)
263
        stream_start(s, aout);
264 265
}

266 267 268 269

/*** Stream helpers ***/
static void stream_state_cb(pa_stream *s, void *userdata)
{
270 271
    pa_threaded_mainloop *mainloop = userdata;

272 273 274 275
    switch (pa_stream_get_state(s)) {
        case PA_STREAM_READY:
        case PA_STREAM_FAILED:
        case PA_STREAM_TERMINATED:
276
            pa_threaded_mainloop_signal(mainloop, 0);
277 278 279 280 281
        default:
            break;
    }
}

282 283 284 285 286 287 288 289 290 291
static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
{
    audio_output_t *aout = userdata;
    const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);

    msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
            "prebuf=%u, minreq=%u",
            pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
}

292 293 294 295 296
static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl,
                            void *userdata)
{
    audio_output_t *aout = userdata;

297 298 299 300 301 302
    if (!strcmp(name, PA_STREAM_EVENT_REQUEST_CORK))
        aout_PolicyReport(aout, true);
    else
    if (!strcmp(name, PA_STREAM_EVENT_REQUEST_UNCORK))
        aout_PolicyReport(aout, false);
    else
303 304 305
    /* FIXME: expose aout_Restart() directly */
    if (!strcmp(name, PA_STREAM_EVENT_FORMAT_LOST)) {
        msg_Dbg (aout, "format lost");
306
        aout_RestartRequest (aout, AOUT_RESTART_OUTPUT);
307
    } else
308
        msg_Warn (aout, "unhandled stream event \"%s\"", name);
309 310 311 312
    (void) s;
    (void) pl;
}

313 314
static void stream_moved_cb(pa_stream *s, void *userdata)
{
315
    audio_output_t *aout = userdata;
316
    const char *name = pa_stream_get_device_name(s);
317

318 319
    msg_Dbg(aout, "connected to sink %s", name);
    aout_DeviceReport(aout, name);
320 321
}

322 323
static void stream_overflow_cb(pa_stream *s, void *userdata)
{
324
    audio_output_t *aout = userdata;
325
    aout_sys_t *sys = aout->sys;
326
    pa_operation *op;
327

328 329
    msg_Err(aout, "overflow, flushing");
    op = pa_stream_flush(s, NULL, NULL);
330 331 332 333
    if (unlikely(op == NULL))
        return;
    pa_operation_unref(op);
    sys->first_pts = VLC_TS_INVALID;
334 335 336 337
}

static void stream_started_cb(pa_stream *s, void *userdata)
{
338
    audio_output_t *aout = userdata;
339 340 341 342 343 344 345

    msg_Dbg(aout, "started");
    (void) s;
}

static void stream_suspended_cb(pa_stream *s, void *userdata)
{
346
    audio_output_t *aout = userdata;
347 348

    msg_Dbg(aout, "suspended");
349
    (void) s;
350 351 352 353
}

static void stream_underflow_cb(pa_stream *s, void *userdata)
{
354
    audio_output_t *aout = userdata;
355

356 357
    msg_Dbg(aout, "underflow");
    (void) s;
358 359
}

360
static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
361 362 363 364 365 366
{
    pa_stream_state_t state;

    while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
        if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
            return -1;
367
        pa_threaded_mainloop_wait(mainloop);
368 369 370 371
    }
    return 0;
}

372 373 374 375 376 377

/*** Sink input ***/
static void sink_input_info_cb(pa_context *ctx, const pa_sink_input_info *i,
                               int eol, void *userdata)
{
    audio_output_t *aout = userdata;
378
    aout_sys_t *sys = aout->sys;
379 380 381

    if (eol)
        return;
382
    (void) ctx;
383

384
    sys->cvolume = i->volume; /* cache volume for balance preservation */
385
    VolumeReport(aout);
386
    aout_MuteReport(aout, i->mute);
387 388
}

389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
static void sink_input_event(pa_context *ctx,
                             pa_subscription_event_type_t type,
                             uint32_t idx, audio_output_t *aout)
{
    pa_operation *op;

    /* Gee... PA will not provide the infos directly in the event. */
    switch (type)
    {
        case PA_SUBSCRIPTION_EVENT_REMOVE:
            msg_Err(aout, "sink input killed!");
            break;

        default:
            op = pa_context_get_sink_input_info(ctx, idx, sink_input_info_cb,
                                                aout);
            if (likely(op != NULL))
                pa_operation_unref(op);
            break;
    }
}


/*** Context ***/
static void context_cb(pa_context *ctx, pa_subscription_event_type_t type,
                       uint32_t idx, void *userdata)
{
    audio_output_t *aout = userdata;
    aout_sys_t *sys = aout->sys;
    unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;

    type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK;
    switch (facility)
    {
        case PA_SUBSCRIPTION_EVENT_SINK:
            sink_event(ctx, type, idx, userdata);
            break;

        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
            /* only interested in our sink input */
            if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream))
                sink_input_event(ctx, type, idx, userdata);
            break;

        default: /* unsubscribed facility?! */
434
            vlc_assert_unreachable();
435 436 437
    }
}

438 439 440

/*** VLC audio output callbacks ***/

441
static int TimeGet(audio_output_t *aout, mtime_t *restrict delay)
442 443 444
{
    aout_sys_t *sys = aout->sys;
    pa_stream *s = sys->stream;
445
    int ret = -1;
446

447 448 449 450 451 452 453 454 455 456 457 458
    pa_threaded_mainloop_lock(sys->mainloop);
    if (pa_stream_is_corked(s) <= 0)
    {   /* latency is relevant only if not corked */
        mtime_t delta = vlc_pa_get_latency(aout, sys->context, s);
        if (delta != VLC_TS_INVALID)
        {
            *delay = delta;
            ret = 0;
        }
    }
    pa_threaded_mainloop_unlock(sys->mainloop);
    return ret;
459 460
}

461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
/* Memory free callback. The block_t address is in front of the data. */
static void data_free(void *data)
{
    block_t **pp = data, *block;

    memcpy(&block, pp - 1, sizeof (block));
    block_Release(block);
}

static void *data_convert(block_t **pp)
{
    block_t *block = *pp;
    /* In most cases, there is enough head room, and this is really cheap: */
    block = block_Realloc(block, sizeof (block), block->i_buffer);
    *pp = block;
    if (unlikely(block == NULL))
        return NULL;

    memcpy(block->p_buffer, &block, sizeof (block));
    block->p_buffer += sizeof (block);
    block->i_buffer -= sizeof (block);
    return block->p_buffer;
}

485
/**
Jean-Paul Saman's avatar
Jean-Paul Saman committed
486
 * Queue one audio frame to the playback stream
487
 */
488
static void Play(audio_output_t *aout, block_t *block)
489
{
490
    aout_sys_t *sys = aout->sys;
491 492
    pa_stream *s = sys->stream;

493 494 495 496 497 498
    const void *ptr = data_convert(&block);
    if (unlikely(ptr == NULL))
        return;

    size_t len = block->i_buffer;

499 500 501 502 503
    /* Note: The core already holds the output FIFO lock at this point.
     * Therefore we must not under any circumstances (try to) acquire the
     * output FIFO lock while the PulseAudio threaded main loop lock is held
     * (including from PulseAudio stream callbacks). Otherwise lock inversion
     * will take place, and sooner or later a deadlock. */
504
    pa_threaded_mainloop_lock(sys->mainloop);
505

506 507 508
    if (sys->first_pts == VLC_TS_INVALID)
        sys->first_pts = block->i_pts;

509
    if (pa_stream_is_corked(s) > 0)
510
        stream_start(s, aout);
511

512
#if 0 /* Fault injector to test underrun recovery */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
513 514
    static volatile unsigned u = 0;
    if ((++u % 1000) == 0) {
515
        msg_Err(aout, "fault injection");
516
        pa_operation_unref(pa_stream_flush(s, NULL, NULL));
517 518 519
    }
#endif

520
    if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0) {
521
        vlc_pa_error(aout, "cannot write", sys->context);
522
        block_Release(block);
523 524
    }

525
    pa_threaded_mainloop_unlock(sys->mainloop);
526 527
}

528 529 530
/**
 * Cork or uncork the playback stream
 */
531
static void Pause(audio_output_t *aout, bool paused, mtime_t date)
532
{
533
    aout_sys_t *sys = aout->sys;
534
    pa_stream *s = sys->stream;
535

536
    pa_threaded_mainloop_lock(sys->mainloop);
537

538
    if (paused) {
539
        pa_stream_set_latency_update_callback(s, NULL, NULL);
540
        stream_stop(s, aout);
541
    } else {
542
        pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
543 544
        if (likely(sys->first_pts != VLC_TS_INVALID))
            stream_start_now(s, aout);
545
    }
546

547
    pa_threaded_mainloop_unlock(sys->mainloop);
548
    (void) date;
549 550
}

551 552 553 554 555 556 557 558 559
/**
 * Flush or drain the playback stream
 */
static void Flush(audio_output_t *aout, bool wait)
{
    aout_sys_t *sys = aout->sys;
    pa_stream *s = sys->stream;
    pa_operation *op;

560
    pa_threaded_mainloop_lock(sys->mainloop);
561 562 563 564 565 566 567 568

    if (wait)
        op = pa_stream_drain(s, NULL, NULL);
        /* TODO: wait for drain completion*/
    else
        op = pa_stream_flush(s, NULL, NULL);
    if (op != NULL)
        pa_operation_unref(op);
569 570 571
    sys->first_pts = VLC_TS_INVALID;
    stream_stop(s, aout);

572
    pa_threaded_mainloop_unlock(sys->mainloop);
573 574
}

575
static int VolumeSet(audio_output_t *aout, float vol)
576
{
577
    aout_sys_t *sys = aout->sys;
578 579
    pa_stream *s = sys->stream;
    pa_operation *op;
580
    pa_volume_t volume;
581

582 583 584 585
    /* VLC provides the software volume so convert directly to PulseAudio
     * software volume, pa_volume_t. This is not a linear amplification factor
     * so do not use PulseAudio linear amplification! */
    vol *= PA_VOLUME_NORM;
586 587 588 589
    if (unlikely(vol >= (float)PA_VOLUME_MAX))
        volume = PA_VOLUME_MAX;
    else
        volume = lroundf(vol);
590 591 592 593

    if (s == NULL)
    {
        sys->volume_force = volume;
594 595
        aout_VolumeReport(aout, (float)volume / (float)PA_VOLUME_NORM);
        return 0;
596 597
    }

598 599
    pa_threaded_mainloop_lock(sys->mainloop);

600 601 602 603 604 605 606 607
    if (!pa_cvolume_valid(&sys->cvolume))
    {
        const pa_sample_spec *ss = pa_stream_get_sample_spec(s);

        msg_Warn(aout, "balance clobbered by volume change");
        pa_cvolume_set(&sys->cvolume, ss->channels, PA_VOLUME_NORM);
    }

608 609 610
    /* Preserve the balance (VLC does not support it). */
    pa_cvolume cvolume = sys->cvolume;
    pa_cvolume_scale(&cvolume, PA_VOLUME_NORM);
611
    pa_sw_cvolume_multiply_scalar(&cvolume, &cvolume, volume);
612
    assert(pa_cvolume_valid(&cvolume));
613

614 615
    op = pa_context_set_sink_input_volume(sys->context, pa_stream_get_index(s),
                                          &cvolume, NULL, NULL);
616 617
    if (likely(op != NULL))
        pa_operation_unref(op);
618
    pa_threaded_mainloop_unlock(sys->mainloop);
619
    return likely(op != NULL) ? 0 : -1;
620 621 622 623 624
}

static int MuteSet(audio_output_t *aout, bool mute)
{
    aout_sys_t *sys = aout->sys;
625

626 627
    if (sys->stream == NULL)
    {
628 629 630
        sys->flags_force &= ~(PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED);
        sys->flags_force |=
            mute ? PA_STREAM_START_MUTED : PA_STREAM_START_UNMUTED;
631
        aout_MuteReport(aout, mute);
632
        return 0;
633 634
    }

635 636 637
    pa_operation *op;
    uint32_t idx = pa_stream_get_index(sys->stream);
    pa_threaded_mainloop_lock(sys->mainloop);
638
    op = pa_context_set_sink_input_mute(sys->context, idx, mute, NULL, NULL);
639 640
    if (likely(op != NULL))
        pa_operation_unref(op);
641
    pa_threaded_mainloop_unlock(sys->mainloop);
642 643 644

    return 0;
}
645

646
static int StreamMove(audio_output_t *aout, const char *name)
647
{
648
    aout_sys_t *sys = aout->sys;
649 650 651 652 653 654

    if (sys->stream == NULL)
    {
        msg_Dbg(aout, "will connect to sink %s", name);
        free(sys->sink_force);
        sys->sink_force = strdup(name);
655
        aout_DeviceReport(aout, name);
656 657 658
        return 0;
    }

659
    pa_operation *op;
660
    uint32_t idx = pa_stream_get_index(sys->stream);
661

662
    pa_threaded_mainloop_lock(sys->mainloop);
663 664
    op = pa_context_move_sink_input_by_name(sys->context, idx, name,
                                            NULL, NULL);
665 666
    if (likely(op != NULL)) {
        pa_operation_unref(op);
667
        msg_Dbg(aout, "moving to sink %s", name);
668
    } else
669
        vlc_pa_error(aout, "cannot move sink input", sys->context);
670
    pa_threaded_mainloop_unlock(sys->mainloop);
671

672
    return (op != NULL) ? 0 : -1;
673 674
}

675
static void Stop(audio_output_t *);
676

677 678 679 680 681 682 683 684 685 686 687 688 689
static int strcmp_void(const void *a, const void *b)
{
    const char *const *entry = b;
    return strcmp(a, *entry);
}

static const char *str_map(const char *key, const char *const table[][2],
                           size_t n)
{
     const char **r = bsearch(key, table, n, sizeof (*table), strcmp_void);
     return (r != NULL) ? r[1] : NULL;
}

690 691 692
/**
 * Create a PulseAudio playback stream, a.k.a. a sink input.
 */
693
static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
694
{
695
    aout_sys_t *sys = aout->sys;
696

697 698
    /* Sample format specification */
    struct pa_sample_spec ss;
699
    pa_encoding_t encoding = PA_ENCODING_INVALID;
Danny Wood's avatar
Danny Wood committed
700

701
    switch (fmt->i_format)
Danny Wood's avatar
Danny Wood committed
702
    {
703 704 705 706
        case VLC_CODEC_FL64:
            fmt->i_format = VLC_CODEC_FL32;
        case VLC_CODEC_FL32:
            ss.format = PA_SAMPLE_FLOAT32NE;
707
            break;
708 709
        case VLC_CODEC_S32N:
            ss.format = PA_SAMPLE_S32NE;
710
            break;
711 712
        case VLC_CODEC_S16N:
            ss.format = PA_SAMPLE_S16NE;
713 714 715
            break;
        case VLC_CODEC_U8:
            ss.format = PA_SAMPLE_U8;
716
            break;
717
        case VLC_CODEC_A52:
718
            fmt->i_format = VLC_CODEC_SPDIFL;
719 720
            fmt->i_bytes_per_frame = 4;
            fmt->i_frame_length = 1;
721
            encoding = PA_ENCODING_AC3_IEC61937;
722
            ss.format = PA_SAMPLE_S16NE;
723
            break;
Thomas Guillem's avatar
Thomas Guillem committed
724 725
        case VLC_CODEC_EAC3:
            fmt->i_format = VLC_CODEC_SPDIFL;
726 727
            fmt->i_bytes_per_frame = 4;
            fmt->i_frame_length = 1;
728
            encoding = PA_ENCODING_EAC3_IEC61937;
729
            ss.format = PA_SAMPLE_S16NE;
730
            break;
Thomas Guillem's avatar
Thomas Guillem committed
731
        /* case VLC_CODEC_MPGA:
732
            fmt->i_format = VLC_CODEC_SPDIFL FIXME;
733
            encoding = PA_ENCODING_MPEG_IEC61937;
734
            ss.format = PA_SAMPLE_S16NE;
735 736
            break;*/
        case VLC_CODEC_DTS:
737
            fmt->i_format = VLC_CODEC_SPDIFL;
738 739
            fmt->i_bytes_per_frame = 4;
            fmt->i_frame_length = 1;
740
            encoding = PA_ENCODING_DTS_IEC61937;
741
            ss.format = PA_SAMPLE_S16NE;
742
            break;
743
        default:
744
            if (!AOUT_FMT_LINEAR(fmt) || aout_FormatNbChannels(fmt) == 0)
745
                return VLC_EGENERIC;
746

747 748
            if (HAVE_FPU)
            {
749
                fmt->i_format = VLC_CODEC_FL32;
750 751 752 753
                ss.format = PA_SAMPLE_FLOAT32NE;
            }
            else
            {
754
                fmt->i_format = VLC_CODEC_S16N;
755 756 757
                ss.format = PA_SAMPLE_S16NE;
            }
            break;
Danny Wood's avatar
Danny Wood committed
758 759
    }

760
    ss.rate = fmt->i_rate;
761
    ss.channels = fmt->i_channels;
762
    if (!pa_sample_spec_valid(&ss)) {
763
        msg_Err(aout, "unsupported sample specification");
764
        return VLC_EGENERIC;
765
    }
766

767
    /* Stream parameters */
768 769 770 771 772 773
    pa_stream_flags_t flags = sys->flags_force
                            | PA_STREAM_START_CORKED
                            | PA_STREAM_INTERPOLATE_TIMING
                            | PA_STREAM_NOT_MONOTONIC
                            | PA_STREAM_AUTO_TIMING_UPDATE
                            | PA_STREAM_FIX_RATE;
774 775

    struct pa_buffer_attr attr;
776
    attr.maxlength = -1;
777 778 779 780
    /* PulseAudio goes berserk if the target length (tlength) is not
     * significantly longer than 2 periods (minreq), or when the period length
     * is unspecified and the target length is short. */
    attr.tlength = pa_usec_to_bytes(3 * AOUT_MIN_PREPARE_TIME, &ss);
781
    attr.prebuf = 0; /* trigger manually */
782
    attr.minreq = pa_usec_to_bytes(AOUT_MIN_PREPARE_TIME, &ss);
783
    attr.fragsize = 0; /* not used for output */
784

785 786 787 788 789 790 791
    pa_cvolume *cvolume = NULL, cvolumebuf;
    if (PA_VOLUME_IS_VALID(sys->volume_force))
    {
        cvolume = &cvolumebuf;
        pa_cvolume_set(cvolume, ss.channels, sys->volume_force);
    }

792
    sys->trigger = NULL;
793
    pa_cvolume_init(&sys->cvolume);
794
    sys->first_pts = VLC_TS_INVALID;
795

796 797 798 799 800 801 802 803 804 805
    pa_format_info *formatv[2];
    unsigned formatc = 0;

    /* Favor digital pass-through if available*/
    if (encoding != PA_ENCODING_INVALID) {
        formatv[formatc] = pa_format_info_new();
        formatv[formatc]->encoding = encoding;
        pa_format_info_set_rate(formatv[formatc], ss.rate);
        pa_format_info_set_channels(formatv[formatc], ss.channels);
        formatc++;
806 807 808 809 810 811

        /* FIX flags are only permitted for PCM, and there is no way to pass
         * different flags for different formats... */
        flags &= ~(PA_STREAM_FIX_FORMAT
                 | PA_STREAM_FIX_RATE
                 | PA_STREAM_FIX_CHANNELS);
812
    }
813 814
    else
    {
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
        /* Channel mapping (order defined in vlc_aout.h) */
        struct pa_channel_map map;
        map.channels = 0;

        if (fmt->i_physical_channels & AOUT_CHAN_LEFT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
        if (fmt->i_physical_channels & AOUT_CHAN_RIGHT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
        if (fmt->i_physical_channels & AOUT_CHAN_MIDDLELEFT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_LEFT;
        if (fmt->i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_SIDE_RIGHT;
        if (fmt->i_physical_channels & AOUT_CHAN_REARLEFT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
        if (fmt->i_physical_channels & AOUT_CHAN_REARRIGHT)
            map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
        if (fmt->i_physical_channels & AOUT_CHAN_REARCENTER)
            map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
        if (fmt->i_physical_channels & AOUT_CHAN_CENTER)
        {
            if (ss.channels == 1)
                map.map[map.channels++] = PA_CHANNEL_POSITION_MONO;
            else
                map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_CENTER;
        }
        if (fmt->i_physical_channels & AOUT_CHAN_LFE)
            map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;
        fmt->i_original_channels = fmt->i_physical_channels;

        static_assert(AOUT_CHAN_MAX == 9, "Missing channels");

        for (unsigned i = 0; map.channels < ss.channels; i++) {
            map.map[map.channels++] = PA_CHANNEL_POSITION_AUX0 + i;
            msg_Warn(aout, "mapping channel %"PRIu8" to AUX%u", map.channels, i);
        }

        if (!pa_channel_map_valid(&map)) {
            msg_Err(aout, "unsupported channel map");
            return VLC_EGENERIC;
        } else {
            const char *name = pa_channel_map_to_name(&map);
            msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
        }

859 860 861 862 863 864 865 866 867
        /* PCM */
        formatv[formatc] = pa_format_info_new();
        formatv[formatc]->encoding = PA_ENCODING_PCM;
        pa_format_info_set_sample_format(formatv[formatc], ss.format);
        pa_format_info_set_rate(formatv[formatc], ss.rate);
        pa_format_info_set_channels(formatv[formatc], ss.channels);
        pa_format_info_set_channel_map(formatv[formatc], &map);
        formatc++;
    }
868

869
    /* Create a playback stream */
870 871
    pa_proplist *props = pa_proplist_new();
    if (likely(props != NULL))
872
    {
873
        /* TODO: set other stream properties */
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
        char *str = var_InheritString(aout, "role");
        if (str != NULL)
        {
            static const char *const role_map[][2] = {
                { "accessibility", "a11y"       },
                { "animation",     "animation"  },
                { "communication", "phone"      },
                { "game",          "game"       },
                { "music",         "music"      },
                { "notification",  "event"      },
                { "production",    "production" },
                { "test",          "test"       },
                { "video",         "video"      },
            };
            const char *role = str_map(str, role_map, ARRAY_SIZE(role_map));
            if (role != NULL)
                pa_proplist_sets(props, PA_PROP_MEDIA_ROLE, role);
            free(str);
       }
    }
894

895
    pa_threaded_mainloop_lock(sys->mainloop);
896 897 898
    pa_stream *s = pa_stream_new_extended(sys->context, "audio stream",
                                          formatv, formatc, props);

899 900
    if (likely(props != NULL))
        pa_proplist_free(props);
901 902
    for (unsigned i = 0; i < formatc; i++)
        pa_format_info_free(formatv[i]);
903

904
    if (s == NULL) {
905 906 907
        pa_threaded_mainloop_unlock(sys->mainloop);
        vlc_pa_error(aout, "stream creation failure", sys->context);
        return VLC_EGENERIC;
908
    }
909
    assert(sys->stream == NULL);
910
    sys->stream = s;
911
    pa_stream_set_state_callback(s, stream_state_cb, sys->mainloop);
912
    pa_stream_set_buffer_attr_callback(s, stream_buffer_attr_cb, aout);
913
    pa_stream_set_event_callback(s, stream_event_cb, aout);
914
    pa_stream_set_latency_update_callback(s, stream_latency_cb, aout);
915
    pa_stream_set_moved_callback(s, stream_moved_cb, aout);
916 917 918 919
    pa_stream_set_overflow_callback(s, stream_overflow_cb, aout);
    pa_stream_set_started_callback(s, stream_started_cb, aout);
    pa_stream_set_suspended_callback(s, stream_suspended_cb, aout);
    pa_stream_set_underflow_callback(s, stream_underflow_cb, aout);
920

921 922
    if (pa_stream_connect_playback(s, sys->sink_force, &attr, flags,
                                   cvolume, NULL) < 0
923
     || stream_wait(s, sys->mainloop)) {
924 925 926 927 928
        if (encoding != PA_ENCODING_INVALID)
            vlc_pa_error(aout, "digital pass-through stream connection failure",
                         sys->context);
        else
            vlc_pa_error(aout, "stream connection failure", sys->context);
929
        goto fail;
930
    }
931
    sys->volume_force = PA_VOLUME_INVALID;
932
    sys->flags_force = PA_STREAM_NOFLAGS;
933 934
    free(sys->sink_force);
    sys->sink_force = NULL;
935

936 937 938
    if (encoding == PA_ENCODING_INVALID)
    {
        const struct pa_sample_spec *spec = pa_stream_get_sample_spec(s);
939
        fmt->i_rate = spec->rate;
940
    }
941

942
    stream_buffer_attr_cb(s, aout);
943
    stream_moved_cb(s, aout);
944
    pa_threaded_mainloop_unlock(sys->mainloop);
945

946 947 948
    return VLC_SUCCESS;

fail:
949
    pa_threaded_mainloop_unlock(sys->mainloop);
950
    Stop(aout);
951 952 953
    return VLC_EGENERIC;
}

954 955 956
/**
 * Removes a PulseAudio playback stream
 */
957
static void Stop(audio_output_t *aout)
958
{
959
    aout_sys_t *sys = aout->sys;
960 961
    pa_stream *s = sys->stream;

962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
    pa_threaded_mainloop_lock(sys->mainloop);
    if (unlikely(sys->trigger != NULL))
        vlc_pa_rttime_free(sys->mainloop, sys->trigger);
    pa_stream_disconnect(s);

    /* Clear all callbacks */
    pa_stream_set_state_callback(s, NULL, NULL);
    pa_stream_set_buffer_attr_callback(s, NULL, NULL);
    pa_stream_set_event_callback(s, NULL, NULL);
    pa_stream_set_latency_update_callback(s, NULL, NULL);
    pa_stream_set_moved_callback(s, NULL, NULL);
    pa_stream_set_overflow_callback(s, NULL, NULL);
    pa_stream_set_started_callback(s, NULL, NULL);
    pa_stream_set_suspended_callback(s, NULL, NULL);
    pa_stream_set_underflow_callback(s, NULL, NULL);

    pa_stream_unref(s);
979
    sys->stream = NULL;
980 981 982 983 984 985 986
    pa_threaded_mainloop_unlock(sys->mainloop);
}

static int Open(vlc_object_t *obj)
{
    audio_output_t *aout = (audio_output_t *)obj;
    aout_sys_t *sys = malloc(sizeof (*sys));
987
    pa_operation *op;
988 989 990 991 992 993 994 995 996 997

    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    /* Allocate structures */
    pa_context *ctx = vlc_pa_connect(obj, &sys->mainloop);
    if (ctx == NULL)
    {
        free(sys);
        return VLC_EGENERIC;
998
    }
999
    sys->stream = NULL;
1000
    sys->context = ctx;
1001
    sys->volume_force = PA_VOLUME_INVALID;
1002
    sys->flags_force = PA_STREAM_NOFLAGS;
1003
    sys->sink_force = NULL;
1004
    sys->sinks = NULL;
1005 1006 1007 1008

    aout->sys = sys;
    aout->start = Start;
    aout->stop = Stop;
1009
    aout->time_get = TimeGet;
1010 1011 1012 1013 1014
    aout->play = Play;
    aout->pause = Pause;
    aout->flush = Flush;
    aout->volume_set = VolumeSet;
    aout->mute_set = MuteSet;
1015
    aout->device_select = StreamMove;
1016 1017

    pa_threaded_mainloop_lock(sys->mainloop);
1018 1019
    /* Sinks (output devices) list */
    op = pa_context_get_sink_info_list(sys->context, sink_add_cb, aout);
1020 1021 1022 1023
    if (likely(op != NULL))
    {
        while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
            pa_threaded_mainloop_wait(sys->mainloop);
1024
        pa_operation_unref(op);
1025
    }
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

    /* Context events */
    const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SINK
                                      | PA_SUBSCRIPTION_MASK_SINK_INPUT;
    pa_context_set_subscribe_callback(sys->context, context_cb, aout);
    op = pa_context_subscribe(sys->context, mask, NULL, NULL);
    if (likely(op != NULL))
       pa_operation_unref(op);
    pa_threaded_mainloop_unlock(sys->mainloop);

1036 1037 1038 1039 1040 1041 1042 1043
    return VLC_SUCCESS;
}

static void Close(vlc_object_t *obj)
{
    audio_output_t *aout = (audio_output_t *)obj;
    aout_sys_t *sys = aout->sys;
    pa_context *ctx = sys->context;
1044

1045 1046 1047
    pa_threaded_mainloop_lock(sys->mainloop);
    pa_context_set_subscribe_callback(sys->context, NULL, NULL);
    pa_threaded_mainloop_unlock(sys->mainloop);
1048
    vlc_pa_disconnect(obj, ctx, sys->mainloop);
1049

1050 1051 1052 1053 1054
    for (struct sink *sink = sys->sinks, *next; sink != NULL; sink = next)
    {
        next = sink->next;
        free(sink);
    }
1055
    free(sys->sink_force);
1056
    free(sys);
1057
}