1 /*****************************************************************************
2 * dec.c : audio output API towards decoders
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
33 #include <vlc_common.h>
35 #include <vlc_input.h>
36 #include <vlc_atomic.h>
38 #include "aout_internal.h"
42 * Creates an audio output
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 )
49 /* Sanitize audio format */
50 if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
52 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
56 if( p_format->i_rate > 192000 )
58 msg_Err( p_aout, "excessive audio sample frequency (%u)",
62 if( p_format->i_rate < 4000 )
64 msg_Err( p_aout, "too low audio sample frequency (%u)",
69 aout_owner_t *owner = aout_owner(p_aout);
72 /* TODO: reduce lock scope depending on decoder's real need */
75 var_Destroy( p_aout, "stereo-mode" );
77 /* Create the audio output stream */
78 owner->volume = aout_volume_New (p_aout, p_replay_gain);
80 vlc_atomic_set (&owner->restart, 0);
81 owner->input_format = *p_format;
82 owner->mixer_format = owner->input_format;
84 if (aout_OutputNew (p_aout, &owner->mixer_format))
86 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
88 /* Create the audio filtering "input" pipeline */
89 if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
92 aout_OutputDelete (p_aout);
94 aout_volume_Delete (owner->volume);
99 owner->sync.end = VLC_TS_INVALID;
100 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
101 owner->sync.discontinuity = true;
102 aout_unlock( p_aout );
104 atomic_init (&owner->buffers_lost, 0);
110 * Stops all plugins involved in the audio output.
112 void aout_DecDelete (audio_output_t *p_aout)
114 aout_owner_t *owner = aout_owner (p_aout);
117 aout_FiltersDelete (p_aout);
118 aout_OutputDelete( p_aout );
119 aout_volume_Delete (owner->volume);
121 var_Destroy( p_aout, "stereo-mode" );
123 aout_unlock( p_aout );
126 #define AOUT_RESTART_OUTPUT 1
127 #define AOUT_RESTART_INPUT 2
128 static int aout_CheckRestart (audio_output_t *aout)
130 aout_owner_t *owner = aout_owner (aout);
132 aout_assert_locked (aout);
134 int restart = vlc_atomic_swap (&owner->restart, 0);
135 if (likely(restart == 0))
138 assert (restart & AOUT_RESTART_INPUT);
140 const aout_request_vout_t request_vout = owner->request_vout;
142 aout_FiltersDelete (aout);
144 /* Reinitializes the output */
145 if (restart & AOUT_RESTART_OUTPUT)
147 aout_OutputDelete (aout);
148 owner->mixer_format = owner->input_format;
149 if (aout_OutputNew (aout, &owner->mixer_format))
150 abort (); /* FIXME we are officially screwed */
151 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
154 owner->sync.end = VLC_TS_INVALID;
155 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
157 if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
160 abort (); /* FIXME */
166 * Marks the audio output for restart, to update any parameter of the output
167 * plug-in (e.g. output device or channel mapping).
169 static void aout_RequestRestart (audio_output_t *aout)
171 aout_owner_t *owner = aout_owner (aout);
173 /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
174 vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
177 int aout_ChannelsRestart (vlc_object_t *obj, const char *varname,
178 vlc_value_t oldval, vlc_value_t newval, void *data)
180 audio_output_t *aout = (audio_output_t *)obj;
181 (void)oldval; (void)newval; (void)data;
183 if (!strcmp (varname, "audio-device"))
185 /* This is supposed to be a significant change and supposes
186 * rebuilding the channel choices. */
187 var_Destroy (aout, "stereo-mode");
189 aout_RequestRestart (aout);
194 * This function will safely mark aout input to be restarted as soon as
195 * possible to take configuration changes into account
197 void aout_InputRequestRestart (audio_output_t *aout)
199 aout_owner_t *owner = aout_owner (aout);
201 vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
209 /*****************************************************************************
210 * aout_DecNewBuffer : ask for a new empty buffer
211 *****************************************************************************/
212 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
214 /* NOTE: the caller is responsible for serializing input change */
215 aout_owner_t *owner = aout_owner (aout);
217 size_t length = samples * owner->input_format.i_bytes_per_frame
218 / owner->input_format.i_frame_length;
219 block_t *block = block_Alloc( length );
220 if( likely(block != NULL) )
222 block->i_nb_samples = samples;
223 block->i_pts = block->i_length = 0;
228 /*****************************************************************************
229 * aout_DecDeleteBuffer : destroy an undecoded buffer
230 *****************************************************************************/
231 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
234 block_Release (block);
237 static void aout_StopResampling (audio_output_t *aout)
239 aout_owner_t *owner = aout_owner (aout);
241 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
242 aout_FiltersAdjustResampling (aout, 0);
245 static void aout_DecSilence (audio_output_t *aout, mtime_t length)
247 aout_owner_t *owner = aout_owner (aout);
248 const audio_sample_format_t *fmt = &owner->mixer_format;
249 size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
252 if (AOUT_FMT_SPDIF(fmt))
253 block = block_Alloc (4 * frames);
255 block = block_Alloc (frames * fmt->i_bytes_per_frame);
256 if (unlikely(block == NULL))
259 msg_Dbg (aout, "inserting %zu zeroes", frames);
260 memset (block->p_buffer, 0, block->i_buffer);
261 block->i_nb_samples = frames;
262 block->i_length = length;
264 aout_OutputPlay (aout, block);
267 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
270 aout_owner_t *owner = aout_owner (aout);
271 mtime_t aout_pts, drift;
274 * Depending on the drift between the actual and intended playback times,
275 * the audio core may ignore the drift, trigger upsampling or downsampling,
276 * insert silence or even discard samples.
277 * Future VLC versions may instead adjust the input rate.
279 * The audio output plugin is responsible for estimating its actual
280 * playback time, or rather the estimated time when the next sample will
281 * be played. (The actual playback time is always the current time, that is
282 * to say mdate(). It is not an useful statistic.)
284 * Most audio output plugins can estimate the delay until playback of
285 * the next sample to be written to the buffer, or equally the time until
286 * all samples in the buffer will have been played. Then:
287 * pts = mdate() + delay
289 if (aout_OutputTimeGet (aout, &aout_pts) != 0)
290 return; /* nothing can be done if timing is unknown */
291 drift = aout_pts - dec_pts;
293 /* Late audio output.
294 * This can happen due to insufficient caching, scheduling jitter
295 * or bug in the decoder. Ideally, the output would seek backward. But that
296 * is not portable, not supported by some hardware and often unsafe/buggy
297 * where supported. The other alternative is to flush the buffers
299 if (drift > (owner->sync.discontinuity ? 0
300 : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
302 if (!owner->sync.discontinuity)
303 msg_Warn (aout, "playback way too late (%"PRId64"): "
304 "flushing buffers", drift);
306 msg_Dbg (aout, "playback too late (%"PRId64"): "
307 "flushing buffers", drift);
308 aout_OutputFlush (aout, false);
310 aout_StopResampling (aout);
311 owner->sync.end = VLC_TS_INVALID;
312 owner->sync.discontinuity = true;
314 /* Now the output might be too early... Recheck. */
315 if (aout_OutputTimeGet (aout, &aout_pts) != 0)
316 return; /* nothing can be done if timing is unknown */
317 drift = aout_pts - dec_pts;
320 /* Early audio output.
321 * This is rare except at startup when the buffers are still empty. */
322 if (drift < (owner->sync.discontinuity ? 0
323 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
325 if (!owner->sync.discontinuity)
326 msg_Warn (aout, "playback way too early (%"PRId64"): "
327 "playing silence", drift);
328 aout_DecSilence (aout, -drift);
330 aout_StopResampling (aout);
331 owner->sync.discontinuity = true;
336 if (drift > +AOUT_MAX_PTS_DELAY
337 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
339 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
341 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
342 owner->sync.resamp_start_drift = +drift;
344 if (drift < -AOUT_MAX_PTS_ADVANCE
345 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
347 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
349 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
350 owner->sync.resamp_start_drift = -drift;
353 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
354 return; /* Everything is fine. Nothing to do. */
356 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
357 { /* If the drift is ever increasing, then something is seriously wrong.
358 * Cease resampling and hope for the best. */
359 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
360 "stopping resampling", drift);
361 aout_StopResampling (aout);
365 /* Resampling has been triggered earlier. This checks if it needs to be
366 * increased or decreased. Resampling rate changes must be kept slow for
367 * the comfort of listeners. */
368 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
370 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
371 /* If the drift has been reduced from more than half its initial
372 * value, then it is time to switch back the resampling direction. */
375 if (!aout_FiltersAdjustResampling (aout, adj))
376 { /* Everything is back to normal: stop resampling. */
377 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
378 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
382 /*****************************************************************************
383 * aout_DecPlay : filter & mix the decoded buffer
384 *****************************************************************************/
385 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
387 aout_owner_t *owner = aout_owner (aout);
389 assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
390 assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
391 assert (block->i_pts >= VLC_TS_0);
393 block->i_length = CLOCK_FREQ * block->i_nb_samples
394 / owner->input_format.i_rate;
397 if (unlikely(aout_CheckRestart (aout)))
398 goto drop; /* Pipeline is unrecoverably broken :-( */
400 const mtime_t now = mdate (), advance = block->i_pts - now;
401 if (advance < AOUT_MIN_PREPARE_TIME)
402 { /* Late buffer can be caused by bugs in the decoder, by scheduling
403 * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
404 * insufficient. We assume the PTS is wrong and play the buffer anyway:
405 * Hopefully video has encountered a similar PTS problem as audio. */
406 msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
409 if (advance > AOUT_MAX_ADVANCE_TIME)
410 { /* Early buffers can only be caused by bugs in the decoder. */
411 msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
414 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
415 owner->sync.discontinuity = true;
417 block = aout_FiltersPlay (aout, block, input_rate);
421 /* Software volume */
422 aout_volume_Amplify (owner->volume, block);
424 /* Drift correction */
425 aout_DecSynchronize (aout, block->i_pts, input_rate);
428 owner->sync.end = block->i_pts + block->i_length + 1;
429 owner->sync.discontinuity = false;
430 aout_OutputPlay (aout, block);
435 owner->sync.discontinuity = true;
436 block_Release (block);
438 atomic_fetch_add(&owner->buffers_lost, 1);
442 int aout_DecGetResetLost (audio_output_t *aout)
444 aout_owner_t *owner = aout_owner (aout);
445 return atomic_exchange(&owner->buffers_lost, 0);
448 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
450 aout_owner_t *owner = aout_owner (aout);
453 if (owner->sync.end != VLC_TS_INVALID)
456 owner->sync.end -= date;
458 owner->sync.end += date;
460 aout_OutputPause (aout, paused, date);
464 void aout_DecFlush (audio_output_t *aout)
466 aout_owner_t *owner = aout_owner (aout);
469 owner->sync.end = VLC_TS_INVALID;
470 aout_OutputFlush (aout, false);
474 bool aout_DecIsEmpty (audio_output_t *aout)
476 aout_owner_t *owner = aout_owner (aout);
477 mtime_t now = mdate ();
481 if (owner->sync.end != VLC_TS_INVALID)
482 empty = owner->sync.end <= now;
484 /* The last PTS has elapsed already. So the underlying audio output
485 * buffer should be empty or almost. Thus draining should be fast
486 * and will not block the caller too long. */
487 aout_OutputFlush (aout, true);