dec.c 15.9 KB
Newer Older
1
2
3
/*****************************************************************************
 * dec.c : audio output API towards decoders
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5
 * $Id$
6
7
8
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
Jean-Baptiste Kempf's avatar
LGPL    
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
 * (at your option) any later version.
13
 *
14
15
 * 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
LGPL    
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
LGPL    
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
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27
28
29
30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
32
#include <assert.h>

33
#include <vlc_common.h>
zorglub's avatar
zorglub committed
34
35
#include <vlc_aout.h>
#include <vlc_input.h>
36
#include <vlc_atomic.h>
zorglub's avatar
zorglub committed
37

38
#include "aout_internal.h"
39
#include "libvlc.h"
40

41
42
43
/**
 * Creates an audio output
 */
44
45
46
47
int aout_DecNew( audio_output_t *p_aout,
                 const audio_sample_format_t *p_format,
                 const audio_replay_gain_t *p_replay_gain,
                 const aout_request_vout_t *p_request_vout )
48
{
49
    /* Sanitize audio format */
50
51
52
    if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
    {
        msg_Err( p_aout, "incompatible audio channels count with layout mask" );
53
        return -1;
54
    }
55
56
57
58
59

    if( p_format->i_rate > 192000 )
    {
        msg_Err( p_aout, "excessive audio sample frequency (%u)",
                 p_format->i_rate );
60
        return -1;
61
    }
62
63
64
65
    if( p_format->i_rate < 4000 )
    {
        msg_Err( p_aout, "too low audio sample frequency (%u)",
                 p_format->i_rate );
66
        return -1;
67
    }
68

69
    aout_owner_t *owner = aout_owner(p_aout);
70

71
    /* TODO: reduce lock scope depending on decoder's real need */
72
    aout_lock( p_aout );
73

74
    var_Destroy( p_aout, "stereo-mode" );
75

76
    /* Create the audio output stream */
77
    owner->volume = aout_volume_New (p_aout, p_replay_gain);
78
79
80
81
82
83

    vlc_atomic_set (&owner->restart, 0);
    owner->input_format = *p_format;
    owner->mixer_format = owner->input_format;

    if (aout_OutputNew (p_aout, &owner->mixer_format))
84
        goto error;
85
    aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
86
87

    /* Create the audio filtering "input" pipeline */
88
89
    if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
                         p_request_vout))
90
    {
91
        aout_OutputDelete (p_aout);
92
error:
93
        aout_volume_Delete (owner->volume);
94
95
        aout_unlock (p_aout);
        return -1;
96
    }
97

98
    owner->sync.end = VLC_TS_INVALID;
99
    owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
100
    owner->sync.discontinuity = true;
101
    aout_unlock( p_aout );
102

103
    atomic_init (&owner->buffers_lost, 0);
104
    return 0;
105
106
}

107
108
109
/**
 * Stops all plugins involved in the audio output.
 */
110
void aout_DecDelete (audio_output_t *p_aout)
111
{
112
113
    aout_owner_t *owner = aout_owner (p_aout);

114
    aout_lock( p_aout );
115
    aout_FiltersDelete (p_aout);
116
117
118
    aout_OutputDelete( p_aout );
    aout_volume_Delete (owner->volume);

119
    var_Destroy( p_aout, "stereo-mode" );
120

121
    aout_unlock( p_aout );
122
123
}

