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_FormatNbChannels( p_format ) )
56 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
60 if( p_format->i_rate > 192000 )
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 /* Calling decoder is responsible for serializing aout_DecNew() and
76 * aout_DecDelete(). So no need to lock to _read_ those properties. */
77 if (owner->module != NULL) /* <- output exists */
78 { /* Check if we can recycle the existing output and pipelines */
79 if (AOUT_FMTS_IDENTICAL(&owner->input_format, p_format))
82 /* TODO? If the new input format is closer to the output format than
83 * the old input format was, then the output could be recycled. The
84 * input pipeline however would need to be restarted. */
86 /* No recycling: delete everything and restart from scratch */
87 aout_Shutdown (p_aout);
92 /* TODO: reduce lock scope depending on decoder's real need */
94 assert (owner->module == NULL);
96 /* Create the audio output stream */
97 var_Destroy( p_aout, "audio-device" );
98 var_Destroy( p_aout, "audio-channels" );
100 owner->input_format = *p_format;
101 vlc_atomic_set (&owner->restart, 0);
102 if( aout_OutputNew( p_aout, p_format ) < 0 )
108 /* Allocate a software mixer */
109 assert (owner->volume.mixer == NULL);
110 owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
112 aout_ReplayGainInit (&owner->gain.data, p_replay_gain);
113 var_AddCallback (p_aout, "audio-replay-gain-mode",
114 ReplayGainCallback, owner);
115 var_TriggerCallback (p_aout, "audio-replay-gain-mode");
117 /* Create the audio filtering "input" pipeline */
118 date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
119 date_Set (&owner->sync.date, VLC_TS_INVALID);
121 assert (owner->input == NULL);
122 owner->input = aout_InputNew (p_aout, p_format, &owner->mixer_format,
124 if (owner->input == NULL)
126 struct audio_mixer *mixer = owner->volume.mixer;
128 owner->volume.mixer = NULL;
129 aout_OutputDelete (p_aout);
130 aout_unlock (p_aout);
131 aout_MixerDelete (mixer);
135 aout_unlock( p_aout );
140 * Stops all plugins involved in the audio output.
142 void aout_Shutdown (audio_output_t *p_aout)
144 aout_owner_t *owner = aout_owner (p_aout);
146 struct audio_mixer *mixer;
149 /* Remove the input. */
150 input = owner->input;
151 if (likely(input != NULL))
152 aout_InputDelete (p_aout, input);
155 mixer = owner->volume.mixer;
156 owner->volume.mixer = NULL;
158 var_DelCallback (p_aout, "audio-replay-gain-mode",
159 ReplayGainCallback, owner);
161 aout_OutputDelete( p_aout );
162 var_Destroy( p_aout, "audio-device" );
163 var_Destroy( p_aout, "audio-channels" );
165 aout_unlock( p_aout );
167 aout_MixerDelete (mixer);
172 * Stops the decoded audio input.
173 * @note Due to output recycling, this function is esssentially a stub.
175 void aout_DecDelete (audio_output_t *aout)
180 aout_Shutdown (aout);
184 #define AOUT_RESTART_OUTPUT 1
185 #define AOUT_RESTART_INPUT 2
186 static void aout_CheckRestart (audio_output_t *aout)
188 aout_owner_t *owner = aout_owner (aout);
190 aout_assert_locked (aout);
192 int restart = vlc_atomic_swap (&owner->restart, 0);
193 if (likely(restart == 0))
196 assert (restart & AOUT_RESTART_INPUT);
198 const aout_request_vout_t request_vout = owner->input->request_vout;
200 if (likely(owner->input != NULL))
201 aout_InputDelete (aout, owner->input);
204 /* Reinitializes the output */
205 if (restart & AOUT_RESTART_OUTPUT)
207 aout_MixerDelete (owner->volume.mixer);
208 owner->volume.mixer = NULL;
209 aout_OutputDelete (aout);
211 if (aout_OutputNew (aout, &owner->input_format))
212 return; /* we are officially screwed */
213 owner->volume.mixer = aout_MixerNew (aout,
214 owner->mixer_format.i_format);
217 owner->input = aout_InputNew (aout, &owner->input_format,
218 &owner->mixer_format, &request_vout);
222 * Marks the audio output for restart, to update any parameter of the output
223 * plug-in (e.g. output device or channel mapping).
225 void aout_RequestRestart (audio_output_t *aout)
227 aout_owner_t *owner = aout_owner (aout);
229 /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
230 vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
234 * This function will safely mark aout input to be restarted as soon as
235 * possible to take configuration changes into account
237 void aout_InputRequestRestart (audio_output_t *aout)
239 aout_owner_t *owner = aout_owner (aout);
241 vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
249 /*****************************************************************************
250 * aout_DecNewBuffer : ask for a new empty buffer
251 *****************************************************************************/
252 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
254 /* NOTE: the caller is responsible for serializing input change */
255 aout_owner_t *owner = aout_owner (aout);
257 size_t length = samples * owner->input_format.i_bytes_per_frame
258 / owner->input_format.i_frame_length;
259 block_t *block = block_Alloc( length );
260 if( likely(block != NULL) )
262 block->i_nb_samples = samples;
263 block->i_pts = block->i_length = 0;
268 /*****************************************************************************
269 * aout_DecDeleteBuffer : destroy an undecoded buffer
270 *****************************************************************************/
271 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
274 aout_BufferFree (block);
277 /*****************************************************************************
278 * aout_DecPlay : filter & mix the decoded buffer
279 *****************************************************************************/
280 int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
282 aout_owner_t *owner = aout_owner (p_aout);
285 assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
286 i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
287 assert( p_buffer->i_pts > 0 );
289 p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
290 / owner->input_format.i_rate;
293 aout_CheckRestart( p_aout );
295 input = owner->input;
296 if (unlikely(input == NULL)) /* can happen due to restart */
298 aout_unlock( p_aout );
299 aout_BufferFree( p_buffer );
304 p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
306 if( p_buffer != NULL )
308 date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
311 if (owner->volume.mixer != NULL)
313 float amp = owner->volume.multiplier
314 * vlc_atomic_getf (&owner->gain.multiplier);
315 aout_MixerRun (owner->volume.mixer, p_buffer, amp);
319 aout_OutputPlay( p_aout, p_buffer );
322 aout_unlock( p_aout );
326 int aout_DecGetResetLost (audio_output_t *aout)
328 aout_owner_t *owner = aout_owner (aout);
329 aout_input_t *input = owner->input;
333 if (likely(input != NULL))
335 val = input->i_buffer_lost;
336 input->i_buffer_lost = 0;
339 val = 0; /* if aout_CheckRestart() failed */
345 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
347 aout_owner_t *owner = aout_owner (aout);
350 /* XXX: Should the date be offset by the pause duration instead? */
351 date_Set (&owner->sync.date, VLC_TS_INVALID);
352 aout_OutputPause (aout, paused, date);
356 void aout_DecFlush (audio_output_t *aout)
358 aout_owner_t *owner = aout_owner (aout);
361 date_Set (&owner->sync.date, VLC_TS_INVALID);
362 aout_OutputFlush (aout, false);
366 bool aout_DecIsEmpty (audio_output_t *aout)
368 aout_owner_t *owner = aout_owner (aout);
369 mtime_t end_date, now = mdate ();
373 end_date = date_Get (&owner->sync.date);
374 empty = end_date == VLC_TS_INVALID || end_date <= now;
376 /* The last PTS has elapsed already. So the underlying audio output
377 * buffer should be empty or almost. Thus draining should be fast
378 * and will not block the caller too long. */
379 aout_OutputFlush (aout, true);
385 * Notifies the audio input of the drift from the requested audio
386 * playback timestamp (@ref block_t.i_pts) to the anticipated playback time
387 * as reported by the audio output hardware.
388 * Depending on the drift amplitude, the input core may ignore the drift
389 * trigger upsampling or downsampling, or even discard samples.
390 * Future VLC versions may instead adjust the input decoding speed.
392 * The audio output plugin is responsible for estimating the ideal current
393 * playback time defined as follows:
394 * ideal time = buffer timestamp - (output latency + pending buffer duration)
396 * Practically, this is the PTS (block_t.i_pts) of the current buffer minus
397 * the latency reported by the output programming interface.
398 * Computing the estimated drift directly would probably be more intuitive.
399 * However the use of an absolute time value does not introduce extra
400 * measurement errors due to the CPU scheduling jitter and clock resolution.
401 * Furthermore, the ideal while it is an abstract value, is easy for most
402 * audio output plugins to compute.
403 * The following definition is equivalent but depends on the clock time:
404 * ideal time = real time + drift
406 * @note If aout_LatencyReport() is never called, the core will assume that
409 * @param ideal estimated ideal time as defined above.
411 void aout_TimeReport (audio_output_t *aout, mtime_t ideal)
413 mtime_t delta = mdate() - ideal /* = -drift */;
415 aout_assert_locked (aout);
416 if (delta < -AOUT_MAX_PTS_ADVANCE || +AOUT_MAX_PTS_DELAY < delta)
418 aout_owner_t *owner = aout_owner (aout);
420 msg_Warn (aout, "not synchronized (%"PRId64" us), resampling",
422 if (date_Get (&owner->sync.date) != VLC_TS_INVALID)
423 date_Move (&owner->sync.date, delta);
427 static int ReplayGainCallback (vlc_object_t *obj, char const *var,
428 vlc_value_t oldval, vlc_value_t val, void *data)
430 aout_owner_t *owner = data;
431 float multiplier = aout_ReplayGainSelect (obj, val.psz_string,
433 vlc_atomic_setf (&owner->gain.multiplier, multiplier);
434 VLC_UNUSED(var); VLC_UNUSED(oldval);