aout: move code
[vlc.git] / src / audio_output / dec.c
blob58ede03c51e16cf60765fddd53818137d8cd4a08
1 /*****************************************************************************
2 * dec.c : audio output API towards decoders
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
5 * $Id$
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <assert.h>
33 #include <vlc_common.h>
34 #include <vlc_aout.h>
35 #include <vlc_input.h>
37 #include "aout_internal.h"
38 #include "libvlc.h"
40 /**
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 )
49 /* Sanitize audio format, input need to have a valid physical channels
50 * layout or a valid number of channels. */
51 int i_map_channels = aout_FormatNbChannels( p_format );
52 if( ( i_map_channels == 0 && p_format->i_channels == 0 )
53 || i_map_channels > AOUT_CHAN_MAX || p_format->i_channels > INPUT_CHAN_MAX )
55 msg_Err( p_aout, "invalid audio channels count" );
56 return -1;
59 if( p_format->i_rate > 352800 )
61 msg_Err( p_aout, "excessive audio sample frequency (%u)",
62 p_format->i_rate );
63 return -1;
65 if( p_format->i_rate < 4000 )
67 msg_Err( p_aout, "too low audio sample frequency (%u)",
68 p_format->i_rate );
69 return -1;
72 aout_owner_t *owner = aout_owner(p_aout);
74 /* TODO: reduce lock scope depending on decoder's real need */
75 aout_OutputLock (p_aout);
77 /* Create the audio output stream */
78 owner->volume = aout_volume_New (p_aout, p_replay_gain);
80 atomic_store (&owner->restart, 0);
81 owner->input_format = *p_format;
82 owner->mixer_format = owner->input_format;
83 owner->request_vout = *p_request_vout;
85 var_Change (p_aout, "stereo-mode", VLC_VAR_SETVALUE,
86 &(vlc_value_t) { .i_int = AOUT_VAR_CHAN_UNSET }, NULL);
88 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
89 if (aout_OutputNew (p_aout, &owner->mixer_format, &owner->filters_cfg))
90 goto error;
91 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
93 /* Create the audio filtering "input" pipeline */
94 owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
95 &owner->request_vout,
96 &owner->filters_cfg);
97 if (owner->filters == NULL)
99 aout_OutputDelete (p_aout);
100 error:
101 aout_volume_Delete (owner->volume);
102 owner->volume = NULL;
103 aout_OutputUnlock (p_aout);
104 return -1;
108 owner->sync.end = VLC_TS_INVALID;
109 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
110 owner->sync.discontinuity = true;
111 aout_OutputUnlock (p_aout);
113 atomic_init (&owner->buffers_lost, 0);
114 atomic_init (&owner->buffers_played, 0);
115 return 0;
119 * Stops all plugins involved in the audio output.
121 void aout_DecDelete (audio_output_t *aout)
123 aout_owner_t *owner = aout_owner (aout);
125 aout_OutputLock (aout);
126 if (owner->mixer_format.i_format)
128 aout_FiltersDelete (aout, owner->filters);
129 aout_OutputDelete (aout);
131 aout_volume_Delete (owner->volume);
132 owner->volume = NULL;
133 aout_OutputUnlock (aout);
136 static int aout_CheckReady (audio_output_t *aout)
138 aout_owner_t *owner = aout_owner (aout);
140 int status = AOUT_DEC_SUCCESS;
141 int restart = atomic_exchange (&owner->restart, 0);
142 if (unlikely(restart))
144 if (owner->mixer_format.i_format)
145 aout_FiltersDelete (aout, owner->filters);
147 if (restart & AOUT_RESTART_OUTPUT)
148 { /* Reinitializes the output */
149 msg_Dbg (aout, "restarting output...");
150 if (owner->mixer_format.i_format)
151 aout_OutputDelete (aout);
152 owner->mixer_format = owner->input_format;
153 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
154 if (aout_OutputNew (aout, &owner->mixer_format, &owner->filters_cfg))
155 owner->mixer_format.i_format = 0;
156 aout_volume_SetFormat (owner->volume,
157 owner->mixer_format.i_format);
159 /* Notify the decoder that the aout changed in order to try a new
160 * suitable codec (like an HDMI audio format). However, keep the
161 * same codec if the aout was restarted because of a stereo-mode
162 * change from the user. */
163 if (!(restart & AOUT_RESTART_STEREOMODE))
164 status = AOUT_DEC_CHANGED;
167 msg_Dbg (aout, "restarting filters...");
168 owner->sync.end = VLC_TS_INVALID;
169 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
171 if (owner->mixer_format.i_format)
173 owner->filters = aout_FiltersNew (aout, &owner->input_format,
174 &owner->mixer_format,
175 &owner->request_vout,
176 &owner->filters_cfg);
177 if (owner->filters == NULL)
179 aout_OutputDelete (aout);
180 owner->mixer_format.i_format = 0;
183 /* TODO: This would be a good time to call clean up any video output
184 * left over by an audio visualization:
185 input_resource_TerminatVout(MAGIC HERE); */
187 return (owner->mixer_format.i_format) ? status : AOUT_DEC_FAILED;
191 * Marks the audio output for restart, to update any parameter of the output
192 * plug-in (e.g. output device or channel mapping).
194 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
196 aout_owner_t *owner = aout_owner (aout);
197 atomic_fetch_or (&owner->restart, mode);
198 msg_Dbg (aout, "restart requested (%u)", mode);
202 * Buffer management
205 static void aout_StopResampling (audio_output_t *aout)
207 aout_owner_t *owner = aout_owner (aout);
209 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
210 aout_FiltersAdjustResampling (owner->filters, 0);
213 static void aout_DecSilence (audio_output_t *aout, mtime_t length, mtime_t pts)
215 aout_owner_t *owner = aout_owner (aout);
216 const audio_sample_format_t *fmt = &owner->mixer_format;
217 size_t frames = (fmt->i_rate * length) / CLOCK_FREQ;
219 block_t *block = block_Alloc (frames * fmt->i_bytes_per_frame
220 / fmt->i_frame_length);
221 if (unlikely(block == NULL))
222 return; /* uho! */
224 msg_Dbg (aout, "inserting %zu zeroes", frames);
225 memset (block->p_buffer, 0, block->i_buffer);
226 block->i_nb_samples = frames;
227 block->i_pts = pts;
228 block->i_dts = pts;
229 block->i_length = length;
230 aout_OutputPlay (aout, block);
233 static void aout_DecSynchronize (audio_output_t *aout, mtime_t dec_pts,
234 int input_rate)
236 aout_owner_t *owner = aout_owner (aout);
237 mtime_t drift;
240 * Depending on the drift between the actual and intended playback times,
241 * the audio core may ignore the drift, trigger upsampling or downsampling,
242 * insert silence or even discard samples.
243 * Future VLC versions may instead adjust the input rate.
245 * The audio output plugin is responsible for estimating its actual
246 * playback time, or rather the estimated time when the next sample will
247 * be played. (The actual playback time is always the current time, that is
248 * to say mdate(). It is not an useful statistic.)
250 * Most audio output plugins can estimate the delay until playback of
251 * the next sample to be written to the buffer, or equally the time until
252 * all samples in the buffer will have been played. Then:
253 * pts = mdate() + delay
255 if (aout_OutputTimeGet (aout, &drift) != 0)
256 return; /* nothing can be done if timing is unknown */
257 drift += mdate () - dec_pts;
259 /* Late audio output.
260 * This can happen due to insufficient caching, scheduling jitter
261 * or bug in the decoder. Ideally, the output would seek backward. But that
262 * is not portable, not supported by some hardware and often unsafe/buggy
263 * where supported. The other alternative is to flush the buffers
264 * completely. */
265 if (drift > (owner->sync.discontinuity ? 0
266 : +3 * input_rate * AOUT_MAX_PTS_DELAY / INPUT_RATE_DEFAULT))
268 if (!owner->sync.discontinuity)
269 msg_Warn (aout, "playback way too late (%"PRId64"): "
270 "flushing buffers", drift);
271 else
272 msg_Dbg (aout, "playback too late (%"PRId64"): "
273 "flushing buffers", drift);
274 aout_OutputFlush (aout, false);
276 aout_StopResampling (aout);
277 owner->sync.end = VLC_TS_INVALID;
278 owner->sync.discontinuity = true;
280 /* Now the output might be too early... Recheck. */
281 if (aout_OutputTimeGet (aout, &drift) != 0)
282 return; /* nothing can be done if timing is unknown */
283 drift += mdate () - dec_pts;
286 /* Early audio output.
287 * This is rare except at startup when the buffers are still empty. */
288 if (drift < (owner->sync.discontinuity ? 0
289 : -3 * input_rate * AOUT_MAX_PTS_ADVANCE / INPUT_RATE_DEFAULT))
291 if (!owner->sync.discontinuity)
292 msg_Warn (aout, "playback way too early (%"PRId64"): "
293 "playing silence", drift);
294 aout_DecSilence (aout, -drift, dec_pts);
296 aout_StopResampling (aout);
297 owner->sync.discontinuity = true;
298 drift = 0;
301 if (!aout_FiltersCanResample(owner->filters))
302 return;
304 /* Resampling */
305 if (drift > +AOUT_MAX_PTS_DELAY
306 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
308 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
309 drift);
310 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
311 owner->sync.resamp_start_drift = +drift;
313 if (drift < -AOUT_MAX_PTS_ADVANCE
314 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
316 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
317 drift);
318 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
319 owner->sync.resamp_start_drift = -drift;
322 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
323 return; /* Everything is fine. Nothing to do. */
325 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
326 { /* If the drift is ever increasing, then something is seriously wrong.
327 * Cease resampling and hope for the best. */
328 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
329 "stopping resampling", drift);
330 aout_StopResampling (aout);
331 return;
334 /* Resampling has been triggered earlier. This checks if it needs to be
335 * increased or decreased. Resampling rate changes must be kept slow for
336 * the comfort of listeners. */
337 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
339 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
340 /* If the drift has been reduced from more than half its initial
341 * value, then it is time to switch back the resampling direction. */
342 adj *= -1;
344 if (!aout_FiltersAdjustResampling (owner->filters, adj))
345 { /* Everything is back to normal: stop resampling. */
346 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
347 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
351 /*****************************************************************************
352 * aout_DecPlay : filter & mix the decoded buffer
353 *****************************************************************************/
354 int aout_DecPlay (audio_output_t *aout, block_t *block, int input_rate)
356 aout_owner_t *owner = aout_owner (aout);
358 assert (input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE);
359 assert (input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE);
360 assert (block->i_pts >= VLC_TS_0);
362 block->i_length = CLOCK_FREQ * block->i_nb_samples
363 / owner->input_format.i_rate;
365 aout_OutputLock (aout);
366 int ret = aout_CheckReady (aout);
367 if (unlikely(ret == AOUT_DEC_FAILED))
368 goto drop; /* Pipeline is unrecoverably broken :-( */
370 const mtime_t now = mdate (), advance = block->i_pts - now;
371 if (advance < -AOUT_MAX_PTS_DELAY)
372 { /* Late buffer can be caused by bugs in the decoder, by scheduling
373 * latency spikes (excessive load, SIGSTOP, etc.) or if buffering is
374 * insufficient. We assume the PTS is wrong and play the buffer anyway:
375 * Hopefully video has encountered a similar PTS problem as audio. */
376 msg_Warn (aout, "buffer too late (%"PRId64" us): dropped", advance);
377 goto drop;
379 if (advance > AOUT_MAX_ADVANCE_TIME)
380 { /* Early buffers can only be caused by bugs in the decoder. */
381 msg_Err (aout, "buffer too early (%"PRId64" us): dropped", advance);
382 goto drop;
384 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
385 owner->sync.discontinuity = true;
387 block = aout_FiltersPlay (owner->filters, block, input_rate);
388 if (block == NULL)
389 goto lost;
391 /* Software volume */
392 aout_volume_Amplify (owner->volume, block);
394 /* Drift correction */
395 aout_DecSynchronize (aout, block->i_pts, input_rate);
397 /* Output */
398 owner->sync.end = block->i_pts + block->i_length + 1;
399 owner->sync.discontinuity = false;
400 aout_OutputPlay (aout, block);
401 atomic_fetch_add(&owner->buffers_played, 1);
402 out:
403 aout_OutputUnlock (aout);
404 return ret;
405 drop:
406 owner->sync.discontinuity = true;
407 block_Release (block);
408 lost:
409 atomic_fetch_add(&owner->buffers_lost, 1);
410 goto out;
413 void aout_DecGetResetStats(audio_output_t *aout, unsigned *restrict lost,
414 unsigned *restrict played)
416 aout_owner_t *owner = aout_owner (aout);
418 *lost = atomic_exchange(&owner->buffers_lost, 0);
419 *played = atomic_exchange(&owner->buffers_played, 0);
422 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
424 aout_owner_t *owner = aout_owner (aout);
426 aout_OutputLock (aout);
427 if (owner->sync.end != VLC_TS_INVALID)
429 if (paused)
430 owner->sync.end -= date;
431 else
432 owner->sync.end += date;
434 if (owner->mixer_format.i_format)
435 aout_OutputPause (aout, paused, date);
436 aout_OutputUnlock (aout);
439 void aout_DecFlush (audio_output_t *aout, bool wait)
441 aout_owner_t *owner = aout_owner (aout);
443 aout_OutputLock (aout);
444 owner->sync.end = VLC_TS_INVALID;
445 if (owner->mixer_format.i_format)
447 if (wait)
449 block_t *block = aout_FiltersDrain (owner->filters);
450 if (block)
451 aout_OutputPlay (aout, block);
453 else
454 aout_FiltersFlush (owner->filters);
455 aout_OutputFlush (aout, wait);
457 aout_OutputUnlock (aout);