1 /*****************************************************************************
2 * mixer.c : audio output mixing operations
3 *****************************************************************************
4 * Copyright (C) 2002-2004 VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* calloc(), malloc(), free() */
36 #include "audio_output.h"
37 #include "aout_internal.h"
39 /*****************************************************************************
40 * aout_MixerNew: prepare a mixer plug-in
41 *****************************************************************************
42 * Please note that you must hold the mixer lock.
43 *****************************************************************************/
44 int aout_MixerNew( aout_instance_t
* p_aout
)
46 p_aout
->mixer
.p_module
= module_Need( p_aout
, "audio mixer", NULL
, 0 );
47 if ( p_aout
->mixer
.p_module
== NULL
)
49 msg_Err( p_aout
, "no suitable aout mixer" );
52 p_aout
->mixer
.b_error
= 0;
56 /*****************************************************************************
57 * aout_MixerDelete: delete the mixer
58 *****************************************************************************
59 * Please note that you must hold the mixer lock.
60 *****************************************************************************/
61 void aout_MixerDelete( aout_instance_t
* p_aout
)
63 if ( p_aout
->mixer
.b_error
) return;
64 module_Unneed( p_aout
, p_aout
->mixer
.p_module
);
65 p_aout
->mixer
.b_error
= 1;
68 /*****************************************************************************
69 * MixBuffer: try to prepare one output buffer
70 *****************************************************************************
71 * Please note that you must hold the mixer lock.
72 *****************************************************************************/
73 static int MixBuffer( aout_instance_t
* p_aout
)
75 int i
, i_first_input
= 0;
76 aout_buffer_t
* p_output_buffer
;
77 mtime_t start_date
, end_date
;
78 audio_date_t exact_start_date
;
80 if ( p_aout
->mixer
.b_error
)
82 /* Free all incoming buffers. */
83 vlc_mutex_lock( &p_aout
->input_fifos_lock
);
84 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
86 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
87 aout_buffer_t
* p_buffer
= p_input
->fifo
.p_first
;
88 if ( p_input
->b_error
) continue;
89 while ( p_buffer
!= NULL
)
91 aout_buffer_t
* p_next
= p_buffer
->p_next
;
92 aout_BufferFree( p_buffer
);
96 vlc_mutex_unlock( &p_aout
->input_fifos_lock
);
101 vlc_mutex_lock( &p_aout
->output_fifo_lock
);
102 vlc_mutex_lock( &p_aout
->input_fifos_lock
);
104 /* Retrieve the date of the next buffer. */
105 memcpy( &exact_start_date
, &p_aout
->output
.fifo
.end_date
,
106 sizeof(audio_date_t
) );
107 start_date
= aout_DateGet( &exact_start_date
);
109 if ( start_date
!= 0 && start_date
< mdate() )
111 /* The output is _very_ late. This can only happen if the user
112 * pauses the stream (or if the decoder is buggy, which cannot
114 msg_Warn( p_aout
, "output PTS is out of range ("I64Fd
"), clearing out",
115 mdate() - start_date
);
116 aout_FifoSet( p_aout
, &p_aout
->output
.fifo
, 0 );
117 aout_DateSet( &exact_start_date
, 0 );
121 vlc_mutex_unlock( &p_aout
->output_fifo_lock
);
123 /* See if we have enough data to prepare a new buffer for the audio
124 * output. First : start date. */
127 /* Find the latest start date available. */
128 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
130 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
131 aout_fifo_t
* p_fifo
= &p_input
->fifo
;
132 aout_buffer_t
* p_buffer
;
134 if ( p_input
->b_error
) continue;
136 p_buffer
= p_fifo
->p_first
;
137 while ( p_buffer
!= NULL
&& p_buffer
->start_date
< mdate() )
139 msg_Warn( p_aout
, "input PTS is out of range ("I64Fd
"), "
140 "trashing", mdate() - p_buffer
->start_date
);
141 p_buffer
= aout_FifoPop( p_aout
, p_fifo
);
142 aout_BufferFree( p_buffer
);
143 p_buffer
= p_fifo
->p_first
;
144 p_input
->p_first_byte_to_mix
= NULL
;
147 if ( p_buffer
== NULL
)
152 if ( !start_date
|| start_date
< p_buffer
->start_date
)
154 aout_DateSet( &exact_start_date
, p_buffer
->start_date
);
155 start_date
= p_buffer
->start_date
;
159 if ( i
< p_aout
->i_nb_inputs
)
161 /* Interrupted before the end... We can't run. */
162 vlc_mutex_unlock( &p_aout
->input_fifos_lock
);
166 aout_DateIncrement( &exact_start_date
, p_aout
->output
.i_nb_samples
);
167 end_date
= aout_DateGet( &exact_start_date
);
169 /* Check that start_date and end_date are available for all input
171 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
173 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
174 aout_fifo_t
* p_fifo
= &p_input
->fifo
;
175 aout_buffer_t
* p_buffer
;
177 vlc_bool_t b_drop_buffers
;
179 if ( p_input
->b_error
)
181 if ( i_first_input
== i
) i_first_input
++;
185 p_buffer
= p_fifo
->p_first
;
186 if ( p_buffer
== NULL
)
191 /* Check for the continuity of start_date */
192 while ( p_buffer
!= NULL
&& p_buffer
->end_date
< start_date
- 1 )
194 /* We authorize a +-1 because rounding errors get compensated
196 aout_buffer_t
* p_next
= p_buffer
->p_next
;
197 msg_Warn( p_aout
, "the mixer got a packet in the past ("I64Fd
")",
198 start_date
- p_buffer
->end_date
);
199 aout_BufferFree( p_buffer
);
200 p_fifo
->p_first
= p_buffer
= p_next
;
201 p_input
->p_first_byte_to_mix
= NULL
;
203 if ( p_buffer
== NULL
)
205 p_fifo
->pp_last
= &p_fifo
->p_first
;
209 /* Check that we have enough samples. */
212 p_buffer
= p_fifo
->p_first
;
213 if ( p_buffer
== NULL
) break;
214 if ( p_buffer
->end_date
>= end_date
) break;
216 /* Check that all buffers are contiguous. */
217 prev_date
= p_fifo
->p_first
->end_date
;
218 p_buffer
= p_buffer
->p_next
;
220 for ( ; p_buffer
!= NULL
; p_buffer
= p_buffer
->p_next
)
222 if ( prev_date
!= p_buffer
->start_date
)
225 "buffer hole, dropping packets ("I64Fd
")",
226 p_buffer
->start_date
- prev_date
);
230 if ( p_buffer
->end_date
>= end_date
) break;
231 prev_date
= p_buffer
->end_date
;
233 if ( b_drop_buffers
)
235 aout_buffer_t
* p_deleted
= p_fifo
->p_first
;
236 while ( p_deleted
!= NULL
&& p_deleted
!= p_buffer
)
238 aout_buffer_t
* p_next
= p_deleted
->p_next
;
239 aout_BufferFree( p_deleted
);
242 p_fifo
->p_first
= p_deleted
; /* == p_buffer */
246 if ( p_buffer
== NULL
) break;
248 p_buffer
= p_fifo
->p_first
;
249 if ( !AOUT_FMT_NON_LINEAR( &p_aout
->mixer
.mixer
) )
251 /* Additionally check that p_first_byte_to_mix is well
253 mtime_t i_nb_bytes
= (start_date
- p_buffer
->start_date
)
254 * p_aout
->mixer
.mixer
.i_bytes_per_frame
255 * p_aout
->mixer
.mixer
.i_rate
256 / p_aout
->mixer
.mixer
.i_frame_length
258 ptrdiff_t mixer_nb_bytes
;
260 if ( p_input
->p_first_byte_to_mix
== NULL
)
262 p_input
->p_first_byte_to_mix
= p_buffer
->p_buffer
;
264 mixer_nb_bytes
= p_input
->p_first_byte_to_mix
- p_buffer
->p_buffer
;
266 if ( !((i_nb_bytes
+ p_aout
->mixer
.mixer
.i_bytes_per_frame
268 (i_nb_bytes
< p_aout
->mixer
.mixer
.i_bytes_per_frame
271 msg_Warn( p_aout
, "mixer start isn't output start ("I64Fd
")",
272 i_nb_bytes
- mixer_nb_bytes
);
274 /* Round to the nearest multiple */
275 i_nb_bytes
/= p_aout
->mixer
.mixer
.i_bytes_per_frame
;
276 i_nb_bytes
*= p_aout
->mixer
.mixer
.i_bytes_per_frame
;
279 /* Is it really the best way to do it ? */
280 aout_FifoSet( p_aout
, &p_aout
->output
.fifo
, 0 );
281 aout_DateSet( &exact_start_date
, 0 );
285 p_input
->p_first_byte_to_mix
= p_buffer
->p_buffer
+ i_nb_bytes
;
290 if ( i
< p_aout
->i_nb_inputs
|| i_first_input
== p_aout
->i_nb_inputs
)
292 /* Interrupted before the end... We can't run. */
293 vlc_mutex_unlock( &p_aout
->input_fifos_lock
);
298 aout_BufferAlloc( &p_aout
->mixer
.output_alloc
,
299 ((uint64_t)p_aout
->output
.i_nb_samples
* 1000000)
300 / p_aout
->output
.output
.i_rate
,
301 /* This is a bit kludgy, but is actually only used
302 * for the S/PDIF dummy mixer : */
303 p_aout
->pp_inputs
[i_first_input
]->fifo
.p_first
,
305 if ( p_output_buffer
== NULL
)
307 msg_Err( p_aout
, "out of memory" );
308 vlc_mutex_unlock( &p_aout
->input_fifos_lock
);
311 /* This is again a bit kludgy - for the S/PDIF mixer. */
312 if ( p_aout
->mixer
.output_alloc
.i_alloc_type
!= AOUT_ALLOC_NONE
)
314 p_output_buffer
->i_nb_samples
= p_aout
->output
.i_nb_samples
;
315 p_output_buffer
->i_nb_bytes
= p_aout
->output
.i_nb_samples
316 * p_aout
->mixer
.mixer
.i_bytes_per_frame
317 / p_aout
->mixer
.mixer
.i_frame_length
;
319 p_output_buffer
->start_date
= start_date
;
320 p_output_buffer
->end_date
= end_date
;
322 p_aout
->mixer
.pf_do_work( p_aout
, p_output_buffer
);
324 vlc_mutex_unlock( &p_aout
->input_fifos_lock
);
326 aout_OutputPlay( p_aout
, p_output_buffer
);
331 /*****************************************************************************
332 * aout_MixerRun: entry point for the mixer & post-filters processing
333 *****************************************************************************
334 * Please note that you must hold the mixer lock.
335 *****************************************************************************/
336 void aout_MixerRun( aout_instance_t
* p_aout
)
338 while( MixBuffer( p_aout
) != -1 );
341 /*****************************************************************************
342 * aout_MixerMultiplierSet: set p_aout->mixer.f_multiplier
343 *****************************************************************************
344 * Please note that we assume that you own the mixer lock when entering this
345 * function. This function returns -1 on error.
346 *****************************************************************************/
347 int aout_MixerMultiplierSet( aout_instance_t
* p_aout
, float f_multiplier
)
349 float f_old
= p_aout
->mixer
.f_multiplier
;
350 vlc_bool_t b_new_mixer
= 0;
352 if ( !p_aout
->mixer
.b_error
)
354 aout_MixerDelete( p_aout
);
358 p_aout
->mixer
.f_multiplier
= f_multiplier
;
360 if ( b_new_mixer
&& aout_MixerNew( p_aout
) )
362 p_aout
->mixer
.f_multiplier
= f_old
;
363 aout_MixerNew( p_aout
);
370 /*****************************************************************************
371 * aout_MixerMultiplierGet: get p_aout->mixer.f_multiplier
372 *****************************************************************************
373 * Please note that we assume that you own the mixer lock when entering this
374 * function. This function returns -1 on error.
375 *****************************************************************************/
376 int aout_MixerMultiplierGet( aout_instance_t
* p_aout
, float * pf_multiplier
)
378 *pf_multiplier
= p_aout
->mixer
.f_multiplier
;