pulse.c 17.9 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * pulse.c : Pulseaudio output plugin for vlc
 *****************************************************************************
 * Copyright (C) 2008 the VideoLAN team
5
 * Copyright (C) 2009-2011 Rémi Denis-Courmont
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * Authors: Martin Hamrle <hamrle @ post . cz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU 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.
 *****************************************************************************/

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

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

#include <pulse/pulseaudio.h>

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

38
vlc_module_begin ()
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
39
    set_shortname( "PulseAudio" )
40
    set_description( N_("Pulseaudio audio output") )
41
    set_capability( "audio output", 160 )
42
43
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_AOUT )
44
    add_shortcut( "pulseaudio", "pa" )
45
46
    set_callbacks( Open, Close )
vlc_module_end ()
47

48
49
/* TODO: single static mainloop */

50
51
52
53
54
struct aout_sys_t
{
    pa_stream *stream; /**< PulseAudio playback stream object */
    pa_context *context; /**< PulseAudio connection context */
    pa_threaded_mainloop *mainloop; /**< PulseAudio event loop */
55
56
    pa_volume_t base_volume; /**< 0dB reference volume */
    pa_cvolume cvolume; /**< actual sink input volume */
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    //uint32_t byterate; /**< bytes per second */
};

/* Context helpers */
static void context_state_cb(pa_context *c, void *userdata)
{
    pa_threaded_mainloop *mainloop = userdata;

    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_READY:
        case PA_CONTEXT_FAILED:
        case PA_CONTEXT_TERMINATED:
            pa_threaded_mainloop_signal(mainloop, 0);
        default:
            break;
    }
}

static bool context_wait(pa_threaded_mainloop *mainloop, pa_context *context)
{
    pa_context_state_t state;

    while ((state = pa_context_get_state(context)) != PA_CONTEXT_READY) {
        if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
            return -1;
        pa_threaded_mainloop_wait(mainloop);
    }
    return 0;
}

static void error(aout_instance_t *aout, const char *msg, pa_context *context)
{
    msg_Err(aout, "%s: %s", msg, pa_strerror(pa_context_errno(context)));
}

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/* Sink */
static void sink_info_cb(pa_context *c, const pa_sink_info *i, int eol,
                         void *userdata)
{
    aout_instance_t *aout = userdata;
    aout_sys_t *sys = aout->output.p_sys;

    if (eol)
        return;
    (void) c;

    /* PulseAudio maps 100% to no SW amplification and maximum HW amplification.
     * VLC maps 100% to no amplification at all. Thus we need to use the sink
     * base_volume as a multiplier, if and only if flat volume is active. */
    if (i->flags & PA_SINK_FLAT_VOLUME)
        sys->base_volume = i->base_volume;
    else
        sys->base_volume = PA_VOLUME_NORM;
    msg_Dbg(aout, "base volume: %f", pa_sw_volume_to_linear(sys->base_volume));
}

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* Stream helpers */
static void stream_state_cb(pa_stream *s, void *userdata)
{
    pa_threaded_mainloop *mainloop = userdata;

    switch (pa_stream_get_state(s)) {
        case PA_STREAM_READY:
        case PA_STREAM_FAILED:
        case PA_STREAM_TERMINATED:
            pa_threaded_mainloop_signal(mainloop, 0);
        default:
            break;
    }
}

static void stream_moved_cb(pa_stream *s, void *userdata)
{
130
131
132
133
    aout_instance_t *aout = userdata;
    aout_sys_t *sys = aout->output.p_sys;
    pa_operation *op;
    uint32_t idx = pa_stream_get_device_index(s);
134

135
136
137
138
    msg_Dbg(aout, "connected to device %s (%u)", pa_stream_get_device_name(s), idx);
    op = pa_context_get_sink_info_by_index(sys->context, idx, sink_info_cb, aout);
    if (likely(op != NULL))
        pa_operation_unref(op);
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
}

static int stream_wait(pa_threaded_mainloop *mainloop, pa_stream *stream)
{
    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;
        pa_threaded_mainloop_wait(mainloop);
    }
    return 0;
}

/* 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;
}

/*****************************************************************************
 * Play: play a sound samples buffer
 *****************************************************************************/
