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