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_aout_mixer.h>
36 #include <vlc_input.h>
37 #include <vlc_atomic.h>
39 #include "aout_internal.h"
42 static int ReplayGainCallback (vlc_object_t *, char const *,
43 vlc_value_t, vlc_value_t, void *);
46 * Creates an audio output
48 int aout_DecNew( audio_output_t *p_aout,
49 const audio_sample_format_t *p_format,
50 const audio_replay_gain_t *p_replay_gain,
51 const aout_request_vout_t *p_request_vout )
53 /* Sanitize audio format */
54 if( p_format->i_channels > AOUT_CHAN_MAX )
56 msg_Err( p_aout, "too many audio channels (%u)",
57 p_format->i_channels );
60 if( p_format->i_channels <= 0 )
62 msg_Err( p_aout, "no audio channels" );
65 if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
67 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
71 if( p_format->i_rate > 192000 )
73 msg_Err( p_aout, "excessive audio sample frequency (%u)",
77 if( p_format->i_rate < 4000 )
79 msg_Err( p_aout, "too low audio sample frequency (%u)",
84 aout_owner_t *owner = aout_owner(p_aout);
86 /* Calling decoder is responsible for serializing aout_DecNew() and
87 * aout_DecDelete(). So no need to lock to _read_ those properties. */
88 if (owner->module != NULL) /* <- output exists */
89 { /* Check if we can recycle the existing output and pipelines */
90 if (AOUT_FMTS_IDENTICAL(&owner->input_format, p_format))
93 /* TODO? If the new input format is closer to the output format than
94 * the old input format was, then the output could be recycled. The
95 * input pipeline however would need to be restarted. */
97 /* No recycling: delete everything and restart from scratch */
98 aout_Shutdown (p_aout);
103 /* TODO: reduce lock scope depending on decoder's real need */
105 assert (owner->module == NULL);
107 /* Create the audio output stream */
108 var_Destroy( p_aout, "audio-device" );
109 var_Destroy( p_aout, "audio-channels" );
111 owner->input_format = *p_format;
112 vlc_atomic_set (&owner->restart, 0);
113 if( aout_OutputNew( p_aout, p_format ) < 0 )
119 /* Allocate a software mixer */
120 assert (owner->volume.mixer == NULL);
121 owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
123 aout_ReplayGainInit (&owner->gain.data, p_replay_gain);
124 var_AddCallback (p_aout, "audio-replay-gain-mode",
125 ReplayGainCallback, owner);
126 var_TriggerCallback (p_aout, "audio-replay-gain-mode");
128 /* Create the audio filtering "input" pipeline */
129 date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
130 date_Set (&owner->sync.date, VLC_TS_INVALID);
132 assert (owner->input == NULL);
133 owner->input = aout_InputNew (p_aout, p_format, &owner->mixer_format,
135 if (owner->input == NULL)
137 struct audio_mixer *mixer = owner->volume.mixer;
139 owner->volume.mixer = NULL;
140 aout_OutputDelete (p_aout);
141 aout_unlock (p_aout);
142 aout_MixerDelete (mixer);
146 aout_unlock( p_aout );
151 * Stops all plugins involved in the audio output.
153 void aout_Shutdown (audio_output_t *p_aout)
155 aout_owner_t *owner = aout_owner (p_aout);
157 struct audio_mixer *mixer;
160 /* Remove the input. */
161 input = owner->input;
162 if (likely(input != NULL))
163 aout_InputDelete (p_aout, input);
166 mixer = owner->volume.mixer;
167 owner->volume.mixer = NULL;
169 var_DelCallback (p_aout, "audio-replay-gain-mode",
170 ReplayGainCallback, owner);
172 aout_OutputDelete( p_aout );
173 var_Destroy( p_aout, "audio-device" );
174 var_Destroy( p_aout, "audio-channels" );
176 aout_unlock( p_aout );
178 aout_MixerDelete (mixer);
183 * Stops the decoded audio input.
184 * @note Due to output recycling, this function is esssentially a stub.
186 void aout_DecDelete (audio_output_t *aout)
191 aout_Shutdown (aout);
195 #define AOUT_RESTART_OUTPUT 1
196 #define AOUT_RESTART_INPUT 2
197 static void aout_CheckRestart (audio_output_t *aout)
199 aout_owner_t *owner = aout_owner (aout);
201 aout_assert_locked (aout);
203 int restart = vlc_atomic_swap (&owner->restart, 0);
204 if (likely(restart == 0))
207 assert (restart & AOUT_RESTART_INPUT);
209 const aout_request_vout_t request_vout = owner->input->request_vout;
211 if (likely(owner->input != NULL))
212 aout_InputDelete (aout, owner->input);
215 /* Reinitializes the output */
216 if (restart & AOUT_RESTART_OUTPUT)
218 aout_MixerDelete (owner->volume.mixer);
219 owner->volume.mixer = NULL;
220 aout_OutputDelete (aout);
222 if (aout_OutputNew (aout, &owner->input_format))
223 return; /* we are officially screwed */
224 owner->volume.mixer = aout_MixerNew (aout,
225 owner->mixer_format.i_format);
228 owner->input = aout_InputNew (aout, &owner->input_format,
229 &owner->mixer_format, &request_vout);
233 * Marks the audio output for restart, to update any parameter of the output
234 * plug-in (e.g. output device or channel mapping).
236 void aout_RequestRestart (audio_output_t *aout)
238 aout_owner_t *owner = aout_owner (aout);
240 /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
241 vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
245 * This function will safely mark aout input to be restarted as soon as
246 * possible to take configuration changes into account
248 void aout_InputRequestRestart (audio_output_t *aout)
250 aout_owner_t *owner = aout_owner (aout);
252 vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
260 /*****************************************************************************
261 * aout_DecNewBuffer : ask for a new empty buffer
262 *****************************************************************************/
263 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
265 /* NOTE: the caller is responsible for serializing input change */
266 aout_owner_t *owner = aout_owner (aout);
268 size_t length = samples * owner->input_format.i_bytes_per_frame
269 / owner->input_format.i_frame_length;
270 block_t *block = block_Alloc( length );
271 if( likely(block != NULL) )
273 block->i_nb_samples = samples;
274 block->i_pts = block->i_length = 0;
279 /*****************************************************************************
280 * aout_DecDeleteBuffer : destroy an undecoded buffer
281 *****************************************************************************/
282 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
285 aout_BufferFree (block);
288 /*****************************************************************************
289 * aout_DecPlay : filter & mix the decoded buffer
290 *****************************************************************************/
291 int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
293 aout_owner_t *owner = aout_owner (p_aout);
296 assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
297 i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
298 assert( p_buffer->i_pts > 0 );
300 p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
301 / owner->input_format.i_rate;
304 aout_CheckRestart( p_aout );
306 input = owner->input;
307 if (unlikely(input == NULL)) /* can happen due to restart */
309 aout_unlock( p_aout );
310 aout_BufferFree( p_buffer );
315 p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
317 if( p_buffer != NULL )
319 date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
322 if (owner->volume.mixer != NULL)
324 float amp = owner->volume.multiplier
325 * vlc_atomic_getf (&owner->gain.multiplier);
326 aout_MixerRun (owner->volume.mixer, p_buffer, amp);
330 aout_OutputPlay( p_aout, p_buffer );
333 aout_unlock( p_aout );
337 int aout_DecGetResetLost (audio_output_t *aout)
339 aout_owner_t *owner = aout_owner (aout);
340 aout_input_t *input = owner->input;
344 if (likely(input != NULL))
346 val = input->i_buffer_lost;
347 input->i_buffer_lost = 0;
350 val = 0; /* if aout_CheckRestart() failed */
356 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
358 aout_owner_t *owner = aout_owner (aout);
361 /* XXX: Should the date be offset by the pause duration instead? */
362 date_Set (&owner->sync.date, VLC_TS_INVALID);
363 aout_OutputPause (aout, paused, date);
367 void aout_DecFlush (audio_output_t *aout)
369 aout_owner_t *owner = aout_owner (aout);
372 date_Set (&owner->sync.date, VLC_TS_INVALID);
373 aout_OutputFlush (aout, false);
377 bool aout_DecIsEmpty (audio_output_t *aout)
379 aout_owner_t *owner = aout_owner (aout);
380 mtime_t end_date, now = mdate ();
384 end_date = date_Get (&owner->sync.date);
385 empty = end_date == VLC_TS_INVALID || end_date <= now;
387 /* The last PTS has elapsed already. So the underlying audio output
388 * buffer should be empty or almost. Thus draining should be fast
389 * and will not block the caller too long. */
390 aout_OutputFlush (aout, true);
396 * Notifies the audio input of the drift from the requested audio
397 * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
398 * as reported by the audio output hardware.
399 * Depending on the drift amplitude, the input core may ignore the drift
400 * trigger upsampling or downsampling, or even discard samples.
401 * Future VLC versions may instead adjust the input decoding speed.
403 * The audio output plugin is responsible for estimating the ideal current
404 * playback time defined as follows:
405 * ideal time = buffer timestamp - (output latency + pending buffer duration)
407 * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
408 * the latency reported by the output programming interface.
409 * Computing the estimated drift directly would probably be more intuitive.
410 * However the use of an absolute time value does not introduce extra
411 * measurement errors due to the CPU scheduling jitter and clock resolution.
412 * Furthermore, the ideal while it is an abstract value, is easy for most
413 * audio output plugins to compute.
414 * The following definition is equivalent but depends on the clock time:
415 * ideal time = real time + drift
417 * @note If aout_LatencyReport() is never called, the core will assume that
420 * @param ideal estimated ideal time as defined above.
422 void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
424 mtime_t delta = mdate() - ideal /* = -drift */;
426 aout_assert_locked (aout);
427 if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
429 aout_owner_t *owner = aout_owner (aout);
431 msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
433 if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
434 date_Move (&owner->sync.date, delta);
438 static int ReplayGainCallback (vlc_object_t *obj, char const *var,
439 vlc_value_t oldval, vlc_value_t val, void *data)
441 aout_owner_t *owner = data;
442 float multiplier = aout_ReplayGainSelect (obj, val.psz_string,
444 vlc_atomic_setf (&owner->gain.multiplier, multiplier);
445 VLC_UNUSED(var); VLC_UNUSED(oldval);