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
)
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" );
59 if( p_format
->i_rate
> 352800 )
61 msg_Err( p_aout
, "excessive audio sample frequency (%u)",
65 if( p_format
->i_rate
< 4000 )
67 msg_Err( p_aout
, "too low audio sample frequency (%u)",
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
))
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
,
97 if (owner
->filters
== NULL
)
99 aout_OutputDelete (p_aout
);
101 aout_volume_Delete (owner
->volume
);
102 owner
->volume
= NULL
;
103 aout_OutputUnlock (p_aout
);
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);
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
);
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
))
224 msg_Dbg (aout
, "inserting %zu zeroes", frames
);
225 memset (block
->p_buffer
, 0, block
->i_buffer
);
226 block
->i_nb_samples
= frames
;
229 block
->i_length
= length
;
230 aout_OutputPlay (aout
, block
);
233 static void aout_DecSynchronize (audio_output_t
*aout
, mtime_t dec_pts
,
236 aout_owner_t
*owner
= aout_owner (aout
);
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
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
);
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;
301 if (!aout_FiltersCanResample(owner
->filters
))
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",
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",
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
);
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. */
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
);
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
);
384 if (block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
385 owner
->sync
.discontinuity
= true;
387 block
= aout_FiltersPlay (owner
->filters
, block
, input_rate
);
391 /* Software volume */
392 aout_volume_Amplify (owner
->volume
, block
);
394 /* Drift correction */
395 aout_DecSynchronize (aout
, block
->i_pts
, input_rate
);
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);
403 aout_OutputUnlock (aout
);
406 owner
->sync
.discontinuity
= true;
407 block_Release (block
);
409 atomic_fetch_add(&owner
->buffers_lost
, 1);
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
)
430 owner
->sync
.end
-= date
;
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
)
449 block_t
*block
= aout_FiltersDrain (owner
->filters
);
451 aout_OutputPlay (aout
, block
);
454 aout_FiltersFlush (owner
->filters
);
455 aout_OutputFlush (aout
, wait
);
457 aout_OutputUnlock (aout
);