aout: change rate argument
[vlc.git] / src / audio_output / dec.c
blob4d87c2a462c9f73f73725bcc405b005262153750
1 /*****************************************************************************
2 * dec.c : audio output API towards decoders
3 *****************************************************************************
4 * Copyright (C) 2002-2007 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <assert.h>
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_aout.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)
47 if( p_format->i_bitspersample > 0 )
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;
60 if( p_format->i_rate > 352800 )
62 msg_Err( p_aout, "excessive audio sample frequency (%u)",
63 p_format->i_rate );
64 return -1;
66 if( p_format->i_rate < 4000 )
68 msg_Err( p_aout, "too low audio sample frequency (%u)",
69 p_format->i_rate );
70 return -1;
73 aout_owner_t *owner = aout_owner(p_aout);
75 /* Create the audio output stream */
76 owner->volume = aout_volume_New (p_aout, p_replay_gain);
78 atomic_store_explicit(&owner->restart, 0, memory_order_relaxed);
79 owner->input_format = *p_format;
80 owner->mixer_format = owner->input_format;
82 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
83 if (aout_OutputNew (p_aout, &owner->mixer_format, &owner->filters_cfg))
84 goto error;
85 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
87 /* Create the audio filtering "input" pipeline */
88 owner->filters = aout_FiltersNew(p_aout, p_format, &owner->mixer_format,
89 &owner->filters_cfg);
90 if (owner->filters == NULL)
92 aout_OutputDelete (p_aout);
93 error:
94 aout_volume_Delete (owner->volume);
95 owner->volume = NULL;
96 return -1;
99 owner->sync.rate = 1.f;
100 owner->sync.end = VLC_TICK_INVALID;
101 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
102 owner->sync.discontinuity = true;
104 atomic_init (&owner->buffers_lost, 0);
105 atomic_init (&owner->buffers_played, 0);
106 atomic_store_explicit(&owner->vp.update, true, memory_order_relaxed);
107 return 0;
111 * Stops all plugins involved in the audio output.
113 void aout_DecDelete (audio_output_t *aout)
115 aout_owner_t *owner = aout_owner (aout);
117 if (owner->mixer_format.i_format)
119 aout_FiltersDelete (aout, owner->filters);
120 aout_OutputDelete (aout);
122 aout_volume_Delete (owner->volume);
123 owner->volume = NULL;
126 static int aout_CheckReady (audio_output_t *aout)
128 aout_owner_t *owner = aout_owner (aout);
129 int status = AOUT_DEC_SUCCESS;
131 int restart = atomic_exchange_explicit(&owner->restart, 0,
132 memory_order_acquire);
133 if (unlikely(restart))
135 if (owner->mixer_format.i_format)
136 aout_FiltersDelete (aout, owner->filters);
138 if (restart & AOUT_RESTART_OUTPUT)
139 { /* Reinitializes the output */
140 msg_Dbg (aout, "restarting output...");
141 if (owner->mixer_format.i_format)
142 aout_OutputDelete (aout);
143 owner->mixer_format = owner->input_format;
144 owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
145 if (aout_OutputNew (aout, &owner->mixer_format, &owner->filters_cfg))
146 owner->mixer_format.i_format = 0;
147 aout_volume_SetFormat (owner->volume,
148 owner->mixer_format.i_format);
150 /* Notify the decoder that the aout changed in order to try a new
151 * suitable codec (like an HDMI audio format). However, keep the
152 * same codec if the aout was restarted because of a stereo-mode
153 * change from the user. */
154 if (restart == AOUT_RESTART_OUTPUT)
155 status = AOUT_DEC_CHANGED;
158 msg_Dbg (aout, "restarting filters...");
159 owner->sync.end = VLC_TICK_INVALID;
160 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
162 if (owner->mixer_format.i_format)
164 owner->filters = aout_FiltersNew(aout, &owner->input_format,
165 &owner->mixer_format,
166 &owner->filters_cfg);
167 if (owner->filters == NULL)
169 aout_OutputDelete (aout);
170 owner->mixer_format.i_format = 0;
173 /* TODO: This would be a good time to call clean up any video output
174 * left over by an audio visualization:
175 input_resource_TerminatVout(MAGIC HERE); */
177 return (owner->mixer_format.i_format) ? status : AOUT_DEC_FAILED;
181 * Marks the audio output for restart, to update any parameter of the output
182 * plug-in (e.g. output device or channel mapping).
184 void aout_RequestRestart (audio_output_t *aout, unsigned mode)
186 aout_owner_t *owner = aout_owner (aout);
187 atomic_fetch_or_explicit(&owner->restart, mode, memory_order_release);
188 msg_Dbg (aout, "restart requested (%u)", mode);
192 * Buffer management
195 static void aout_StopResampling (audio_output_t *aout)
197 aout_owner_t *owner = aout_owner (aout);
199 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
200 aout_FiltersAdjustResampling (owner->filters, 0);
203 static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t pts)
205 aout_owner_t *owner = aout_owner (aout);
206 const audio_sample_format_t *fmt = &owner->mixer_format;
207 size_t frames = samples_from_vlc_tick(length, fmt->i_rate);
209 block_t *block = block_Alloc (frames * fmt->i_bytes_per_frame
210 / fmt->i_frame_length);
211 if (unlikely(block == NULL))
212 return; /* uho! */
214 msg_Dbg (aout, "inserting %zu zeroes", frames);
215 memset (block->p_buffer, 0, block->i_buffer);
216 block->i_nb_samples = frames;
217 block->i_pts = pts;
218 block->i_dts = pts;
219 block->i_length = length;
220 aout->play(aout, block, pts);
223 static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts)
225 aout_owner_t *owner = aout_owner (aout);
226 const float rate = owner->sync.rate;
227 vlc_tick_t drift;
230 * Depending on the drift between the actual and intended playback times,
231 * the audio core may ignore the drift, trigger upsampling or downsampling,
232 * insert silence or even discard samples.
233 * Future VLC versions may instead adjust the input rate.
235 * The audio output plugin is responsible for estimating its actual
236 * playback time, or rather the estimated time when the next sample will
237 * be played. (The actual playback time is always the current time, that is
238 * to say vlc_tick_now(). It is not an useful statistic.)
240 * Most audio output plugins can estimate the delay until playback of
241 * the next sample to be written to the buffer, or equally the time until
242 * all samples in the buffer will have been played. Then:
243 * pts = vlc_tick_now() + delay
245 if (aout->time_get(aout, &drift) != 0)
246 return; /* nothing can be done if timing is unknown */
247 drift += vlc_tick_now () - dec_pts;
249 /* Late audio output.
250 * This can happen due to insufficient caching, scheduling jitter
251 * or bug in the decoder. Ideally, the output would seek backward. But that
252 * is not portable, not supported by some hardware and often unsafe/buggy
253 * where supported. The other alternative is to flush the buffers
254 * completely. */
255 if (drift > (owner->sync.discontinuity ? 0
256 : lroundf(+3 * AOUT_MAX_PTS_DELAY / rate)))
258 if (!owner->sync.discontinuity)
259 msg_Warn (aout, "playback way too late (%"PRId64"): "
260 "flushing buffers", drift);
261 else
262 msg_Dbg (aout, "playback too late (%"PRId64"): "
263 "flushing buffers", drift);
264 aout->flush(aout, false);
266 aout_StopResampling (aout);
267 owner->sync.end = VLC_TICK_INVALID;
268 owner->sync.discontinuity = true;
270 /* Now the output might be too early... Recheck. */
271 if (aout->time_get(aout, &drift) != 0)
272 return; /* nothing can be done if timing is unknown */
273 drift += vlc_tick_now () - dec_pts;
276 /* Early audio output.
277 * This is rare except at startup when the buffers are still empty. */
278 if (drift < (owner->sync.discontinuity ? 0
279 : lroundf(-3 * AOUT_MAX_PTS_ADVANCE * rate)))
281 if (!owner->sync.discontinuity)
282 msg_Warn (aout, "playback way too early (%"PRId64"): "
283 "playing silence", drift);
284 aout_DecSilence (aout, -drift, dec_pts);
286 aout_StopResampling (aout);
287 owner->sync.discontinuity = true;
288 drift = 0;
291 if (!aout_FiltersCanResample(owner->filters))
292 return;
294 /* Resampling */
295 if (drift > +AOUT_MAX_PTS_DELAY
296 && owner->sync.resamp_type != AOUT_RESAMPLING_UP)
298 msg_Warn (aout, "playback too late (%"PRId64"): up-sampling",
299 drift);
300 owner->sync.resamp_type = AOUT_RESAMPLING_UP;
301 owner->sync.resamp_start_drift = +drift;
303 if (drift < -AOUT_MAX_PTS_ADVANCE
304 && owner->sync.resamp_type != AOUT_RESAMPLING_DOWN)
306 msg_Warn (aout, "playback too early (%"PRId64"): down-sampling",
307 drift);
308 owner->sync.resamp_type = AOUT_RESAMPLING_DOWN;
309 owner->sync.resamp_start_drift = -drift;
312 if (owner->sync.resamp_type == AOUT_RESAMPLING_NONE)
313 return; /* Everything is fine. Nothing to do. */
315 if (llabs (drift) > 2 * owner->sync.resamp_start_drift)
316 { /* If the drift is ever increasing, then something is seriously wrong.
317 * Cease resampling and hope for the best. */
318 msg_Warn (aout, "timing screwed (drift: %"PRId64" us): "
319 "stopping resampling", drift);
320 aout_StopResampling (aout);
321 return;
324 /* Resampling has been triggered earlier. This checks if it needs to be
325 * increased or decreased. Resampling rate changes must be kept slow for
326 * the comfort of listeners. */
327 int adj = (owner->sync.resamp_type == AOUT_RESAMPLING_UP) ? +2 : -2;
329 if (2 * llabs (drift) <= owner->sync.resamp_start_drift)
330 /* If the drift has been reduced from more than half its initial
331 * value, then it is time to switch back the resampling direction. */
332 adj *= -1;
334 if (!aout_FiltersAdjustResampling (owner->filters, adj))
335 { /* Everything is back to normal: stop resampling. */
336 owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
337 msg_Dbg (aout, "resampling stopped (drift: %"PRId64" us)", drift);
341 /*****************************************************************************
342 * aout_DecPlay : filter & mix the decoded buffer
343 *****************************************************************************/
344 int aout_DecPlay(audio_output_t *aout, block_t *block)
346 aout_owner_t *owner = aout_owner (aout);
348 assert (block->i_pts != VLC_TICK_INVALID);
350 block->i_length = vlc_tick_from_samples( block->i_nb_samples,
351 owner->input_format.i_rate );
353 int ret = aout_CheckReady (aout);
354 if (unlikely(ret == AOUT_DEC_FAILED))
355 goto drop; /* Pipeline is unrecoverably broken :-( */
357 if (block->i_flags & BLOCK_FLAG_DISCONTINUITY)
358 owner->sync.discontinuity = true;
360 if (atomic_load_explicit(&owner->vp.update, memory_order_relaxed))
362 vlc_mutex_lock (&owner->vp.lock);
363 aout_FiltersChangeViewpoint (owner->filters, &owner->vp.value);
364 atomic_store_explicit(&owner->vp.update, false, memory_order_relaxed);
365 vlc_mutex_unlock (&owner->vp.lock);
368 block = aout_FiltersPlay(owner->filters, block, owner->sync.rate);
369 if (block == NULL)
370 goto lost;
372 /* Software volume */
373 aout_volume_Amplify (owner->volume, block);
375 /* Drift correction */
376 aout_DecSynchronize(aout, block->i_pts);
378 /* Output */
379 owner->sync.end = block->i_pts + block->i_length + 1;
380 owner->sync.discontinuity = false;
381 aout->play(aout, block, block->i_pts);
382 atomic_fetch_add_explicit(&owner->buffers_played, 1, memory_order_relaxed);
383 return ret;
384 drop:
385 owner->sync.discontinuity = true;
386 block_Release (block);
387 lost:
388 atomic_fetch_add_explicit(&owner->buffers_lost, 1, memory_order_relaxed);
389 return ret;
392 void aout_DecGetResetStats(audio_output_t *aout, unsigned *restrict lost,
393 unsigned *restrict played)
395 aout_owner_t *owner = aout_owner (aout);
397 *lost = atomic_exchange_explicit(&owner->buffers_lost, 0,
398 memory_order_relaxed);
399 *played = atomic_exchange_explicit(&owner->buffers_played, 0,
400 memory_order_relaxed);
403 void aout_DecChangePause (audio_output_t *aout, bool paused, vlc_tick_t date)
405 aout_owner_t *owner = aout_owner (aout);
407 if (owner->sync.end != VLC_TICK_INVALID)
409 if (paused)
410 owner->sync.end -= date;
411 else
412 owner->sync.end += date;
415 if (owner->mixer_format.i_format)
416 aout->pause(aout, paused, date);
419 void aout_DecChangeRate(audio_output_t *aout, float rate)
421 aout_owner_t *owner = aout_owner(aout);
423 owner->sync.rate = rate;
426 void aout_DecFlush (audio_output_t *aout, bool wait)
428 aout_owner_t *owner = aout_owner (aout);
430 owner->sync.end = VLC_TICK_INVALID;
431 if (owner->mixer_format.i_format)
433 if (wait)
435 block_t *block = aout_FiltersDrain (owner->filters);
436 if (block)
437 aout->play(aout, block, block->i_pts);
439 else
440 aout_FiltersFlush (owner->filters);
442 aout->flush(aout, wait);
444 owner->sync.discontinuity = true;