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>
37 #include "aout_internal.h"
41 * Creates an audio output
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 )
48 /* Sanitize audio format */
49 if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
51 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
55 if( p_format->i_rate > 192000 )
57 msg_Err( p_aout, "excessive audio sample frequency (%u)",
61 if( p_format->i_rate < 4000 )
63 msg_Err( p_aout, "too low audio sample frequency (%u)",
68 aout_owner_t *owner = aout_owner(p_aout);
70 /* TODO: reduce lock scope depending on decoder's real need */
71 aout_OutputLock (p_aout);
73 var_Destroy( p_aout, "stereo-mode" );
75 /* Create the audio output stream */
76 owner->volume = aout_volume_New (p_aout, p_replay_gain);
78 atomic_store (&owner->restart, 0);
79 owner->input_format = *p_format;
80 owner->mixer_format = owner->input_format;
82 if (aout_OutputNew (p_aout, &owner->mixer_format))
84 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
86 /* Create the audio filtering "input" pipeline */
87 owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
89 if (owner->filters == NULL)
91 aout_OutputDelete (p_aout);
93 aout_volume_Delete (owner->volume);
94 aout_OutputUnlock (p_aout);
98 owner->sync.end = VLC_TS_INVALID;
99 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
100 owner->sync.discontinuity = true;
101 aout_OutputUnlock (p_aout);
103 atomic_init (&owner->buffers_lost, 0);
108 * Stops all plugins involved in the audio output.
110 void aout_DecDelete (audio_output_t *aout)
112 aout_owner_t *owner = aout_owner (aout);
114 aout_OutputLock (aout);
115 if (owner->mixer_format.i_format)
117 aout_FiltersDelete (aout, owner->filters);
118 aout_OutputDelete (aout);
120 aout_volume_Delete (owner->volume);
121 aout_OutputUnlock (aout);
122 var_Destroy (aout, "stereo-mode");
125 static int aout_CheckReady (audio_output_t *aout)
127 aout_owner_t *owner = aout_owner (aout);
129 int restart = atomic_exchange (&owner->restart, 0);
130 if (unlikely(restart))
132 const aout_request_vout_t request_vout = owner->request_vout;
134 if (owner->mixer_format.i_format)
135 aout_FiltersDelete (aout, owner->filters);
137 if (restart & AOUT_RESTART_OUTPUT)
138 { /* Reinitializes the output */
139 msg_Dbg (aout, "restarting output...");
140 if (owner->mixer_format.i_format)
141 aout_OutputDelete (aout);
142 owner->mixer_format = owner->input_format;
143 if (aout_OutputNew (aout, &owner->mixer_format))
144 owner->mixer_format.i_format = 0;
145 aout_volume_SetFormat (owner->volume,
146 owner->mixer_format.i_format);
149 msg_Dbg (aout, "restarting filters...");
150 owner->sync.end = VLC_TS_INVALID;
151 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
153 if (owner->mixer_format.i_format)
155 owner->filters = aout_FiltersNew (aout, &owner->input_format,
156 &owner->mixer_format,
158 if (owner->filters == NULL)
160 aout_OutputDelete (aout);
161 owner->mixer_format.i_format = 0;
165 return (owner->mixer_format.i_format) ? 0 : -1;
169 * Marks the audio output for restart, to update any parameter of the output
170 * plug-in (e.g. output device or channel mapping).
172 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
174 aout_owner_t *owner = aout_owner (aout);
175 atomic_fetch_or (&owner->restart, mode);
176 msg_Dbg (aout, "restart requested (%u)", mode);
183 /*****************************************************************************
184 * aout_DecNewBuffer : ask for a new empty buffer
185 *****************************************************************************/
186 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
188 /* NOTE: the caller is responsible for serializing input change */
189 aout_owner_t *owner = aout_owner (aout);
191 size_t length = samples * owner->input_format.i_bytes_per_frame
192 / owner->input_format.i_frame_length;
193 block_t *block = block_Alloc( length );
194 if( likely(block != NULL) )
196 block->i_nb_samples = samples;
197 block->i_pts = block->i_length = 0;
202 /*****************************************************************************
203 * aout_DecDeleteBuffer : destroy an undecoded buffer
204 *****************************************************************************/
205 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
208 block_Release (block);
211 static void aout_StopResampling (audio_output_t *aout)
213 aout_owner_t *owner = aout_owner (aout);
215 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
216 aout_FiltersAdjustResampling (owner->filters, 0);
219 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
221 aout_owner_t *owner = aout_owner (aout);
222 const audio_sample_format_t *fmt = &owner->mixer_format;
223 size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
226 if (AOUT_FMT_SPDIF(fmt))
227 block = block_Alloc (4 * frames);
229 block = block_Alloc (frames * fmt->i_bytes_per_frame);
230 if (unlikely(block == NULL))
233 msg_Dbg (aout, "inserting %zu zeroes", frames);
234 memset (block->p_buffer, 0, block->i_buffer);
235 block->i_nb_samples = frames;
238 block->i_length = length;
239 aout_OutputPlay (aout, block);
242 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
245 aout_owner_t *owner = aout_owner (aout);
249 * Depending on the drift between the actual and intended playback times,
250 * the audio core may ignore the drift, trigger upsampling or downsampling,
251 * insert silence or even discard samples.
252 * Future VLC versions may instead adjust the input rate.
254 * The audio output plugin is responsible for estimating its actual
255 * playback time, or rather the estimated time when the next sample will
256 * be played. (The actual playback time is always the current time, that is
257 * to say mdate(). It is not an useful statistic.)
259 * Most audio output plugins can estimate the delay until playback of
260 * the next sample to be written to the buffer, or equally the time until
261 * all samples in the buffer will have been played. Then:
262 * pts = mdate() + delay
264 if (aout_OutputTimeGet (aout, &drift) != 0)
265 return; /* nothing can be done if timing is unknown */
266 drift += mdate () - dec_pts;
268 /* Late audio output.
269 * This can happen due to insufficient caching, scheduling jitter
270 * or bug in the decoder. Ideally, the output would seek backward. But that
271 * is not portable, not supported by some hardware and often unsafe/buggy
272 * where supported. The other alternative is to flush the buffers
274 if (drift > (owner->sync.discontinuity ? 0
275 : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
277 if (!owner->sync.discontinuity)
278 msg_Warn (aout, "playback way too late (%"PRId64"): "
279 "flushing buffers", drift);
281 msg_Dbg (aout, "playback too late (%"PRId64"): "
282 "flushing buffers", drift);
283 aout_OutputFlush (aout, false);
285 aout_StopResampling (aout);
286 owner->sync.end = VLC_TS_INVALID;
287 owner->sync.discontinuity = true;
289 /* Now the output might be too early... Recheck. */
290 if (aout_OutputTimeGet (aout, &drift) != 0)
291 return; /* nothing can be done if timing is unknown */
292 drift += mdate () - dec_pts;
295 /* Early audio output.
296 * This is rare except at startup when the buffers are still empty. */
297 if (drift < (owner->sync.discontinuity ? 0
298 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
300 if (!owner->sync.discontinuity)
301 msg_Warn (aout, "playback way too early (%"PRId64"): "
302 "playing silence", drift);
303 aout_DecSilence (aout, -drift, dec_pts);
305 aout_StopResampling (aout);
306 owner->sync.discontinuity = true;
311 if (drift > +AOUT_MAX_PTS_DELAY
312 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
314 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
316 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
317 owner->sync.resamp_start_drift = +drift;
319 if (drift < -AOUT_MAX_PTS_ADVANCE
320 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
322 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
324 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
325 owner->sync.resamp_start_drift = -drift;
328 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
329 return; /* Everything is fine. Nothing to do. */
331 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
332 { /* If the drift is ever increasing, then something is seriously wrong.
333 * Cease resampling and hope for the best. */
334 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
335 "stopping resampling", drift);
336 aout_StopResampling (aout);
340 /* Resampling has been triggered earlier. This checks if it needs to be
341 * increased or decreased. Resampling rate changes must be kept slow for
342 * the comfort of listeners. */
343 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
345 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
346 /* If the drift has been reduced from more than half its initial
347 * value, then it is time to switch back the resampling direction. */
350 if (!aout_FiltersAdjustResampling (owner->filters, adj))
351 { /* Everything is back to normal: stop resampling. */
352 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
353 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
357 /*****************************************************************************
358 * aout_DecPlay : filter & mix the decoded buffer
359 *****************************************************************************/
360 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
362 aout_owner_t *owner = aout_owner (aout);
364 assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
365 assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
366 assert (block->i_pts >= VLC_TS_0);
368 block->i_length = CLOCK_FREQ * block->i_nb_samples
369 / owner->input_format.i_rate;
371 aout_OutputLock (aout);
372 if (unlikely(aout_CheckReady (aout)))
373 goto drop; /* Pipeline is unrecoverably broken :-( */
375 const mtime_t now = mdate (), advance = block->i_pts - now;
376 if (advance < -AOUT_MAX_PTS_DELAY)
377 { /* Late buffer can be caused by bugs in the decoder, by scheduling
378 * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
379 * insufficient. We assume the PTS is wrong and play the buffer anyway:
380 * Hopefully video has encountered a similar PTS problem as audio. */
381 msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
384 if (advance > AOUT_MAX_ADVANCE_TIME)
385 { /* Early buffers can only be caused by bugs in the decoder. */
386 msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
389 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
390 owner->sync.discontinuity = true;
392 block = aout_FiltersPlay (owner->filters, block, input_rate);
396 /* Software volume */
397 aout_volume_Amplify (owner->volume, block);
399 /* Drift correction */
400 aout_DecSynchronize (aout, block->i_pts, input_rate);
403 owner->sync.end = block->i_pts + block->i_length + 1;
404 owner->sync.discontinuity = false;
405 aout_OutputPlay (aout, block);
407 aout_OutputUnlock (aout);
410 owner->sync.discontinuity = true;
411 block_Release (block);
413 atomic_fetch_add(&owner->buffers_lost, 1);
417 int aout_DecGetResetLost (audio_output_t *aout)
419 aout_owner_t *owner = aout_owner (aout);
420 return atomic_exchange(&owner->buffers_lost, 0);
423 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
425 aout_owner_t *owner = aout_owner (aout);
427 aout_OutputLock (aout);
428 if (owner->sync.end != VLC_TS_INVALID)
431 owner->sync.end -= date;
433 owner->sync.end += date;
435 if (owner->mixer_format.i_format)
436 aout_OutputPause (aout, paused, date);
437 aout_OutputUnlock (aout);
440 void aout_DecFlush (audio_output_t *aout)
442 aout_owner_t *owner = aout_owner (aout);
444 aout_OutputLock (aout);
445 owner->sync.end = VLC_TS_INVALID;
446 if (owner->mixer_format.i_format)
447 aout_OutputFlush (aout, false);
448 aout_OutputUnlock (aout);
451 bool aout_DecIsEmpty (audio_output_t *aout)
453 aout_owner_t *owner = aout_owner (aout);
454 mtime_t now = mdate ();
457 aout_OutputLock (aout);
458 if (owner->sync.end != VLC_TS_INVALID)
459 empty = owner->sync.end <= now;
460 if (empty && owner->mixer_format.i_format)
461 /* The last PTS has elapsed already. So the underlying audio output
462 * buffer should be empty or almost. Thus draining should be fast
463 * and will not block the caller too long. */
464 aout_OutputFlush (aout, true);
465 aout_OutputUnlock (aout);