00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031
00032 #ifdef HAVE_ALLOCA_H
00033 # include <alloca.h>
00034 #endif
00035
00036 #include "audio_output.h"
00037 #include "aout_internal.h"
00038
00039
00040
00041
00042
00043
00044 int aout_MixerNew( aout_instance_t * p_aout )
00045 {
00046 p_aout->mixer.p_module = module_Need( p_aout, "audio mixer", NULL, 0 );
00047 if ( p_aout->mixer.p_module == NULL )
00048 {
00049 msg_Err( p_aout, "no suitable aout mixer" );
00050 return -1;
00051 }
00052 p_aout->mixer.b_error = 0;
00053 return 0;
00054 }
00055
00056
00057
00058
00059
00060
00061 void aout_MixerDelete( aout_instance_t * p_aout )
00062 {
00063 if ( p_aout->mixer.b_error ) return;
00064 module_Unneed( p_aout, p_aout->mixer.p_module );
00065 p_aout->mixer.b_error = 1;
00066 }
00067
00068
00069
00070
00071
00072
00073 static int MixBuffer( aout_instance_t * p_aout )
00074 {
00075 int i, i_first_input = 0;
00076 aout_buffer_t * p_output_buffer;
00077 mtime_t start_date, end_date;
00078 audio_date_t exact_start_date;
00079
00080 if ( p_aout->mixer.b_error )
00081 {
00082
00083 vlc_mutex_lock( &p_aout->input_fifos_lock );
00084 for ( i = 0; i < p_aout->i_nb_inputs; i++ )
00085 {
00086 aout_input_t * p_input = p_aout->pp_inputs[i];
00087 aout_buffer_t * p_buffer = p_input->fifo.p_first;
00088 if ( p_input->b_error ) continue;
00089 while ( p_buffer != NULL )
00090 {
00091 aout_buffer_t * p_next = p_buffer->p_next;
00092 aout_BufferFree( p_buffer );
00093 p_buffer = p_next;
00094 }
00095 }
00096 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00097 return -1;
00098 }
00099
00100
00101 vlc_mutex_lock( &p_aout->output_fifo_lock );
00102 vlc_mutex_lock( &p_aout->input_fifos_lock );
00103
00104
00105 memcpy( &exact_start_date, &p_aout->output.fifo.end_date,
00106 sizeof(audio_date_t) );
00107 start_date = aout_DateGet( &exact_start_date );
00108
00109 if ( start_date != 0 && start_date < mdate() )
00110 {
00111
00112
00113
00114 msg_Warn( p_aout, "output PTS is out of range ("I64Fd"), clearing out",
00115 mdate() - start_date );
00116 aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
00117 aout_DateSet( &exact_start_date, 0 );
00118 start_date = 0;
00119 }
00120
00121 vlc_mutex_unlock( &p_aout->output_fifo_lock );
00122
00123
00124
00125 if ( !start_date )
00126 {
00127
00128 for ( i = 0; i < p_aout->i_nb_inputs; i++ )
00129 {
00130 aout_input_t * p_input = p_aout->pp_inputs[i];
00131 aout_fifo_t * p_fifo = &p_input->fifo;
00132 aout_buffer_t * p_buffer;
00133
00134 if ( p_input->b_error ) continue;
00135
00136 p_buffer = p_fifo->p_first;
00137 while ( p_buffer != NULL && p_buffer->start_date < mdate() )
00138 {
00139 msg_Warn( p_aout, "input PTS is out of range ("I64Fd"), "
00140 "trashing", mdate() - p_buffer->start_date );
00141 p_buffer = aout_FifoPop( p_aout, p_fifo );
00142 aout_BufferFree( p_buffer );
00143 p_buffer = p_fifo->p_first;
00144 p_input->p_first_byte_to_mix = NULL;
00145 }
00146
00147 if ( p_buffer == NULL )
00148 {
00149 break;
00150 }
00151
00152 if ( !start_date || start_date < p_buffer->start_date )
00153 {
00154 aout_DateSet( &exact_start_date, p_buffer->start_date );
00155 start_date = p_buffer->start_date;
00156 }
00157 }
00158
00159 if ( i < p_aout->i_nb_inputs )
00160 {
00161
00162 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00163 return -1;
00164 }
00165 }
00166 aout_DateIncrement( &exact_start_date, p_aout->output.i_nb_samples );
00167 end_date = aout_DateGet( &exact_start_date );
00168
00169
00170
00171 for ( i = 0; i < p_aout->i_nb_inputs; i++ )
00172 {
00173 aout_input_t * p_input = p_aout->pp_inputs[i];
00174 aout_fifo_t * p_fifo = &p_input->fifo;
00175 aout_buffer_t * p_buffer;
00176 mtime_t prev_date;
00177 vlc_bool_t b_drop_buffers;
00178
00179 if ( p_input->b_error )
00180 {
00181 if ( i_first_input == i ) i_first_input++;
00182 continue;
00183 }
00184
00185 p_buffer = p_fifo->p_first;
00186 if ( p_buffer == NULL )
00187 {
00188 break;
00189 }
00190
00191
00192 while ( p_buffer != NULL && p_buffer->end_date < start_date - 1 )
00193 {
00194
00195
00196 aout_buffer_t * p_next = p_buffer->p_next;
00197 msg_Warn( p_aout, "the mixer got a packet in the past ("I64Fd")",
00198 start_date - p_buffer->end_date );
00199 aout_BufferFree( p_buffer );
00200 p_fifo->p_first = p_buffer = p_next;
00201 p_input->p_first_byte_to_mix = NULL;
00202 }
00203 if ( p_buffer == NULL )
00204 {
00205 p_fifo->pp_last = &p_fifo->p_first;
00206 break;
00207 }
00208
00209
00210 for ( ; ; )
00211 {
00212 p_buffer = p_fifo->p_first;
00213 if ( p_buffer == NULL ) break;
00214 if ( p_buffer->end_date >= end_date ) break;
00215
00216
00217 prev_date = p_fifo->p_first->end_date;
00218 p_buffer = p_buffer->p_next;
00219 b_drop_buffers = 0;
00220 for ( ; p_buffer != NULL; p_buffer = p_buffer->p_next )
00221 {
00222 if ( prev_date != p_buffer->start_date )
00223 {
00224 msg_Warn( p_aout,
00225 "buffer hole, dropping packets ("I64Fd")",
00226 p_buffer->start_date - prev_date );
00227 b_drop_buffers = 1;
00228 break;
00229 }
00230 if ( p_buffer->end_date >= end_date ) break;
00231 prev_date = p_buffer->end_date;
00232 }
00233 if ( b_drop_buffers )
00234 {
00235 aout_buffer_t * p_deleted = p_fifo->p_first;
00236 while ( p_deleted != NULL && p_deleted != p_buffer )
00237 {
00238 aout_buffer_t * p_next = p_deleted->p_next;
00239 aout_BufferFree( p_deleted );
00240 p_deleted = p_next;
00241 }
00242 p_fifo->p_first = p_deleted;
00243 }
00244 else break;
00245 }
00246 if ( p_buffer == NULL ) break;
00247
00248 p_buffer = p_fifo->p_first;
00249 if ( !AOUT_FMT_NON_LINEAR( &p_aout->mixer.mixer ) )
00250 {
00251
00252
00253 mtime_t i_nb_bytes = (start_date - p_buffer->start_date)
00254 * p_aout->mixer.mixer.i_bytes_per_frame
00255 * p_aout->mixer.mixer.i_rate
00256 / p_aout->mixer.mixer.i_frame_length
00257 / 1000000;
00258 ptrdiff_t mixer_nb_bytes;
00259
00260 if ( p_input->p_first_byte_to_mix == NULL )
00261 {
00262 p_input->p_first_byte_to_mix = p_buffer->p_buffer;
00263 }
00264 mixer_nb_bytes = p_input->p_first_byte_to_mix - p_buffer->p_buffer;
00265
00266 if ( !((i_nb_bytes + p_aout->mixer.mixer.i_bytes_per_frame
00267 > mixer_nb_bytes) &&
00268 (i_nb_bytes < p_aout->mixer.mixer.i_bytes_per_frame
00269 + mixer_nb_bytes)) )
00270 {
00271 msg_Warn( p_aout, "mixer start isn't output start ("I64Fd")",
00272 i_nb_bytes - mixer_nb_bytes );
00273
00274
00275 i_nb_bytes /= p_aout->mixer.mixer.i_bytes_per_frame;
00276 i_nb_bytes *= p_aout->mixer.mixer.i_bytes_per_frame;
00277 if( i_nb_bytes < 0 )
00278 {
00279
00280 aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
00281 aout_DateSet( &exact_start_date, 0 );
00282 break;
00283 }
00284
00285 p_input->p_first_byte_to_mix = p_buffer->p_buffer + i_nb_bytes;
00286 }
00287 }
00288 }
00289
00290 if ( i < p_aout->i_nb_inputs || i_first_input == p_aout->i_nb_inputs )
00291 {
00292
00293 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00294 return -1;
00295 }
00296
00297
00298 aout_BufferAlloc( &p_aout->mixer.output_alloc,
00299 ((uint64_t)p_aout->output.i_nb_samples * 1000000)
00300 / p_aout->output.output.i_rate,
00301
00302
00303 p_aout->pp_inputs[i_first_input]->fifo.p_first,
00304 p_output_buffer );
00305 if ( p_output_buffer == NULL )
00306 {
00307 msg_Err( p_aout, "out of memory" );
00308 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00309 return -1;
00310 }
00311
00312 if ( p_aout->mixer.output_alloc.i_alloc_type != AOUT_ALLOC_NONE )
00313 {
00314 p_output_buffer->i_nb_samples = p_aout->output.i_nb_samples;
00315 p_output_buffer->i_nb_bytes = p_aout->output.i_nb_samples
00316 * p_aout->mixer.mixer.i_bytes_per_frame
00317 / p_aout->mixer.mixer.i_frame_length;
00318 }
00319 p_output_buffer->start_date = start_date;
00320 p_output_buffer->end_date = end_date;
00321
00322 p_aout->mixer.pf_do_work( p_aout, p_output_buffer );
00323
00324 vlc_mutex_unlock( &p_aout->input_fifos_lock );
00325
00326 aout_OutputPlay( p_aout, p_output_buffer );
00327
00328 return 0;
00329 }
00330
00331
00332
00333
00334
00335
00336 void aout_MixerRun( aout_instance_t * p_aout )
00337 {
00338 while( MixBuffer( p_aout ) != -1 );
00339 }
00340
00341
00342
00343
00344
00345
00346
00347 int aout_MixerMultiplierSet( aout_instance_t * p_aout, float f_multiplier )
00348 {
00349 float f_old = p_aout->mixer.f_multiplier;
00350 vlc_bool_t b_new_mixer = 0;
00351
00352 if ( !p_aout->mixer.b_error )
00353 {
00354 aout_MixerDelete( p_aout );
00355 b_new_mixer = 1;
00356 }
00357
00358 p_aout->mixer.f_multiplier = f_multiplier;
00359
00360 if ( b_new_mixer && aout_MixerNew( p_aout ) )
00361 {
00362 p_aout->mixer.f_multiplier = f_old;
00363 aout_MixerNew( p_aout );
00364 return -1;
00365 }
00366
00367 return 0;
00368 }
00369
00370
00371
00372
00373
00374
00375
00376 int aout_MixerMultiplierGet( aout_instance_t * p_aout, float * pf_multiplier )
00377 {
00378 *pf_multiplier = p_aout->mixer.f_multiplier;
00379 return 0;
00380 }
00381