124
125
#define AOUT_RESTART_OUTPUT 1
#define AOUT_RESTART_INPUT  2
126
static int aout_CheckRestart (audio_output_t *aout)
127
128
129
130
131
{
    aout_owner_t *owner = aout_owner (aout);

    aout_assert_locked (aout);

132
133
    int restart = vlc_atomic_swap (&owner->restart, 0);
    if (likely(restart == 0))
134
        return 0;
135

136
    assert (restart & AOUT_RESTART_INPUT);
137

138
    const aout_request_vout_t request_vout = owner->request_vout;
139

140
141
    aout_FiltersDelete (aout);

142
143
    /* Reinitializes the output */
    if (restart & AOUT_RESTART_OUTPUT)
144
    {
145
        aout_OutputDelete (aout);
146
147
        owner->mixer_format = owner->input_format;
        if (aout_OutputNew (aout, &owner->mixer_format))
148
            abort (); /* FIXME we are officially screwed */
149
        aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
150
151
    }

152
    owner->sync.end = VLC_TS_INVALID;
153
154
    owner->sync.resamp_type = AOUT_RESAMPLING_NONE;

155
    if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
156
157
158
159
160
                         &request_vout))
    {
        abort (); /* FIXME */
    }
    return 0;
161
162
}

163
/**
164
165
 * Marks the audio output for restart, to update any parameter of the output
 * plug-in (e.g. output device or channel mapping).
166
 */
167
static void aout_RequestRestart (audio_output_t *aout)
168
169
170
{
    aout_owner_t *owner = aout_owner (aout);

171
172
    /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
    vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
173
174
}

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
int aout_ChannelsRestart (vlc_object_t *obj, const char *varname,
                          vlc_value_t oldval, vlc_value_t newval, void *data)
{
    audio_output_t *aout = (audio_output_t *)obj;
    (void)oldval; (void)newval; (void)data;

    if (!strcmp (varname, "audio-device"))
    {
        /* This is supposed to be a significant change and supposes
         * rebuilding the channel choices. */
        var_Destroy (aout, "stereo-mode");
    }
    aout_RequestRestart (aout);
    return 0;
}

191
192
193
194
195
196
/**
 * This function will safely mark aout input to be restarted as soon as
 * possible to take configuration changes into account
 */
void aout_InputRequestRestart (audio_output_t *aout)
{
197
198
199
    aout_owner_t *owner = aout_owner (aout);

    vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
200
201
}

202
203
204
205
206
207
208
209

/*
 * Buffer management
 */

/*****************************************************************************
 * aout_DecNewBuffer : ask for a new empty buffer
 *****************************************************************************/
210
block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
211
{
212
213
214
    /* NOTE: the caller is responsible for serializing input change */
    aout_owner_t *owner = aout_owner (aout);

215
216
    size_t length = samples * owner->input_format.i_bytes_per_frame
                            / owner->input_format.i_frame_length;
217
    block_t *block = block_Alloc( length );
218
219
    if( likely(block != NULL) )
    {
220
        block->i_nb_samples = samples;
221
222
223
        block->i_pts = block->i_length = 0;
    }
    return block;
224
225
226
227
228
}

/*****************************************************************************
 * aout_DecDeleteBuffer : destroy an undecoded buffer
 *****************************************************************************/
229
void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
230
{
231
    (void) aout;
232
    block_Release (block);
233
234
}

235
236
237
238
239
240
241
242
static void aout_StopResampling (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
    aout_FiltersAdjustResampling (aout, 0);
}

243
static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
    aout_owner_t *owner = aout_owner (aout);
    const audio_sample_format_t *fmt = &owner->mixer_format;
    size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
    block_t *block;

    if (AOUT_FMT_SPDIF(fmt))
        block = block_Alloc (4 * frames);
    else
        block = block_Alloc (frames * fmt->i_bytes_per_frame);
    if (unlikely(block == NULL))
        return; /* uho! */

    msg_Dbg (aout, "inserting %zu zeroes", frames);
    memset (block->p_buffer, 0, block->i_buffer);
    block->i_nb_samples = frames;
260
261
    block->i_pts = pts;
    block->i_dts = pts;
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
    block->i_length = length;
    aout_OutputPlay (aout, block);
}