static void Play(aout_instance_t *aout)
{
    aout_sys_t *sys = aout->output.p_sys;
    pa_stream *s = sys->stream;

    /* 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. */
    pa_threaded_mainloop_lock(sys->mainloop);

    if (pa_stream_is_corked(sys->stream) > 0) {
        pa_operation *op = pa_stream_cork(s, 0, NULL, NULL);
        if (op != NULL)
            pa_operation_unref(op);
        msg_Dbg(aout, "uncorking");
    }

199
#if 0
200
201
202
    /* This function should be called by the LibVLC core a header of time,
     * but not more than AOUT_MAX_PREPARE. The PulseAudio latency should be
     * shorter than that (though it might not be the case with some evil piece
203
204
205
     * of audio output hardware). So we may need to trigger playback early,
     * (that is to say, short cut the PulseAudio prebuffering). Otherwise,
     * audio and video may be out of synchronization. */
206
207
208
209
210
211
    pa_usec_t latency;
    int negative;
    if (pa_stream_get_latency(s, &latency, &negative) < 0) {
        /* Especially at start of stream, latency may not be known (yet). */
        if (pa_context_errno(sys->context) != PA_ERR_NODATA)
            error(aout, "cannot determine latency", sys->context);
212
213
    } else {
        mtime_t gap = aout_FifoFirstDate(aout, &aout->output.fifo) - mdate()
214
                - latency;
215
216
217
218
219
220

        if (gap > AOUT_PTS_TOLERANCE)
            msg_Dbg(aout, "buffer too early (%"PRId64" us)", gap);
        else if (gap < -AOUT_PTS_TOLERANCE)
            msg_Err(aout, "buffer too late (%"PRId64" us)", -gap);
    }
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#endif
#if 0 /* Fault injector to test underrun recovery */
    static unsigned u = 0;
    if ((++u % 500) == 0) {
        msg_Err(aout, "fault injection");
        msleep(CLOCK_FREQ*2);
    }
#endif

    /* This function is called exactly once per block in the output FIFO, so
     * this for-loop is not necessary.
     * If this function is changed to not always dequeue blocks, be sure to
     * limit the queue size to a reasonable limit to avoid huge leaks. */
    for (;;) {
        block_t *block = aout_FifoPop(aout, &aout->output.fifo);
        if (block == NULL)
            break;

        const void *ptr = data_convert(&block);
        if (unlikely(ptr == NULL))
            break;

        size_t len = block->i_buffer;
        //mtime_t pts = block->i_pts, duration = block->i_length;

        if (pa_stream_write(s, ptr, len, data_free, 0, PA_SEEK_RELATIVE) < 0)
        {
            block_Release(block);
            msg_Err(aout, "cannot write: %s",
                    pa_strerror(pa_context_errno(sys->context)));
        }
    }

    pa_threaded_mainloop_unlock(sys->mainloop);
}

257
258
259
static int VolumeGet(aout_instance_t *aout, audio_volume_t *volp)
{
    aout_sys_t *sys = aout->output.p_sys;
260
    pa_volume_t volume = pa_cvolume_max(&sys->cvolume);
261
262
263
264
265
266
267
268
269
270
271
272
273

    *volp = pa_sw_volume_to_linear(volume) * AOUT_VOLUME_DEFAULT;
    return 0;
}

static int VolumeSet(aout_instance_t *aout, audio_volume_t vol)
{
    aout_sys_t *sys = aout->output.p_sys;
    pa_threaded_mainloop *mainloop = sys->mainloop;
    pa_operation *op;

    uint32_t idx = pa_stream_get_index(sys->stream);
    pa_volume_t volume = pa_sw_volume_from_linear(vol / (float)AOUT_VOLUME_DEFAULT);
274
    pa_cvolume cvolume;
275

276
277
    /* TODO: do not ruin the channel balance (if set outside VLC) */
    /* TODO: notify UI about volume changes by other PulseAudio clients */
278
    pa_cvolume_set(&sys->cvolume, sys->cvolume.channels, volume);
279
280
    pa_sw_cvolume_multiply_scalar(&cvolume, &sys->cvolume, sys->base_volume);
    assert(pa_cvolume_valid(&cvolume));
281
282

    pa_threaded_mainloop_lock(mainloop);
283
    op = pa_context_set_sink_input_volume(sys->context, idx, &cvolume, NULL, NULL);
284
285
286
287
288
289
    if (likely(op != NULL))
        pa_operation_unref(op);
    op = pa_context_set_sink_input_mute(sys->context, idx, volume == PA_VOLUME_MUTED,
                                        NULL, NULL);
    if (likely(op != NULL))
        pa_operation_unref(op);
290
291
292
293
    pa_threaded_mainloop_unlock(mainloop);

    return 0;
}
294

295
296
297
/*****************************************************************************
 * Open: open the audio device
 *****************************************************************************/
