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