static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
                                 int input_rate)
{
    aout_owner_t *owner = aout_owner (aout);
    mtime_t aout_pts, drift;

    /**
     * Depending on the drift between the actual and intended playback times,
     * the audio core may ignore the drift, trigger upsampling or downsampling,
     * insert silence or even discard samples.
     * Future VLC versions may instead adjust the input rate.
     *
     * The audio output plugin is responsible for estimating its actual
     * playback time, or rather the estimated time when the next sample will
     * be played. (The actual playback time is always the current time, that is
     * to say mdate(). It is not an useful statistic.)
     *
     * Most audio output plugins can estimate the delay until playback of
     * the next sample to be written to the buffer, or equally the time until
     * all samples in the buffer will have been played. Then:
     *    pts = mdate() + delay
     */
    if (aout_OutputTimeGet (aout, &aout_pts) != 0)
        return; /* nothing can be done if timing is unknown */
    drift = aout_pts - dec_pts;

292
293
294
295
296
297
    /* Late audio output.
     * This can happen due to insufficient caching, scheduling jitter
     * or bug in the decoder. Ideally, the output would seek backward. But that
     * is not portable, not supported by some hardware and often unsafe/buggy
     * where supported. The other alternative is to flush the buffers
     * completely. */
298
299
    if (drift > (owner->sync.discontinuity ? 0
                  : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
300
    {
301
        if (!owner->sync.discontinuity)
302
303
304
305
            msg_Warn (aout, "playback way too late (%"PRId64"): "
                      "flushing buffers", drift);
        else
            msg_Dbg (aout, "playback too late (%"PRId64"): "
306
                     "flushing buffers", drift);
307
308
        aout_OutputFlush (aout, false);

309
310
        aout_StopResampling (aout);
        owner->sync.end = VLC_TS_INVALID;
311
312
313
314
315
316
        owner->sync.discontinuity = true;

        /* Now the output might be too early... Recheck. */
        if (aout_OutputTimeGet (aout, &aout_pts) != 0)
            return; /* nothing can be done if timing is unknown */
        drift = aout_pts - dec_pts;
317
318
    }

319
320
321
322
    /* Early audio output.
     * This is rare except at startup when the buffers are still empty. */
    if (drift < (owner->sync.discontinuity ? 0
                : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
323
    {
324
325
326
        if (!owner->sync.discontinuity)
            msg_Warn (aout, "playback way too early (%"PRId64"): "
                      "playing silence", drift);
327
        aout_DecSilence (aout, -drift, dec_pts);
328
329
330
331

        aout_StopResampling (aout);
        owner->sync.discontinuity = true;
        drift = 0;
332
    }
333
334

    /* Resampling */
335
336
    if (drift > +AOUT_MAX_PTS_DELAY
     && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
337
    {
338
339
        msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
                  drift);
340
        owner->sync.resamp_type = AOUT_RESAMPLING_UP;
341
        owner->sync.resamp_start_drift = +drift;
342
    }
343
344
    if (drift < -AOUT_MAX_PTS_ADVANCE
     && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
345
    {
346
347
        msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
                  drift);
348
        owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
349
        owner->sync.resamp_start_drift = -drift;
350
351
    }

352
353
354
    if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
        return; /* Everything is fine. Nothing to do. */

355
356
357
358
359
360
361
362
363
    if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
    {   /* If the drift is ever increasing, then something is seriously wrong.
         * Cease resampling and hope for the best. */
        msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
                  "stopping resampling", drift);
        aout_StopResampling (aout);
        return;
    }

364
365
366
    /* Resampling has been triggered earlier. This checks if it needs to be
     * increased or decreased. Resampling rate changes must be kept slow for
     * the comfort of listeners. */
367
368
369
370
371
372
    int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;

    if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
        /* If the drift has been reduced from more than half its initial
         * value, then it is time to switch back the resampling direction. */
        adj *= -1;
373
374

    if (!aout_FiltersAdjustResampling (aout, adj))
375
    {   /* Everything is back to normal: stop resampling. */
376
377
378
379
380
        owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
        msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
    }
}

381
382
383
/*****************************************************************************
 * aout_DecPlay : filter & mix the decoded buffer
 *****************************************************************************/
384
int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
385
{
386
    aout_owner_t *owner = aout_owner (aout);
387

388
389
390
    assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
    assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
    assert (block->i_pts >= VLC_TS_0);
391

392
393
    block->i_length = CLOCK_FREQ * block->i_nb_samples
                                 / owner->input_format.i_rate;
394

395
396
397
398
    aout_lock (aout);
    if (unlikely(aout_CheckRestart (aout)))
        goto drop; /* Pipeline is unrecoverably broken :-( */

399
    const mtime_t now = mdate (), advance = block->i_pts - now;
400
    if (advance < -AOUT_MAX_PTS_DELAY)
401
402
403
404
405
    {   /* Late buffer can be caused by bugs in the decoder, by scheduling
         * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
         * insufficient. We assume the PTS is wrong and play the buffer anyway:
         * Hopefully video has encountered a similar PTS problem as audio. */
        msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
406
407
        goto drop;
    }
408
409
410
    if (advance > AOUT_MAX_ADVANCE_TIME)
    {   /* Early buffers can only be caused by bugs in the decoder. */
        msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
411
412
        goto drop;
    }
413
414
    if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
        owner->sync.discontinuity = true;
415

416
417
    block = aout_FiltersPlay (aout, block, input_rate);
    if (block == NULL)
418
        goto lost;
419
420
421
422

    /* Software volume */
    aout_volume_Amplify (owner->volume, block);

423
424
425
    /* Drift correction */
    aout_DecSynchronize (aout, block->i_pts, input_rate);

426
    /* Output */
427
    owner->sync.end = block->i_pts + block->i_length + 1;
428
    owner->sync.discontinuity = false;
429
430
431
    aout_OutputPlay (aout, block);
out:
    aout_unlock (aout);
432
    return 0;
433
drop:
434
    owner->sync.discontinuity = true;
435
    block_Release (block);
436
lost:
437
    atomic_fetch_add(&owner->buffers_lost, 1);
438
    goto out;
439
}
440

441
int aout_DecGetResetLost (audio_output_t *aout)
442
{
443
    aout_owner_t *owner = aout_owner (aout);
444
    return atomic_exchange(&owner->buffers_lost, 0);
445
446
}

447
void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
Laurent Aimar's avatar
Laurent Aimar committed
448
{
449
    aout_owner_t *owner = aout_owner (aout);
450

451
    aout_lock (aout);
452
453
454
455
456
457
458
    if (owner->sync.end != VLC_TS_INVALID)
    {
        if (paused)
            owner->sync.end -= date;
        else
            owner->sync.end += date;
    }
459
460
    aout_OutputPause (aout, paused, date);
    aout_unlock (aout);
Laurent Aimar's avatar
Laurent Aimar committed
461
462
}

463
void aout_DecFlush (audio_output_t *aout)
Laurent Aimar's avatar
Laurent Aimar committed
464
{
465
466
467
    aout_owner_t *owner = aout_owner (aout);

    aout_lock (aout);
468
    owner->sync.end = VLC_TS_INVALID;
469
470
    aout_OutputFlush (aout, false);
    aout_unlock (aout);
Laurent Aimar's avatar
Laurent Aimar committed
471
472
}

473
bool aout_DecIsEmpty (audio_output_t *aout)
474
{
475
    aout_owner_t *owner = aout_owner (aout);
476
477
    mtime_t now = mdate ();
    bool empty = true;
478

479
    aout_lock (aout);
480
481
    if (owner->sync.end != VLC_TS_INVALID)
        empty = owner->sync.end <= now;
482
483
484
485
486
    if (empty)
        /* The last PTS has elapsed already. So the underlying audio output
         * buffer should be empty or almost. Thus draining should be fast
         * and will not block the caller too long. */
        aout_OutputFlush (aout, true);
487
    aout_unlock (aout);
488
    return empty;
489
}