Commit b6717257 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

mixer: simplify based on single input per output

parent d8ab9fd6
...@@ -318,6 +318,8 @@ static int aout_Restart( aout_instance_t * p_aout ) ...@@ -318,6 +318,8 @@ static int aout_Restart( aout_instance_t * p_aout )
/* Re-open the output plug-in. */ /* Re-open the output plug-in. */
aout_OutputDelete( p_aout ); aout_OutputDelete( p_aout );
/* FIXME: This function is notoriously dangerous/unsafe.
* By the way, if OutputNew or MixerNew fails, we are totally screwed. */
if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 ) if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 )
{ {
/* Release all locks and report the error. */ /* Release all locks and report the error. */
......
...@@ -93,39 +93,25 @@ void aout_MixerDelete( aout_instance_t * p_aout ) ...@@ -93,39 +93,25 @@ void aout_MixerDelete( aout_instance_t * p_aout )
*****************************************************************************/ *****************************************************************************/
static int MixBuffer( aout_instance_t * p_aout, float volume ) static int MixBuffer( aout_instance_t * p_aout, float volume )
{ {
int i, i_first_input = 0; aout_mixer_t *p_mixer = p_aout->p_mixer;
mtime_t start_date, end_date;
date_t exact_start_date;
if( !p_aout->p_mixer ) assert( p_aout->i_nb_inputs == 1 );
{
/* Free all incoming buffers. */ aout_input_t *p_input = p_aout->pp_inputs[0];
aout_lock_input_fifos( p_aout ); if( p_input->b_paused )
for ( i = 0; i < p_aout->i_nb_inputs; i++ )
{
aout_input_t * p_input = p_aout->pp_inputs[i];
aout_buffer_t * p_buffer = p_input->mixer.fifo.p_first;
if ( p_input->b_error ) continue;
while ( p_buffer != NULL )
{
aout_buffer_t * p_next = p_buffer->p_next;
aout_BufferFree( p_buffer );
p_buffer = p_next;
}
}
aout_unlock_input_fifos( p_aout );
return -1; return -1;
}
aout_fifo_t * p_fifo = &p_input->mixer.fifo;
mtime_t now = mdate();
aout_lock_input_fifos( p_aout ); aout_lock_input_fifos( p_aout );
aout_lock_output_fifo( p_aout ); aout_lock_output_fifo( p_aout );
/* Retrieve the date of the next buffer. */ /* Retrieve the date of the next buffer. */
exact_start_date = p_aout->output.fifo.end_date; date_t exact_start_date = p_aout->output.fifo.end_date;
start_date = date_Get( &exact_start_date ); mtime_t start_date = date_Get( &exact_start_date );
if ( start_date != 0 && start_date < mdate() ) if( start_date != 0 && start_date < now )
{ {
/* The output is _very_ late. This can only happen if the user /* The output is _very_ late. This can only happen if the user
* pauses the stream (or if the decoder is buggy, which cannot * pauses the stream (or if the decoder is buggy, which cannot
...@@ -144,158 +130,94 @@ static int MixBuffer( aout_instance_t * p_aout, float volume ) ...@@ -144,158 +130,94 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
if ( !start_date ) if ( !start_date )
{ {
/* Find the latest start date available. */ /* Find the latest start date available. */
for ( i = 0; i < p_aout->i_nb_inputs; i++ ) aout_buffer_t *p_buffer;
for( ;; )
{ {
aout_input_t * p_input = p_aout->pp_inputs[i];
aout_fifo_t * p_fifo = &p_input->mixer.fifo;
aout_buffer_t * p_buffer;
if ( p_input->b_error || p_input->b_paused )
continue;
p_buffer = p_fifo->p_first; p_buffer = p_fifo->p_first;
while ( p_buffer != NULL && p_buffer->i_pts < mdate() ) if( p_buffer == NULL )
{ goto giveup;
if( p_buffer->i_pts >= now )
break;
msg_Warn( p_aout, "input PTS is out of range (%"PRId64"), " msg_Warn( p_aout, "input PTS is out of range (%"PRId64"), "
"trashing", mdate() - p_buffer->i_pts ); "trashing", now - p_buffer->i_pts );
p_buffer = aout_FifoPop( p_aout, p_fifo ); aout_BufferFree( aout_FifoPop( p_aout, p_fifo ) );
aout_BufferFree( p_buffer );
p_buffer = p_fifo->p_first;
p_input->mixer.begin = NULL; p_input->mixer.begin = NULL;
} }
if ( p_buffer == NULL )
{
break;
}
if ( !start_date || start_date < p_buffer->i_pts )
{
date_Set( &exact_start_date, p_buffer->i_pts ); date_Set( &exact_start_date, p_buffer->i_pts );
start_date = p_buffer->i_pts; start_date = p_buffer->i_pts;
} }
}
if ( i < p_aout->i_nb_inputs )
{
/* Interrupted before the end... We can't run. */
aout_unlock_input_fifos( p_aout );
return -1;
}
}
date_Increment( &exact_start_date, p_aout->output.i_nb_samples ); date_Increment( &exact_start_date, p_aout->output.i_nb_samples );
end_date = date_Get( &exact_start_date ); mtime_t end_date = date_Get( &exact_start_date );
/* Check that start_date and end_date are available for all input /* Check that start_date is available. */
* streams. */ aout_buffer_t *p_buffer = p_fifo->p_first;
for ( i = 0; i < p_aout->i_nb_inputs; i++ )
{
aout_input_t * p_input = p_aout->pp_inputs[i];
aout_fifo_t * p_fifo = &p_input->mixer.fifo;
aout_buffer_t * p_buffer;
mtime_t prev_date; mtime_t prev_date;
bool b_drop_buffers;
p_input->mixer.is_invalid = p_input->b_error || p_input->b_paused; for( ;; )
if ( p_input->mixer.is_invalid )
{ {
if ( i_first_input == i ) i_first_input++; if( p_buffer == NULL )
continue; goto giveup;
}
p_buffer = p_fifo->p_first;
if ( p_buffer == NULL )
{
break;
}
/* Check for the continuity of start_date */ /* Check for the continuity of start_date */
while ( p_buffer != NULL prev_date = p_buffer->i_pts + p_buffer->i_length;
&& p_buffer->i_pts + p_buffer->i_length < start_date - 1 ) if( prev_date >= start_date - 1 )
{ break;
/* We authorize a +-1 because rounding errors get compensated /* We authorize a +-1 because rounding errors get compensated
* regularly. */ * regularly. */
aout_buffer_t * p_next = p_buffer->p_next;
msg_Warn( p_aout, "the mixer got a packet in the past (%"PRId64")", msg_Warn( p_aout, "the mixer got a packet in the past (%"PRId64")",
start_date - (p_buffer->i_pts + p_buffer->i_length) ); start_date - prev_date );
aout_BufferFree( p_buffer ); aout_BufferFree( aout_FifoPop( p_aout, p_fifo ) );
p_fifo->p_first = p_buffer = p_next;
p_input->mixer.begin = NULL; p_input->mixer.begin = NULL;
} p_buffer = p_fifo->p_first;
if ( p_buffer == NULL )
{
p_fifo->pp_last = &p_fifo->p_first;
break;
} }
/* Check that we have enough samples. */ /* Check that we have enough samples. */
for ( ; ; ) while( prev_date < end_date )
{ {
p_buffer = p_fifo->p_first; p_buffer = p_buffer->p_next;
if ( p_buffer == NULL ) break; if( p_buffer == NULL )
if ( p_buffer->i_pts + p_buffer->i_length >= end_date ) break; goto giveup;
/* Check that all buffers are contiguous. */ /* Check that all buffers are contiguous. */
prev_date = p_fifo->p_first->i_pts + p_fifo->p_first->i_length; if( prev_date != p_buffer->i_pts )
p_buffer = p_buffer->p_next;
b_drop_buffers = 0;
for ( ; p_buffer != NULL; p_buffer = p_buffer->p_next )
{
if ( prev_date != p_buffer->i_pts )
{ {
msg_Warn( p_aout, msg_Warn( p_aout,
"buffer hole, dropping packets (%"PRId64")", "buffer hole, dropping packets (%"PRId64")",
p_buffer->i_pts - prev_date ); p_buffer->i_pts - prev_date );
b_drop_buffers = 1;
break; aout_buffer_t *p_deleted;
while( (p_deleted = p_fifo->p_first) != p_buffer )
aout_BufferFree( aout_FifoPop( p_aout, p_fifo ) );
} }
if ( p_buffer->i_pts + p_buffer->i_length >= end_date ) break;
prev_date = p_buffer->i_pts + p_buffer->i_length; prev_date = p_buffer->i_pts + p_buffer->i_length;
} }
if ( b_drop_buffers )
{
aout_buffer_t * p_deleted = p_fifo->p_first;
while ( p_deleted != NULL && p_deleted != p_buffer )
{
aout_buffer_t * p_next = p_deleted->p_next;
aout_BufferFree( p_deleted );
p_deleted = p_next;
}
p_fifo->p_first = p_deleted; /* == p_buffer */
}
else break;
}
if ( p_buffer == NULL ) break;
p_buffer = p_fifo->p_first; p_buffer = p_fifo->p_first;
if ( !AOUT_FMT_NON_LINEAR( &p_aout->p_mixer->fmt ) ) if( !AOUT_FMT_NON_LINEAR( &p_mixer->fmt ) )
{ {
/* Additionally check that p_first_byte_to_mix is well /* Additionally check that p_first_byte_to_mix is well located. */
* located. */
mtime_t i_buffer = (start_date - p_buffer->i_pts) mtime_t i_buffer = (start_date - p_buffer->i_pts)
* p_aout->p_mixer->fmt.i_bytes_per_frame * p_mixer->fmt.i_bytes_per_frame
* p_aout->p_mixer->fmt.i_rate * p_mixer->fmt.i_rate
/ p_aout->p_mixer->fmt.i_frame_length / p_mixer->fmt.i_frame_length
/ 1000000; / CLOCK_FREQ;
ptrdiff_t mixer_nb_bytes; if( p_input->mixer.begin == NULL )
if ( p_input->mixer.begin == NULL )
{
p_input->mixer.begin = p_buffer->p_buffer; p_input->mixer.begin = p_buffer->p_buffer;
}
mixer_nb_bytes = p_input->mixer.begin - p_buffer->p_buffer;
if ( !((i_buffer + p_aout->p_mixer->fmt.i_bytes_per_frame ptrdiff_t bytes = p_input->mixer.begin - p_buffer->p_buffer;
> mixer_nb_bytes) && if( !((i_buffer + p_mixer->fmt.i_bytes_per_frame > bytes)
(i_buffer < p_aout->p_mixer->fmt.i_bytes_per_frame && (i_buffer < p_mixer->fmt.i_bytes_per_frame + bytes)) )
+ mixer_nb_bytes)) )
{ {
msg_Warn( p_aout, "mixer start isn't output start (%"PRId64")", msg_Warn( p_aout, "mixer start is not output start (%"PRId64")",
i_buffer - mixer_nb_bytes ); i_buffer - bytes );
/* Round to the nearest multiple */ /* Round to the nearest multiple */
i_buffer /= p_aout->p_mixer->fmt.i_bytes_per_frame; i_buffer /= p_mixer->fmt.i_bytes_per_frame;
i_buffer *= p_aout->p_mixer->fmt.i_bytes_per_frame; i_buffer *= p_mixer->fmt.i_bytes_per_frame;
if( i_buffer < 0 ) if( i_buffer < 0 )
{ {
/* Is it really the best way to do it ? */ /* Is it really the best way to do it ? */
...@@ -303,34 +225,29 @@ static int MixBuffer( aout_instance_t * p_aout, float volume ) ...@@ -303,34 +225,29 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
aout_FifoSet( p_aout, &p_aout->output.fifo, 0 ); aout_FifoSet( p_aout, &p_aout->output.fifo, 0 );
date_Set( &exact_start_date, 0 ); date_Set( &exact_start_date, 0 );
aout_unlock_output_fifo( p_aout ); aout_unlock_output_fifo( p_aout );
break; goto giveup;
} }
p_input->mixer.begin = p_buffer->p_buffer + i_buffer; p_input->mixer.begin = p_buffer->p_buffer + i_buffer;
} }
} }
}
if ( i < p_aout->i_nb_inputs || i_first_input == p_aout->i_nb_inputs )
{
/* Interrupted before the end... We can't run. */
aout_unlock_input_fifos( p_aout );
return -1;
}
/* Run the mixer. */ /* Run the mixer. */
aout_buffer_t * p_outbuf; p_buffer = p_mixer->mix( p_aout->p_mixer, p_aout->output.i_nb_samples,
p_outbuf = p_aout->p_mixer->mix( p_aout->p_mixer, volume );
p_aout->output.i_nb_samples, volume );
aout_unlock_input_fifos( p_aout ); aout_unlock_input_fifos( p_aout );
if( unlikely(p_outbuf == NULL) ) if( unlikely(p_buffer == NULL) )
return -1; return -1;
p_outbuf->i_pts = start_date; p_buffer->i_pts = start_date;
p_outbuf->i_length = end_date - start_date; p_buffer->i_length = end_date - start_date;
aout_OutputPlay( p_aout, p_outbuf ); aout_OutputPlay( p_aout, p_buffer );
return 0; return 0;
giveup:
/* Interrupted before the end... We can't run. */
aout_unlock_input_fifos( p_aout );
return -1;
} }
/***************************************************************************** /*****************************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment