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