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 /*****************************************************************************
25 *****************************************************************************/
34 #include <vlc_common.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
)
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" );
60 if( p_format
->i_rate
> 352800 )
62 msg_Err( p_aout
, "excessive audio sample frequency (%u)",
66 if( p_format
->i_rate
< 4000 )
68 msg_Err( p_aout
, "too low audio sample frequency (%u)",
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
))
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
,
90 if (owner
->filters
== NULL
)
92 aout_OutputDelete (p_aout
);
94 aout_volume_Delete (owner
->volume
);
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
);
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
);
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
))
214 msg_Dbg (aout
, "inserting %zu zeroes", frames
);
215 memset (block
->p_buffer
, 0, block
->i_buffer
);
216 block
->i_nb_samples
= frames
;
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
;
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
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
);
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;
291 if (!aout_FiltersCanResample(owner
->filters
))
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",
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",
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
);
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. */
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
);
372 /* Software volume */
373 aout_volume_Amplify (owner
->volume
, block
);
375 /* Drift correction */
376 aout_DecSynchronize(aout
, block
->i_pts
);
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
);
385 owner
->sync
.discontinuity
= true;
386 block_Release (block
);
388 atomic_fetch_add_explicit(&owner
->buffers_lost
, 1, memory_order_relaxed
);
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
)
410 owner
->sync
.end
-= date
;
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
)
435 block_t
*block
= aout_FiltersDrain (owner
->filters
);
437 aout
->play(aout
, block
, block
->i_pts
);
440 aout_FiltersFlush (owner
->filters
);
442 aout
->flush(aout
, wait
);
444 owner
->sync
.discontinuity
= true;