]> git.sesse.net Git - vlc/blob - src/audio_output/dec.c
aout: add some debug when restarting
[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
37 #include "aout_internal.h"
38 #include "libvlc.h"
39
40 /**
41  * Creates an audio output
42  */
43 int aout_DecNew( audio_output_t *p_aout,
44                  const audio_sample_format_t *p_format,
45                  const audio_replay_gain_t *p_replay_gain,
46                  const aout_request_vout_t *p_request_vout )
47 {
48     /* Sanitize audio format */
49     if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
50     {
51         msg_Err( p_aout, "incompatible audio channels count with layout mask" );
52         return -1;
53     }
54
55     if( p_format->i_rate > 192000 )
56     {
57         msg_Err( p_aout, "excessive audio sample frequency (%u)",
58                  p_format->i_rate );
59         return -1;
60     }
61     if( p_format->i_rate < 4000 )
62     {
63         msg_Err( p_aout, "too low audio sample frequency (%u)",
64                  p_format->i_rate );
65         return -1;
66     }
67
68     aout_owner_t *owner = aout_owner(p_aout);
69
70     /* TODO: reduce lock scope depending on decoder's real need */
71     aout_lock( p_aout );
72
73     var_Destroy( p_aout, "stereo-mode" );
74
75     /* Create the audio output stream */
76     owner->volume = aout_volume_New (p_aout, p_replay_gain);
77
78     atomic_store (&owner->restart, 0);
79     owner->input_format = *p_format;
80     owner->mixer_format = owner->input_format;
81
82     if (aout_OutputNew (p_aout, &owner->mixer_format))
83         goto error;
84     aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
85
86     /* Create the audio filtering "input" pipeline */
87     if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
88                          p_request_vout))
89     {
90         aout_OutputDelete (p_aout);
91 error:
92         aout_volume_Delete (owner->volume);
93         aout_unlock (p_aout);
94         return -1;
95     }
96
97     owner->sync.end = VLC_TS_INVALID;
98     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
99     owner->sync.discontinuity = true;
100     aout_unlock( p_aout );
101
102     atomic_init (&owner->buffers_lost, 0);
103     return 0;
104 }
105
106 /**
107  * Stops all plugins involved in the audio output.
108  */
109 void aout_DecDelete (audio_output_t *aout)
110 {
111     aout_owner_t *owner = aout_owner (aout);
112
113     aout_lock (aout);
114     if (owner->mixer_format.i_format)
115     {
116         aout_FiltersDelete (aout);
117         aout_OutputDelete (aout);
118     }
119     aout_volume_Delete (owner->volume);
120     aout_unlock (aout);
121     var_Destroy (aout, "stereo-mode");
122 }
123
124 static int aout_CheckReady (audio_output_t *aout)
125 {
126     aout_owner_t *owner = aout_owner (aout);
127
128     aout_assert_locked (aout);
129
130     int restart = atomic_exchange (&owner->restart, 0);
131     if (unlikely(restart))
132     {
133         const aout_request_vout_t request_vout = owner->request_vout;
134
135         if (owner->mixer_format.i_format)
136             aout_FiltersDelete (aout);
137
138         if (restart & AOUT_RESTART_OUTPUT)
139         {   /* Reinitializes the output */
140             msg_Dbg (aout, "restarting output...");
141             if (owner->mixer_format.i_format)
142                 aout_OutputDelete (aout);
143             owner->mixer_format = owner->input_format;
144             if (aout_OutputNew (aout, &owner->mixer_format))
145                 owner->mixer_format.i_format = 0;
146             aout_volume_SetFormat (owner->volume,
147                                    owner->mixer_format.i_format);
148         }
149
150         msg_Dbg (aout, "restarting filters...");
151         owner->sync.end = VLC_TS_INVALID;
152         owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
153
154         if (owner->mixer_format.i_format
155          && aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
156                              &request_vout))
157         {
158             aout_OutputDelete (aout);
159             owner->mixer_format.i_format = 0;
160         }
161     }
162     return (owner->mixer_format.i_format) ? 0 : -1;
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 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
170 {
171     aout_owner_t *owner = aout_owner (aout);
172     atomic_fetch_or (&owner->restart, mode);
173     msg_Dbg (aout, "restart requested (%u)", mode);
174 }
175
176 /*
177  * Buffer management
178  */
179
180 /*****************************************************************************
181  * aout_DecNewBuffer : ask for a new empty buffer
182  *****************************************************************************/
183 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
184 {
185     /* NOTE: the caller is responsible for serializing input change */
186     aout_owner_t *owner = aout_owner (aout);
187
188     size_t length = samples * owner->input_format.i_bytes_per_frame
189                             / owner->input_format.i_frame_length;
190     block_t *block = block_Alloc( length );
191     if( likely(block != NULL) )
192     {
193         block->i_nb_samples = samples;
194         block->i_pts = block->i_length = 0;
195     }
196     return block;
197 }
198
199 /*****************************************************************************
200  * aout_DecDeleteBuffer : destroy an undecoded buffer
201  *****************************************************************************/
202 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
203 {
204     (void) aout;
205     block_Release (block);
206 }
207
208 static void aout_StopResampling (audio_output_t *aout)
209 {
210     aout_owner_t *owner = aout_owner (aout);
211
212     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
213     aout_FiltersAdjustResampling (aout, 0);
214 }
215
216 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
217 {
218     aout_owner_t *owner = aout_owner (aout);
219     const audio_sample_format_t *fmt = &owner->mixer_format;
220     size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
221     block_t *block;
222
223     if (AOUT_FMT_SPDIF(fmt))
224         block = block_Alloc (4 * frames);
225     else
226         block = block_Alloc (frames * fmt->i_bytes_per_frame);
227     if (unlikely(block == NULL))
228         return; /* uho! */
229
230     msg_Dbg (aout, "inserting %zu zeroes", frames);
231     memset (block->p_buffer, 0, block->i_buffer);
232     block->i_nb_samples = frames;
233     block->i_pts = pts;
234     block->i_dts = pts;
235     block->i_length = length;
236     aout_OutputPlay (aout, block);
237 }
238
239 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
240                                  int input_rate)
241 {
242     aout_owner_t *owner = aout_owner (aout);
243     mtime_t drift;
244
245     /**
246      * Depending on the drift between the actual and intended playback times,
247      * the audio core may ignore the drift, trigger upsampling or downsampling,
248      * insert silence or even discard samples.
249      * Future VLC versions may instead adjust the input rate.
250      *
251      * The audio output plugin is responsible for estimating its actual
252      * playback time, or rather the estimated time when the next sample will
253      * be played. (The actual playback time is always the current time, that is
254      * to say mdate(). It is not an useful statistic.)
255      *
256      * Most audio output plugins can estimate the delay until playback of
257      * the next sample to be written to the buffer, or equally the time until
258      * all samples in the buffer will have been played. Then:
259      *    pts = mdate() + delay
260      */
261     if (aout_OutputTimeGet (aout, &drift) != 0)
262         return; /* nothing can be done if timing is unknown */
263     drift += mdate () - dec_pts;
264
265     /* Late audio output.
266      * This can happen due to insufficient caching, scheduling jitter
267      * or bug in the decoder. Ideally, the output would seek backward. But that
268      * is not portable, not supported by some hardware and often unsafe/buggy
269      * where supported. The other alternative is to flush the buffers
270      * completely. */
271     if (drift > (owner->sync.discontinuity ? 0
272                   : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
273     {
274         if (!owner->sync.discontinuity)
275             msg_Warn (aout, "playback way too late (%"PRId64"): "
276                       "flushing buffers", drift);
277         else
278             msg_Dbg (aout, "playback too late (%"PRId64"): "
279                      "flushing buffers", drift);
280         aout_OutputFlush (aout, false);
281
282         aout_StopResampling (aout);
283         owner->sync.end = VLC_TS_INVALID;
284         owner->sync.discontinuity = true;
285
286         /* Now the output might be too early... Recheck. */
287         if (aout_OutputTimeGet (aout, &drift) != 0)
288             return; /* nothing can be done if timing is unknown */
289         drift += mdate () - dec_pts;
290     }
291
292     /* Early audio output.
293      * This is rare except at startup when the buffers are still empty. */
294     if (drift < (owner->sync.discontinuity ? 0
295                 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
296     {
297         if (!owner->sync.discontinuity)
298             msg_Warn (aout, "playback way too early (%"PRId64"): "
299                       "playing silence", drift);
300         aout_DecSilence (aout, -drift, dec_pts);
301
302         aout_StopResampling (aout);
303         owner->sync.discontinuity = true;
304         drift = 0;
305     }
306
307     /* Resampling */
308     if (drift > +AOUT_MAX_PTS_DELAY
309      && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
310     {
311         msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
312                   drift);
313         owner->sync.resamp_type = AOUT_RESAMPLING_UP;
314         owner->sync.resamp_start_drift = +drift;
315     }
316     if (drift < -AOUT_MAX_PTS_ADVANCE
317      && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
318     {
319         msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
320                   drift);
321         owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
322         owner->sync.resamp_start_drift = -drift;
323     }
324
325     if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
326         return; /* Everything is fine. Nothing to do. */
327
328     if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
329     {   /* If the drift is ever increasing, then something is seriously wrong.
330          * Cease resampling and hope for the best. */
331         msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
332                   "stopping resampling", drift);
333         aout_StopResampling (aout);
334         return;
335     }
336
337     /* Resampling has been triggered earlier. This checks if it needs to be
338      * increased or decreased. Resampling rate changes must be kept slow for
339      * the comfort of listeners. */
340     int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
341
342     if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
343         /* If the drift has been reduced from more than half its initial
344          * value, then it is time to switch back the resampling direction. */
345         adj *= -1;
346
347     if (!aout_FiltersAdjustResampling (aout, adj))
348     {   /* Everything is back to normal: stop resampling. */
349         owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
350         msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
351     }
352 }
353
354 /*****************************************************************************
355  * aout_DecPlay : filter & mix the decoded buffer
356  *****************************************************************************/
357 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
358 {
359     aout_owner_t *owner = aout_owner (aout);
360
361     assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
362     assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
363     assert (block->i_pts >= VLC_TS_0);
364
365     block->i_length = CLOCK_FREQ * block->i_nb_samples
366                                  / owner->input_format.i_rate;
367
368     aout_lock (aout);
369     if (unlikely(aout_CheckReady (aout)))
370         goto drop; /* Pipeline is unrecoverably broken :-( */
371
372     const mtime_t now = mdate (), advance = block->i_pts - now;
373     if (advance < -AOUT_MAX_PTS_DELAY)
374     {   /* Late buffer can be caused by bugs in the decoder, by scheduling
375          * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
376          * insufficient. We assume the PTS is wrong and play the buffer anyway:
377          * Hopefully video has encountered a similar PTS problem as audio. */
378         msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
379         goto drop;
380     }
381     if (advance > AOUT_MAX_ADVANCE_TIME)
382     {   /* Early buffers can only be caused by bugs in the decoder. */
383         msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
384         goto drop;
385     }
386     if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
387         owner->sync.discontinuity = true;
388
389     block = aout_FiltersPlay (aout, block, input_rate);
390     if (block == NULL)
391         goto lost;
392
393     /* Software volume */
394     aout_volume_Amplify (owner->volume, block);
395
396     /* Drift correction */
397     aout_DecSynchronize (aout, block->i_pts, input_rate);
398
399     /* Output */
400     owner->sync.end = block->i_pts + block->i_length + 1;
401     owner->sync.discontinuity = false;
402     aout_OutputPlay (aout, block);
403 out:
404     aout_unlock (aout);
405     return 0;
406 drop:
407     owner->sync.discontinuity = true;
408     block_Release (block);
409 lost:
410     atomic_fetch_add(&owner->buffers_lost, 1);
411     goto out;
412 }
413
414 int aout_DecGetResetLost (audio_output_t *aout)
415 {
416     aout_owner_t *owner = aout_owner (aout);
417     return atomic_exchange(&owner->buffers_lost, 0);
418 }
419
420 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
421 {
422     aout_owner_t *owner = aout_owner (aout);
423
424     aout_lock (aout);
425     if (owner->sync.end != VLC_TS_INVALID)
426     {
427         if (paused)
428             owner->sync.end -= date;
429         else
430             owner->sync.end += date;
431     }
432     if (owner->mixer_format.i_format)
433         aout_OutputPause (aout, paused, date);
434     aout_unlock (aout);
435 }
436
437 void aout_DecFlush (audio_output_t *aout)
438 {
439     aout_owner_t *owner = aout_owner (aout);
440
441     aout_lock (aout);
442     owner->sync.end = VLC_TS_INVALID;
443     if (owner->mixer_format.i_format)
444         aout_OutputFlush (aout, false);
445     aout_unlock (aout);
446 }
447
448 bool aout_DecIsEmpty (audio_output_t *aout)
449 {
450     aout_owner_t *owner = aout_owner (aout);
451     mtime_t now = mdate ();
452     bool empty = true;
453
454     aout_lock (aout);
455     if (owner->sync.end != VLC_TS_INVALID)
456         empty = owner->sync.end <= now;
457     if (empty && owner->mixer_format.i_format)
458         /* The last PTS has elapsed already. So the underlying audio output
459          * buffer should be empty or almost. Thus draining should be fast
460          * and will not block the caller too long. */
461         aout_OutputFlush (aout, true);
462     aout_unlock (aout);
463     return empty;
464 }