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>
36 #include <vlc_atomic.h>
38 #include "aout_internal.h"
42 * Creates an audio output
44 int aout_DecNew( audio_output_t *p_aout,
45 const audio_sample_format_t *p_format,
46 const audio_replay_gain_t *p_replay_gain,
47 const aout_request_vout_t *p_request_vout )
49 /* Sanitize audio format */
50 if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
52 msg_Err( p_aout, "incompatible audio channels count with layout mask" );
56 if( p_format->i_rate > 192000 )
58 msg_Err( p_aout, "excessive audio sample frequency (%u)",
62 if( p_format->i_rate < 4000 )
64 msg_Err( p_aout, "too low audio sample frequency (%u)",
69 aout_owner_t *owner = aout_owner(p_aout);
72 /* TODO: reduce lock scope depending on decoder's real need */
75 var_Destroy( p_aout, "stereo-mode" );
77 /* Create the audio output stream */
78 owner->input_format = *p_format;
79 vlc_atomic_set (&owner->restart, 0);
80 owner->volume = aout_volume_New (p_aout, p_replay_gain);
81 if( aout_OutputNew( p_aout, p_format ) < 0 )
83 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
85 /* Create the audio filtering "input" pipeline */
86 if (aout_FiltersNew (p_aout, p_format, &owner->mixer_format,
89 aout_OutputDelete (p_aout);
91 aout_volume_Delete (owner->volume);
96 date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1);
97 date_Set (&owner->sync.date, VLC_TS_INVALID);
99 assert (owner->input == NULL);
100 owner->input = aout_InputNew (p_format);
101 aout_unlock( p_aout );
106 * Stops all plugins involved in the audio output.
108 void aout_DecDelete (audio_output_t *p_aout)
110 aout_owner_t *owner = aout_owner (p_aout);
114 /* Remove the input. */
115 input = owner->input;
116 aout_InputDelete (input);
119 aout_FiltersDelete (p_aout);
120 aout_OutputDelete( p_aout );
121 aout_volume_Delete (owner->volume);
123 var_Destroy( p_aout, "stereo-mode" );
125 aout_unlock( p_aout );
128 #define AOUT_RESTART_OUTPUT 1
129 #define AOUT_RESTART_INPUT 2
130 static void aout_CheckRestart (audio_output_t *aout)
132 aout_owner_t *owner = aout_owner (aout);
134 aout_assert_locked (aout);
136 int restart = vlc_atomic_swap (&owner->restart, 0);
137 if (likely(restart == 0))
140 assert (restart & AOUT_RESTART_INPUT);
142 const aout_request_vout_t request_vout = owner->request_vout;
144 aout_InputDelete (owner->input);
147 aout_FiltersDelete (aout);
149 /* Reinitializes the output */
150 if (restart & AOUT_RESTART_OUTPUT)
152 aout_OutputDelete (aout);
153 if (aout_OutputNew (aout, &owner->input_format))
155 aout_volume_Delete (owner->volume);
156 return; /* we are officially screwed */
158 aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
161 if (aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format,
163 owner->input = aout_InputNew (&owner->input_format);
167 * Marks the audio output for restart, to update any parameter of the output
168 * plug-in (e.g. output device or channel mapping).
170 static void aout_RequestRestart (audio_output_t *aout)
172 aout_owner_t *owner = aout_owner (aout);
174 /* DO NOT remove AOUT_RESTART_INPUT. You need to change the atomic ops. */
175 vlc_atomic_set (&owner->restart, AOUT_RESTART_OUTPUT|AOUT_RESTART_INPUT);
178 int aout_ChannelsRestart (vlc_object_t *obj, const char *varname,
179 vlc_value_t oldval, vlc_value_t newval, void *data)
181 audio_output_t *aout = (audio_output_t *)obj;
182 (void)oldval; (void)newval; (void)data;
184 if (!strcmp (varname, "audio-device"))
186 /* This is supposed to be a significant change and supposes
187 * rebuilding the channel choices. */
188 var_Destroy (aout, "stereo-mode");
190 aout_RequestRestart (aout);
195 * This function will safely mark aout input to be restarted as soon as
196 * possible to take configuration changes into account
198 void aout_InputRequestRestart (audio_output_t *aout)
200 aout_owner_t *owner = aout_owner (aout);
202 vlc_atomic_compare_swap (&owner->restart, 0, AOUT_RESTART_INPUT);
210 /*****************************************************************************
211 * aout_DecNewBuffer : ask for a new empty buffer
212 *****************************************************************************/
213 block_t *aout_DecNewBuffer (audio_output_t *aout, size_t samples)
215 /* NOTE: the caller is responsible for serializing input change */
216 aout_owner_t *owner = aout_owner (aout);
218 size_t length = samples * owner->input_format.i_bytes_per_frame
219 / owner->input_format.i_frame_length;
220 block_t *block = block_Alloc( length );
221 if( likely(block != NULL) )
223 block->i_nb_samples = samples;
224 block->i_pts = block->i_length = 0;
229 /*****************************************************************************
230 * aout_DecDeleteBuffer : destroy an undecoded buffer
231 *****************************************************************************/
232 void aout_DecDeleteBuffer (audio_output_t *aout, block_t *block)
235 block_Release (block);
238 /*****************************************************************************
239 * aout_DecPlay : filter & mix the decoded buffer
240 *****************************************************************************/
241 int aout_DecPlay (audio_output_t *p_aout, block_t *p_buffer, int i_input_rate)
243 aout_owner_t *owner = aout_owner (p_aout);
246 assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
247 i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
248 assert( p_buffer->i_pts > 0 );
250 p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
251 / owner->input_format.i_rate;
254 aout_CheckRestart( p_aout );
256 input = owner->input;
257 if (unlikely(input == NULL)) /* can happen due to restart */
259 aout_unlock( p_aout );
260 block_Release( p_buffer );
265 p_buffer = aout_InputPlay (p_aout, input, p_buffer, i_input_rate,
267 if( p_buffer != NULL )
269 date_Increment (&owner->sync.date, p_buffer->i_nb_samples);
272 aout_volume_Amplify (owner->volume, p_buffer);
275 aout_OutputPlay( p_aout, p_buffer );
278 aout_unlock( p_aout );
282 int aout_DecGetResetLost (audio_output_t *aout)
284 aout_owner_t *owner = aout_owner (aout);
285 aout_input_t *input = owner->input;
289 if (likely(input != NULL))
291 val = input->i_buffer_lost;
292 input->i_buffer_lost = 0;
295 val = 0; /* if aout_CheckRestart() failed */
301 void aout_DecChangePause (audio_output_t *aout, bool paused, mtime_t date)
303 aout_owner_t *owner = aout_owner (aout);
306 /* XXX: Should the date be offset by the pause duration instead? */
307 date_Set (&owner->sync.date, VLC_TS_INVALID);
308 aout_OutputPause (aout, paused, date);
312 void aout_DecFlush (audio_output_t *aout)
314 aout_owner_t *owner = aout_owner (aout);
317 date_Set (&owner->sync.date, VLC_TS_INVALID);
318 aout_OutputFlush (aout, false);
322 bool aout_DecIsEmpty (audio_output_t *aout)
324 aout_owner_t *owner = aout_owner (aout);
325 mtime_t end_date, now = mdate ();
329 end_date = date_Get (&owner->sync.date);
330 empty = end_date == VLC_TS_INVALID || end_date <= now;
332 /* The last PTS has elapsed already. So the underlying audio output
333 * buffer should be empty or almost. Thus draining should be fast
334 * and will not block the caller too long. */
335 aout_OutputFlush (aout, true);