1 /*****************************************************************************
2 * mixer.c : audio output mixing operations
3 *****************************************************************************
4 * Copyright (C) 2002-2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
33 #include <vlc_common.h>
35 #include <vlc_modules.h>
38 #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 assert( !p_aout
->p_mixer
);
47 vlc_assert_locked( &p_aout
->input_fifos_lock
);
49 aout_mixer_t
*p_mixer
= vlc_object_create( p_aout
, sizeof(*p_mixer
) );
53 p_mixer
->fmt
= p_aout
->mixer_format
;
54 p_mixer
->allocation
= p_aout
->mixer_allocation
;
55 p_mixer
->multiplier
= p_aout
->mixer_multiplier
;
56 p_mixer
->input_count
= p_aout
->i_nb_inputs
;
57 p_mixer
->input
= calloc( p_mixer
->input_count
, sizeof(*p_mixer
->input
) );
58 for( int i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
59 p_mixer
->input
[i
] = &p_aout
->pp_inputs
[i
]->mixer
;
63 vlc_object_attach( p_mixer
, p_aout
);
65 p_mixer
->module
= module_need( p_mixer
, "audio mixer", NULL
, false );
66 if( !p_mixer
->module
)
68 msg_Err( p_aout
, "no suitable audio mixer" );
69 free( p_mixer
->input
);
70 vlc_object_release( p_mixer
);
75 p_aout
->p_mixer
= p_mixer
;
79 /*****************************************************************************
80 * aout_MixerDelete: delete the mixer
81 *****************************************************************************
82 * Please note that you must hold the mixer lock.
83 *****************************************************************************/
84 void aout_MixerDelete( aout_instance_t
* p_aout
)
86 if( !p_aout
->p_mixer
)
89 module_unneed( p_aout
->p_mixer
, p_aout
->p_mixer
->module
);
91 free( p_aout
->p_mixer
->input
);
92 vlc_object_release( p_aout
->p_mixer
);
95 p_aout
->p_mixer
= NULL
;
98 /*****************************************************************************
99 * MixBuffer: try to prepare one output buffer
100 *****************************************************************************
101 * Please note that you must hold the mixer lock.
102 *****************************************************************************/
103 static int MixBuffer( aout_instance_t
* p_aout
)
105 int i
, i_first_input
= 0;
106 aout_buffer_t
* p_output_buffer
;
107 mtime_t start_date
, end_date
;
108 date_t exact_start_date
;
110 if( !p_aout
->p_mixer
)
112 /* Free all incoming buffers. */
113 aout_lock_input_fifos( p_aout
);
114 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
116 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
117 aout_buffer_t
* p_buffer
= p_input
->mixer
.fifo
.p_first
;
118 if ( p_input
->b_error
) continue;
119 while ( p_buffer
!= NULL
)
121 aout_buffer_t
* p_next
= p_buffer
->p_next
;
122 aout_BufferFree( p_buffer
);
126 aout_unlock_input_fifos( p_aout
);
131 aout_lock_input_fifos( p_aout
);
132 aout_lock_output_fifo( p_aout
);
134 /* Retrieve the date of the next buffer. */
135 exact_start_date
= p_aout
->output
.fifo
.end_date
;
136 start_date
= date_Get( &exact_start_date
);
138 if ( start_date
!= 0 && start_date
< mdate() )
140 /* The output is _very_ late. This can only happen if the user
141 * pauses the stream (or if the decoder is buggy, which cannot
143 msg_Warn( p_aout
, "output PTS is out of range (%"PRId64
"), clearing out",
144 mdate() - start_date
);
145 aout_FifoSet( p_aout
, &p_aout
->output
.fifo
, 0 );
146 date_Set( &exact_start_date
, 0 );
150 aout_unlock_output_fifo( p_aout
);
152 /* See if we have enough data to prepare a new buffer for the audio
153 * output. First : start date. */
156 /* Find the latest start date available. */
157 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
159 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
160 aout_fifo_t
* p_fifo
= &p_input
->mixer
.fifo
;
161 aout_buffer_t
* p_buffer
;
163 if ( p_input
->b_error
|| p_input
->b_paused
)
166 p_buffer
= p_fifo
->p_first
;
167 while ( p_buffer
!= NULL
&& p_buffer
->i_pts
< mdate() )
169 msg_Warn( p_aout
, "input PTS is out of range (%"PRId64
"), "
170 "trashing", mdate() - p_buffer
->i_pts
);
171 p_buffer
= aout_FifoPop( p_aout
, p_fifo
);
172 aout_BufferFree( p_buffer
);
173 p_buffer
= p_fifo
->p_first
;
174 p_input
->mixer
.begin
= NULL
;
177 if ( p_buffer
== NULL
)
182 if ( !start_date
|| start_date
< p_buffer
->i_pts
)
184 date_Set( &exact_start_date
, p_buffer
->i_pts
);
185 start_date
= p_buffer
->i_pts
;
189 if ( i
< p_aout
->i_nb_inputs
)
191 /* Interrupted before the end... We can't run. */
192 aout_unlock_input_fifos( p_aout
);
196 date_Increment( &exact_start_date
, p_aout
->output
.i_nb_samples
);
197 end_date
= date_Get( &exact_start_date
);
199 /* Check that start_date and end_date are available for all input
201 for ( i
= 0; i
< p_aout
->i_nb_inputs
; i
++ )
203 aout_input_t
* p_input
= p_aout
->pp_inputs
[i
];
204 aout_fifo_t
* p_fifo
= &p_input
->mixer
.fifo
;
205 aout_buffer_t
* p_buffer
;
209 p_input
->mixer
.is_invalid
= p_input
->b_error
|| p_input
->b_paused
;
210 if ( p_input
->mixer
.is_invalid
)
212 if ( i_first_input
== i
) i_first_input
++;
216 p_buffer
= p_fifo
->p_first
;
217 if ( p_buffer
== NULL
)
222 /* Check for the continuity of start_date */
223 while ( p_buffer
!= NULL
224 && p_buffer
->i_pts
+ p_buffer
->i_length
< start_date
- 1 )
226 /* We authorize a +-1 because rounding errors get compensated
228 aout_buffer_t
* p_next
= p_buffer
->p_next
;
229 msg_Warn( p_aout
, "the mixer got a packet in the past (%"PRId64
")",
230 start_date
- (p_buffer
->i_pts
+ p_buffer
->i_length
) );
231 aout_BufferFree( p_buffer
);
232 p_fifo
->p_first
= p_buffer
= p_next
;
233 p_input
->mixer
.begin
= NULL
;
235 if ( p_buffer
== NULL
)
237 p_fifo
->pp_last
= &p_fifo
->p_first
;
241 /* Check that we have enough samples. */
244 p_buffer
= p_fifo
->p_first
;
245 if ( p_buffer
== NULL
) break;
246 if ( p_buffer
->i_pts
+ p_buffer
->i_length
>= end_date
) break;
248 /* Check that all buffers are contiguous. */
249 prev_date
= p_fifo
->p_first
->i_pts
+ p_fifo
->p_first
->i_length
;
250 p_buffer
= p_buffer
->p_next
;
252 for ( ; p_buffer
!= NULL
; p_buffer
= p_buffer
->p_next
)
254 if ( prev_date
!= p_buffer
->i_pts
)
257 "buffer hole, dropping packets (%"PRId64
")",
258 p_buffer
->i_pts
- prev_date
);
262 if ( p_buffer
->i_pts
+ p_buffer
->i_length
>= end_date
) break;
263 prev_date
= p_buffer
->i_pts
+ p_buffer
->i_length
;
265 if ( b_drop_buffers
)
267 aout_buffer_t
* p_deleted
= p_fifo
->p_first
;
268 while ( p_deleted
!= NULL
&& p_deleted
!= p_buffer
)
270 aout_buffer_t
* p_next
= p_deleted
->p_next
;
271 aout_BufferFree( p_deleted
);
274 p_fifo
->p_first
= p_deleted
; /* == p_buffer */
278 if ( p_buffer
== NULL
) break;
280 p_buffer
= p_fifo
->p_first
;
281 if ( !AOUT_FMT_NON_LINEAR( &p_aout
->p_mixer
->fmt
) )
283 /* Additionally check that p_first_byte_to_mix is well
285 mtime_t i_buffer
= (start_date
- p_buffer
->i_pts
)
286 * p_aout
->p_mixer
->fmt
.i_bytes_per_frame
287 * p_aout
->p_mixer
->fmt
.i_rate
288 / p_aout
->p_mixer
->fmt
.i_frame_length
290 ptrdiff_t mixer_nb_bytes
;
292 if ( p_input
->mixer
.begin
== NULL
)
294 p_input
->mixer
.begin
= p_buffer
->p_buffer
;
296 mixer_nb_bytes
= p_input
->mixer
.begin
- p_buffer
->p_buffer
;
298 if ( !((i_buffer
+ p_aout
->p_mixer
->fmt
.i_bytes_per_frame
300 (i_buffer
< p_aout
->p_mixer
->fmt
.i_bytes_per_frame
303 msg_Warn( p_aout
, "mixer start isn't output start (%"PRId64
")",
304 i_buffer
- mixer_nb_bytes
);
306 /* Round to the nearest multiple */
307 i_buffer
/= p_aout
->p_mixer
->fmt
.i_bytes_per_frame
;
308 i_buffer
*= p_aout
->p_mixer
->fmt
.i_bytes_per_frame
;
311 /* Is it really the best way to do it ? */
312 aout_lock_output_fifo( p_aout
);
313 aout_FifoSet( p_aout
, &p_aout
->output
.fifo
, 0 );
314 date_Set( &exact_start_date
, 0 );
315 aout_unlock_output_fifo( p_aout
);
319 p_input
->mixer
.begin
= p_buffer
->p_buffer
+ i_buffer
;
324 if ( i
< p_aout
->i_nb_inputs
|| i_first_input
== p_aout
->i_nb_inputs
)
326 /* Interrupted before the end... We can't run. */
327 aout_unlock_input_fifos( p_aout
);
332 p_output_buffer
= aout_BufferAlloc( &p_aout
->p_mixer
->allocation
,
333 ((uint64_t)p_aout
->output
.i_nb_samples
* 1000000)
334 / p_aout
->output
.output
.i_rate
,
335 /* This is a bit kludgy, but is actually only used
336 * for the S/PDIF dummy mixer : */
337 p_aout
->pp_inputs
[i_first_input
]->mixer
.fifo
.p_first
);
338 if ( p_output_buffer
== NULL
)
340 aout_unlock_input_fifos( p_aout
);
343 /* This is again a bit kludgy - for the S/PDIF mixer. */
344 if ( p_aout
->p_mixer
->allocation
.b_alloc
)
346 p_output_buffer
->i_nb_samples
= p_aout
->output
.i_nb_samples
;
347 p_output_buffer
->i_buffer
= p_aout
->output
.i_nb_samples
348 * p_aout
->p_mixer
->fmt
.i_bytes_per_frame
349 / p_aout
->p_mixer
->fmt
.i_frame_length
;
351 p_output_buffer
->i_pts
= start_date
;
352 p_output_buffer
->i_length
= end_date
- start_date
;
354 p_aout
->p_mixer
->mix( p_aout
->p_mixer
, p_output_buffer
);
356 aout_unlock_input_fifos( p_aout
);
358 aout_OutputPlay( p_aout
, p_output_buffer
);
363 /*****************************************************************************
364 * aout_MixerRun: entry point for the mixer & post-filters processing
365 *****************************************************************************
366 * Please note that you must hold the mixer lock.
367 *****************************************************************************/
368 void aout_MixerRun( aout_instance_t
* p_aout
)
370 while( MixBuffer( p_aout
) != -1 );
373 /*****************************************************************************
374 * aout_MixerMultiplierSet: set p_aout->mixer.f_multiplier
375 *****************************************************************************
376 * Please note that we assume that you own the mixer lock when entering this
377 * function. This function returns -1 on error.
378 *****************************************************************************/
379 int aout_MixerMultiplierSet( aout_instance_t
* p_aout
, float f_multiplier
)
381 float f_old
= p_aout
->mixer_multiplier
;
382 bool b_new_mixer
= false;
384 if ( p_aout
->p_mixer
)
386 aout_MixerDelete( p_aout
);
390 p_aout
->mixer_multiplier
= f_multiplier
;
392 if ( b_new_mixer
&& aout_MixerNew( p_aout
) )
394 p_aout
->mixer_multiplier
= f_old
;
395 aout_MixerNew( p_aout
);
402 /*****************************************************************************
403 * aout_MixerMultiplierGet: get p_aout->mixer.f_multiplier
404 *****************************************************************************
405 * Please note that we assume that you own the mixer lock when entering this
406 * function. This function returns -1 on error.
407 *****************************************************************************/
408 int aout_MixerMultiplierGet( aout_instance_t
* p_aout
, float * pf_multiplier
)
410 *pf_multiplier
= p_aout
->mixer_multiplier
;