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