298
static int Open(vlc_object_t *obj)
299
{
300
    aout_instance_t *aout = (aout_instance_t *)obj;
301

302
303
    /* Sample format specification */
    struct pa_sample_spec ss;
Danny Wood's avatar
Danny Wood committed
304

305
    switch(aout->output.output.i_format)
Danny Wood's avatar
Danny Wood committed
306
    {
307
        case VLC_CODEC_F64B:
308
            aout->output.output.i_format = VLC_CODEC_F32B;
309
310
        case VLC_CODEC_F32B:
            ss.format = PA_SAMPLE_FLOAT32BE;
311
            break;
312
        case VLC_CODEC_F64L:
313
            aout->output.output.i_format = VLC_CODEC_F32L;
314
315
        case VLC_CODEC_F32L:
            ss.format = PA_SAMPLE_FLOAT32LE;
316
            break;
317
        case VLC_CODEC_FI32:
318
            aout->output.output.i_format = VLC_CODEC_FL32;
319
            ss.format = PA_SAMPLE_FLOAT32NE;
320
            break;
321
322
        case VLC_CODEC_S32B:
            ss.format = PA_SAMPLE_S32BE;
323
            break;
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
        case VLC_CODEC_S32L:
            ss.format = PA_SAMPLE_S32LE;
            break;
        case VLC_CODEC_S24B:
            ss.format = PA_SAMPLE_S24BE;
            break;
        case VLC_CODEC_S24L:
            ss.format = PA_SAMPLE_S24LE;
            break;
        case VLC_CODEC_S16B:
            ss.format = PA_SAMPLE_S16BE;
            break;
        case VLC_CODEC_S16L:
            ss.format = PA_SAMPLE_S16LE;
            break;
        case VLC_CODEC_S8:
340
            aout->output.output.i_format = VLC_CODEC_U8;
341
342
        case VLC_CODEC_U8:
            ss.format = PA_SAMPLE_U8;
343
344
            break;
        default:
345
346
            if (HAVE_FPU)
            {
347
                aout->output.output.i_format = VLC_CODEC_FL32;
348
349
350
351
                ss.format = PA_SAMPLE_FLOAT32NE;
            }
            else
            {
352
                aout->output.output.i_format = VLC_CODEC_S16N;
353
354
355
                ss.format = PA_SAMPLE_S16NE;
            }
            break;
Danny Wood's avatar
Danny Wood committed
356
357
    }

358
359
    ss.rate = aout->output.output.i_rate;
    ss.channels = aout_FormatNbChannels(&aout->output.output);
360
    if (!pa_sample_spec_valid(&ss)) {
361
        msg_Err(aout, "unsupported sample specification");
362
        return VLC_EGENERIC;
363
    }
364

365
    /* Channel mapping (order defined in vlc_aout.h) */
366
367
368
    struct pa_channel_map map;
    map.channels = 0;

369
    if (aout->output.output.i_physical_channels & AOUT_CHAN_LEFT)
370
        map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT;
371
    if (aout->output.output.i_physical_channels & AOUT_CHAN_RIGHT)
372
        map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT;
373
    if (aout->output.output.i_physical_channels & AOUT_CHAN_MIDDLELEFT)
374
        map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
375
    if (aout->output.output.i_physical_channels & AOUT_CHAN_MIDDLERIGHT)
376
        map.map[map.channels++] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
377
378
379
380
381
382
383
384
385
386
387
388
389
    if (aout->output.output.i_physical_channels & AOUT_CHAN_REARLEFT)
        map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_LEFT;
    if (aout->output.output.i_physical_channels & AOUT_CHAN_REARRIGHT)
        map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_RIGHT;
    if (aout->output.output.i_physical_channels & AOUT_CHAN_REARCENTER)
        map.map[map.channels++] = PA_CHANNEL_POSITION_REAR_CENTER;
    if (aout->output.output.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;
    }
390
    if (aout->output.output.i_physical_channels & AOUT_CHAN_LFE)
391
392
393
394
        map.map[map.channels++] = PA_CHANNEL_POSITION_LFE;

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

398
    if (!pa_channel_map_valid(&map)) {
399
        msg_Err(aout, "unsupported channel map");
400
401
402
        return VLC_EGENERIC;
    } else {
        const char *name = pa_channel_map_to_pretty_name(&map);
403
        msg_Dbg(aout, "using %s channel map", (name != NULL) ? name : "?");
404
    }
405

406
    /* Stream parameters */
407
408
    const pa_stream_flags_t flags = PA_STREAM_INTERPOLATE_TIMING
                                  | PA_STREAM_AUTO_TIMING_UPDATE
409
410
                                  | PA_STREAM_ADJUST_LATENCY
                                  | PA_STREAM_START_CORKED;
411

412
    const uint32_t byterate = pa_bytes_per_second(&ss);
413
    struct pa_buffer_attr attr;
414
    /* no point in larger buffers on PA side than VLC */
415
416
    attr.maxlength = -1;
    attr.tlength = byterate * AOUT_MAX_ADVANCE_TIME / CLOCK_FREQ;
417
    attr.prebuf = byterate * AOUT_MAX_PREPARE_TIME / CLOCK_FREQ;
418
419
    attr.minreq = -1;
    attr.fragsize = 0; /* not used for output */
420

421
    /* Allocate structures */
422
    aout_sys_t *sys = malloc(sizeof(*sys));
423
424
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;
425
    aout->output.p_sys = sys;
426
    sys->context = NULL;
427
    sys->stream = NULL;
428
    //sys->byterate = byterate;
429

430
    /* Channel volume */
431
    sys->base_volume = PA_VOLUME_NORM;
432
433
    pa_cvolume_set(&sys->cvolume, ss.channels, PA_VOLUME_NORM);

434
435
436
    /* Allocate threaded main loop */
    pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new();
    if (unlikely(mainloop == NULL)) {
437
438
        free(sys);
        return VLC_ENOMEM;
439
    }
440
    sys->mainloop = mainloop;
441

442
443
    if (pa_threaded_mainloop_start(mainloop) < 0) {
        pa_threaded_mainloop_free(mainloop);
444
445
446
        free(sys);
        return VLC_ENOMEM;
    }
447
448
449
450
451
452
453
454
    pa_threaded_mainloop_lock(mainloop);

    /* Connect to PulseAudio server */
    char *user_agent = var_InheritString(aout, "user-agent");
    pa_context *ctx = pa_context_new(pa_threaded_mainloop_get_api(mainloop),
                                     user_agent);
    free(user_agent);
    if (unlikely(ctx == NULL))
455
        goto fail;
456
    sys->context = ctx;
457

458
459
460
461
    pa_context_set_state_callback(ctx, context_state_cb, mainloop);
    if (pa_context_connect(ctx, NULL, 0, NULL) < 0
     || context_wait(mainloop, ctx)) {
        error(aout, "cannot connect to server", ctx);
462
        goto fail;
463
464
    }

465
466
467
468
469
    /* Create a playback stream */
    pa_stream *s = pa_stream_new(ctx, "audio stream", &ss, &map);
    if (s == NULL) {
        error(aout, "cannot create stream", ctx);
        goto fail;
470
    }
471
472
473
    sys->stream = s;
    pa_stream_set_state_callback(s, stream_state_cb, mainloop);
    pa_stream_set_moved_callback(s, stream_moved_cb, aout);
474

475
    if (pa_stream_connect_playback(s, NULL, &attr, flags, NULL, NULL) < 0
476
477
478
     || stream_wait(mainloop, s)) {
        error(aout, "cannot connect stream", ctx);
        goto fail;
479
    }
480
    stream_moved_cb(s, aout);
481

482
483
    const struct pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
    msg_Dbg(aout, "using buffer metrics: maxlength=%u, tlength=%u, "
484
485
            "prebuf=%u, minreq=%u",
            pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
486

487
488
489
490
    aout->output.i_nb_samples = pba->minreq / pa_frame_size(&ss);
    pa_threaded_mainloop_unlock(mainloop);

    aout->output.pf_play = Play;
491
492
    aout->output.pf_volume_get = VolumeGet;
    aout->output.pf_volume_set = VolumeSet;
493
494
495
    return VLC_SUCCESS;

fail:
496
497
    pa_threaded_mainloop_unlock(mainloop);
    Close(obj);
498
499
500
501
502
503
    return VLC_EGENERIC;
}

/*****************************************************************************
 * Close: close the audio device
 *****************************************************************************/
504
static void Close (vlc_object_t *obj)
505
{
506
    aout_instance_t *aout = (aout_instance_t *)obj;
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
    aout_sys_t *sys = aout->output.p_sys;
    pa_threaded_mainloop *mainloop = sys->mainloop;
    pa_context *ctx = sys->context;
    pa_stream *s = sys->stream;

    pa_threaded_mainloop_lock(mainloop);
    if (s != NULL) {
        pa_operation *op;

        pa_stream_set_write_callback(s, NULL, NULL);
        op = pa_stream_flush(s, NULL, NULL);
        if (op != NULL)
            pa_operation_unref(op);
        op = pa_stream_drain(s, NULL, NULL);
        if (op != NULL)
            pa_operation_unref(op);
        pa_stream_disconnect(s);
        pa_stream_unref(s);
525
    }
526
527
528
529
    if (ctx != NULL)
        pa_context_unref(ctx);
    pa_threaded_mainloop_unlock(mainloop);
    pa_threaded_mainloop_free(mainloop);
530
    free(sys);
531
}