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