]> git.sesse.net Git - vlc/blob - src/audio_output/dec.c
aout: fix flawed resampling logic
[vlc] / src / audio_output / dec.c
1 /*****************************************************************************
2  * dec.c : audio output API towards decoders
3  *****************************************************************************
4  * Copyright (C) 2002-2007 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <assert.h>
32
33 #include <vlc_common.h>
34 #include <vlc_aout.h>
35 #include <vlc_input.h>
36 #include <vlc_atomic.h>
37
38 #include "aout_internal.h"
39 #include "libvlc.h"
40
41 /**
42  * Creates an audio output
43  */
44 int aout_DecNew( audio_output_t *p_aout,
45                  const audio_sample_format_t *p_format,
46                  const audio_replay_gain_t *p_replay_gain,
47                  const aout_request_vout_t *p_request_vout )
48 {
49     /* Sanitize audio format */
50     if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
51     {
52         msg_Err( p_aout, "incompatible audio channels count with layout mask" );
53         return -1;
54     }
55
56     if( p_format->i_rate > 192000 )
57     {
58         msg_Err( p_aout, "excessive audio sample frequency (%u)",
59                  p_format->i_rate );
60         return -1;
61     }
62     if( p_format->i_rate < 4000 )
63     {
64         msg_Err( p_aout, "too low audio sample frequency (%u)",
65                  p_format->i_rate );
66         return -1;
67     }
68
69     aout_owner_t *owner = aout_owner(p_aout);
70     int ret = 0;
71
72     /* TODO: reduce lock scope depending on decoder's real need */
73     aout_lock( p_aout );
74
75     var_Destroy( p_aout, "stereo-mode" );
76
77     /* Create the audio output stream */
78     owner->volume = aout_volume_New (p_aout, p_replay_gain);
79
80     vlc_atomic_set (&owner->restart, 0);
81     owner->input_format = *p_format;
82     owner->mixer_format = owner->input_format;
83
84     if (aout_OutputNew (p_aout, &owner->mixer_format))
85         goto error;
86     aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
87
88     /* Create the audio filtering "input" pipeline */
89     if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
90                          p_request_vout))
91     {
92         aout_OutputDelete (p_aout);
93 error:
94         aout_volume_Delete (owner->volume);
95         ret = -1;
96         goto error;
97     }
98
99     owner->sync.end = VLC_TS_INVALID;
100     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
101     owner->sync.discontinuity = true;
102     aout_unlock( p_aout );
103
104     atomic_init (&owner->buffers_lost, 0);
105
106     return ret;
107 }
108
109 /**
110  * Stops all plugins involved in the audio output.
111  */
112 void aout_DecDelete (audio_output_t *p_aout)
113 {
114     aout_owner_t *owner = aout_owner (p_aout);
115
116     aout_lock( p_aout );
117     aout_FiltersDelete (p_aout);
118     aout_OutputDelete( p_aout );
119     aout_volume_Delete (owner->volume);
120
121     var_Destroy( p_aout, "stereo-mode" );
122
123     aout_unlock( p_aout );
124 }
125
126 #define AOUT_RESTART_OUTPUT 1
127 #define AOUT_RESTART_INPUT  2
128 static int aout_CheckRestart (audio_output_t *aout)
129 {
130     aout_owner_t *owner = aout_owner (aout);
131
132     aout_assert_locked (aout);
133
134     int restart = vlc_atomic_swap (&owner->restart, 0);
135     if (likely(restart == 0))
136         return 0;
137
138     assert (restart & AOUT_RESTART_INPUT);
139
140     const aout_request_vout_t request_vout = owner->request_vout;
141
142     aout_FiltersDelete (aout);
143
144     /* Reinitializes the output */
145     if (restart & AOUT_RESTART_OUTPUT)
146     {
147         aout_OutputDelete (aout);
148         owner->mixer_format = owner->input_format;
149         if (aout_OutputNew (aout, &owner->mixer_format))
150             abort (); /* FIXME we are officially screwed */
151         aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
152     }
153
154     owner->sync.end = VLC_TS_INVALID;
155     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
156
157     if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
158                          &request_vout))
159     {
160         abort (); /* FIXME */
161     }
162     return 0;
163 }
164
165 /**
166  * Marks the audio output for restart, to update any parameter of the output
167  * plug-in (e.g. output device or channel mapping).
168  */
169 static void aout_RequestRestart (audio_output_t *aout)
170 {
171     aout_owner_t *owner = aout_owner (aout);
172
173     /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
174     vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
175 }
176
177 int aout_ChannelsRestart (vlc_object_t *obj, const char *varname,
178                           vlc_value_t oldval, vlc_value_t newval, void *data)
179 {
180     audio_output_t *aout = (audio_output_t *)obj;
181     (void)oldval; (void)newval; (void)data;
182
183     if (!strcmp (varname, "audio-device"))
184     {
185         /* This is supposed to be a significant change and supposes
186          * rebuilding the channel choices. */
187         var_Destroy (aout, "stereo-mode");
188     }
189     aout_RequestRestart (aout);
190     return 0;
191 }
192
193 /**
194  * This function will safely mark aout input to be restarted as soon as
195  * possible to take configuration changes into account
196  */
197 void aout_InputRequestRestart (audio_output_t *aout)
198 {
199     aout_owner_t *owner = aout_owner (aout);
200
201     vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
202 }
203
204
205 /*
206  * Buffer management
207  */
208
209 /*****************************************************************************
210  * aout_DecNewBuffer : ask for a new empty buffer
211  *****************************************************************************/
212 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
213 {
214     /* NOTE: the caller is responsible for serializing input change */
215     aout_owner_t *owner = aout_owner (aout);
216
217     size_t length = samples * owner->input_format.i_bytes_per_frame
218                             / owner->input_format.i_frame_length;
219     block_t *block = block_Alloc( length );
220     if( likely(block != NULL) )
221     {
222         block->i_nb_samples = samples;
223         block->i_pts = block->i_length = 0;
224     }
225     return block;
226 }
227
228 /*****************************************************************************
229  * aout_DecDeleteBuffer : destroy an undecoded buffer
230  *****************************************************************************/
231 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
232 {
233     (void) aout;
234     block_Release (block);
235 }
236
237 static void aout_StopResampling (audio_output_t *aout)
238 {
239     aout_owner_t *owner = aout_owner (aout);
240
241     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
242     aout_FiltersAdjustResampling (aout, 0);
243 }
244
245 static void aout_DecSilence (audio_output_t *aout, mtime_t length)
246 {
247     aout_owner_t *owner = aout_owner (aout);
248     const audio_sample_format_t *fmt = &owner->mixer_format;
249     size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
250     block_t *block;
251
252     if (AOUT_FMT_SPDIF(fmt))
253         block = block_Alloc (4 * frames);
254     else
255         block = block_Alloc (frames * fmt->i_bytes_per_frame);
256     if (unlikely(block == NULL))
257         return; /* uho! */
258
259     msg_Dbg (aout, "inserting %zu zeroes", frames);
260     memset (block->p_buffer, 0, block->i_buffer);
261     block->i_nb_samples = frames;
262     block->i_length = length;
263     /* FIXME: PTS... */
264     aout_OutputPlay (aout, block);
265 }
266
267 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
268                                  int input_rate)
269 {
270     aout_owner_t *owner = aout_owner (aout);
271     mtime_t aout_pts, drift;
272
273     /**
274      * Depending on the drift between the actual and intended playback times,
275      * the audio core may ignore the drift, trigger upsampling or downsampling,
276      * insert silence or even discard samples.
277      * Future VLC versions may instead adjust the input rate.
278      *
279      * The audio output plugin is responsible for estimating its actual
280      * playback time, or rather the estimated time when the next sample will
281      * be played. (The actual playback time is always the current time, that is
282      * to say mdate(). It is not an useful statistic.)
283      *
284      * Most audio output plugins can estimate the delay until playback of
285      * the next sample to be written to the buffer, or equally the time until
286      * all samples in the buffer will have been played. Then:
287      *    pts = mdate() + delay
288      */
289     if (aout_OutputTimeGet (aout, &aout_pts) != 0)
290         return; /* nothing can be done if timing is unknown */
291     drift = aout_pts - dec_pts;
292
293     /* Late audio output.
294      * This can happen due to insufficient caching, scheduling jitter
295      * or bug in the decoder. Ideally, the output would seek backward. But that
296      * is not portable, not supported by some hardware and often unsafe/buggy
297      * where supported. The other alternative is to flush the buffers
298      * completely. */
299     if (drift > (owner->sync.discontinuity ? 0
300                   : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
301     {
302         if (!owner->sync.discontinuity)
303             msg_Warn (aout, "playback way too late (%"PRId64"): "
304                       "flushing buffers", drift);
305         else
306             msg_Dbg (aout, "playback too late (%"PRId64"): "
307                      "flushing buffers", drift);
308         aout_OutputFlush (aout, false);
309
310         aout_StopResampling (aout);
311         owner->sync.end = VLC_TS_INVALID;
312         owner->sync.discontinuity = true;
313
314         /* Now the output might be too early... Recheck. */
315         if (aout_OutputTimeGet (aout, &aout_pts) != 0)
316             return; /* nothing can be done if timing is unknown */
317         drift = aout_pts - dec_pts;
318     }
319
320     /* Early audio output.
321      * This is rare except at startup when the buffers are still empty. */
322     if (drift < (owner->sync.discontinuity ? 0
323                 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
324     {
325         if (!owner->sync.discontinuity)
326             msg_Warn (aout, "playback way too early (%"PRId64"): "
327                       "playing silence", drift);
328         aout_DecSilence (aout, -drift);
329
330         aout_StopResampling (aout);
331         owner->sync.discontinuity = true;
332         drift = 0;
333     }
334
335     /* Resampling */
336     if (drift > +AOUT_MAX_PTS_DELAY
337      && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
338     {
339         msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
340                   drift);
341         owner->sync.resamp_type = AOUT_RESAMPLING_UP;
342         owner->sync.resamp_start_drift = +drift;
343     }
344     if (drift < -AOUT_MAX_PTS_ADVANCE
345      && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
346     {
347         msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
348                   drift);
349         owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
350         owner->sync.resamp_start_drift = -drift;
351     }
352
353     if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
354         return; /* Everything is fine. Nothing to do. */
355
356     if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
357     {   /* If the drift is ever increasing, then something is seriously wrong.
358          * Cease resampling and hope for the best. */
359         msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
360                   "stopping resampling", drift);
361         aout_StopResampling (aout);
362         return;
363     }
364
365     /* Resampling has been triggered earlier. This checks if it needs to be
366      * increased or decreased. Resampling rate changes must be kept slow for
367      * the comfort of listeners. */
368     int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
369
370     if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
371         /* If the drift has been reduced from more than half its initial
372          * value, then it is time to switch back the resampling direction. */
373         adj *= -1;
374
375     if (!aout_FiltersAdjustResampling (aout, adj))
376     {   /* Everything is back to normal: stop resampling. */
377         owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
378         msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
379     }
380 }
381
382 /*****************************************************************************
383  * aout_DecPlay : filter & mix the decoded buffer
384  *****************************************************************************/
385 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
386 {
387     aout_owner_t *owner = aout_owner (aout);
388
389     assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
390     assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
391     assert (block->i_pts >= VLC_TS_0);
392
393     block->i_length = CLOCK_FREQ * block->i_nb_samples
394                                  / owner->input_format.i_rate;
395
396     aout_lock (aout);
397     if (unlikely(aout_CheckRestart (aout)))
398         goto drop; /* Pipeline is unrecoverably broken :-( */
399
400     const mtime_t now = mdate (), advance = block->i_pts - now;
401     if (advance < AOUT_MIN_PREPARE_TIME)
402     {   /* Late buffer can be caused by bugs in the decoder, by scheduling
403          * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
404          * insufficient. We assume the PTS is wrong and play the buffer anyway:
405          * Hopefully video has encountered a similar PTS problem as audio. */
406         msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
407         goto drop;
408     }
409     if (advance > AOUT_MAX_ADVANCE_TIME)
410     {   /* Early buffers can only be caused by bugs in the decoder. */
411         msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
412         goto drop;
413     }
414     if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
415         owner->sync.discontinuity = true;
416
417     block = aout_FiltersPlay (aout, block, input_rate);
418     if (block == NULL)
419         goto lost;
420
421     /* Software volume */
422     aout_volume_Amplify (owner->volume, block);
423
424     /* Drift correction */
425     aout_DecSynchronize (aout, block->i_pts, input_rate);
426
427     /* Output */
428     owner->sync.end = block->i_pts + block->i_length + 1;
429     owner->sync.discontinuity = false;
430     aout_OutputPlay (aout, block);
431 out:
432     aout_unlock (aout);
433     return 0;
434 drop:
435     owner->sync.discontinuity = true;
436     block_Release (block);
437 lost:
438     atomic_fetch_add(&owner->buffers_lost, 1);
439     goto out;
440 }
441
442 int aout_DecGetResetLost (audio_output_t *aout)
443 {
444     aout_owner_t *owner = aout_owner (aout);
445     return atomic_exchange(&owner->buffers_lost, 0);
446 }
447
448 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
449 {
450     aout_owner_t *owner = aout_owner (aout);
451
452     aout_lock (aout);
453     if (owner->sync.end != VLC_TS_INVALID)
454     {
455         if (paused)
456             owner->sync.end -= date;
457         else
458             owner->sync.end += date;
459     }
460     aout_OutputPause (aout, paused, date);
461     aout_unlock (aout);
462 }
463
464 void aout_DecFlush (audio_output_t *aout)
465 {
466     aout_owner_t *owner = aout_owner (aout);
467
468     aout_lock (aout);
469     owner->sync.end = VLC_TS_INVALID;
470     aout_OutputFlush (aout, false);
471     aout_unlock (aout);
472 }
473
474 bool aout_DecIsEmpty (audio_output_t *aout)
475 {
476     aout_owner_t *owner = aout_owner (aout);
477     mtime_t now = mdate ();
478     bool empty = true;
479
480     aout_lock (aout);
481     if (owner->sync.end != VLC_TS_INVALID)
482         empty = owner->sync.end <= now;
483     if (empty)
484         /* The last PTS has elapsed already. So the underlying audio output
485          * buffer should be empty or almost. Thus draining should be fast
486          * and will not block the caller too long. */
487         aout_OutputFlush (aout, true);
488     aout_unlock (aout);
489     return empty;
490 }