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

Merge all audio output locks except volume control

With only one input per output, the lock is only useful:
 - to restart the audio instance (needed 3 out of 4 locks anyway),
 - to propagate volume change to the mixer or output plugin,
 - to access the FIFO from the output plugin thread (if applicable).

So 4 fine-grained was over-engineering. Most importantly, the locking
scheme was overly complicated and generally misunderstood/misused. Also
to avoid lock inversion, some unlocking/relocking sequences were
introduced; they broke atomicity.

We could certainly reduce the scope of the remaining lock. Since we
have one only input per output, most of the code is only ever run from
the decoder thread. Thus reentrancy is not anymore needed in some
places. But first aout_Restart() needs to be fixed and simplified.
parent 1d7fcd8c
......@@ -178,22 +178,9 @@ struct aout_instance_t
{
VLC_COMMON_MEMBERS
/* Locks : please note that if you need several of these locks, it is
* mandatory (to avoid deadlocks) to take them in the following order :
* mixer_lock, p_input->lock, output_fifo_lock, input_fifos_lock.
* --Meuuh */
/* When input_fifos_lock is taken, none of the p_input->fifo structures
* can be read or modified by a third-party thread. */
vlc_mutex_t input_fifos_lock;
/* When mixer_lock is taken, all decoder threads willing to mix a
* buffer must wait until it is released. The output pipeline cannot
* be modified. No input stream can be added or removed. */
vlc_mutex_t mixer_lock;
/* When output_fifo_lock is taken, the p_aout->output.fifo structure
* cannot be read or written by a third-party thread. */
vlc_mutex_t output_fifo_lock;
/* volume_vars_lock is taken */
vlc_mutex_t volume_vars_lock;
/* Lock for volume variables (FIXME: should be in input manager) */
vlc_mutex_t volume_lock;
vlc_mutex_t lock;
/* Input streams & pre-filters */
aout_input_t * p_input;
......
......@@ -97,7 +97,7 @@ struct aout_input_t
/* From input.c : */
int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input, const aout_request_vout_t * );
int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input );
int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
void aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
aout_buffer_t * p_buffer, int i_input_rate );
void aout_InputCheckAndRestart( aout_instance_t * p_aout, aout_input_t * p_input );
......@@ -138,7 +138,7 @@ bool aout_ChangeFilterString( vlc_object_t *, aout_instance_t *, const char *psz
/* From dec.c */
aout_input_t *aout_DecNew( aout_instance_t *, audio_sample_format_t *,
const audio_replay_gain_t *, const aout_request_vout_t * );
int aout_DecDelete ( aout_instance_t *, aout_input_t * );
void aout_DecDelete ( aout_instance_t *, aout_input_t * );
aout_buffer_t * aout_DecNewBuffer( aout_input_t *, size_t );
void aout_DecDeleteBuffer( aout_instance_t *, aout_input_t *, aout_buffer_t * );
int aout_DecPlay( aout_instance_t *, aout_input_t *, aout_buffer_t *, int i_input_rate );
......@@ -157,81 +157,40 @@ bool aout_DecIsEmpty( aout_instance_t * p_aout, aout_input_t * p_input );
#ifdef AOUT_DEBUG
enum
{
MIXER_LOCK=1,
INPUT_LOCK=2,
INPUT_FIFO_LOCK=4,
OUTPUT_FIFO_LOCK=8,
VOLUME_VARS_LOCK=16
OUTPUT_LOCK=1,
VOLUME_LOCK=2,
};
void aout_lock (unsigned);
void aout_unlock (unsigned);
void aout_lock_check (unsigned);
void aout_unlock_check (unsigned);
#else
# define aout_lock( i ) (void)0
# define aout_unlock( i ) (void)0
# define aout_lock_check( i ) (void)0
# define aout_unlock_check( i ) (void)0
#endif
static inline void aout_lock_mixer( aout_instance_t *p_aout )
static inline void aout_lock( aout_instance_t *p_aout )
{
aout_lock( MIXER_LOCK );
vlc_mutex_lock( &p_aout->mixer_lock );
aout_lock_check( OUTPUT_LOCK );
vlc_mutex_lock( &p_aout->lock );
}
static inline void aout_unlock_mixer( aout_instance_t *p_aout )
static inline void aout_unlock( aout_instance_t *p_aout )
{
aout_unlock( MIXER_LOCK );
vlc_mutex_unlock( &p_aout->mixer_lock );
}
static inline void aout_lock_input_fifos( aout_instance_t *p_aout )
{
aout_lock( INPUT_FIFO_LOCK );
vlc_mutex_lock( &p_aout->input_fifos_lock );
}
static inline void aout_unlock_input_fifos( aout_instance_t *p_aout )
{
aout_unlock( INPUT_FIFO_LOCK );
vlc_mutex_unlock( &p_aout->input_fifos_lock );
}
static inline void aout_lock_output_fifo( aout_instance_t *p_aout )
{
aout_lock( OUTPUT_FIFO_LOCK );
vlc_mutex_lock( &p_aout->output_fifo_lock );
}
static inline void aout_unlock_output_fifo( aout_instance_t *p_aout )
{
aout_unlock( OUTPUT_FIFO_LOCK );
vlc_mutex_unlock( &p_aout->output_fifo_lock );
}
static inline void aout_lock_input( aout_instance_t *p_aout, aout_input_t * p_input )
{
(void)p_aout;
aout_lock( INPUT_LOCK );
vlc_mutex_lock( &p_input->lock );
}
static inline void aout_unlock_input( aout_instance_t *p_aout, aout_input_t * p_input )
{
(void)p_aout;
aout_unlock( INPUT_LOCK );
vlc_mutex_unlock( &p_input->lock );
aout_unlock_check( OUTPUT_LOCK );
vlc_mutex_unlock( &p_aout->lock );
}
static inline void aout_lock_volume( aout_instance_t *p_aout )
{
aout_lock( VOLUME_VARS_LOCK );
vlc_mutex_lock( &p_aout->volume_vars_lock );
aout_lock_check( VOLUME_LOCK );
vlc_mutex_lock( &p_aout->volume_lock );
}
static inline void aout_unlock_volume( aout_instance_t *p_aout )
{
aout_unlock( VOLUME_VARS_LOCK );
vlc_mutex_unlock( &p_aout->volume_vars_lock );
aout_unlock_check( VOLUME_LOCK );
vlc_mutex_unlock( &p_aout->volume_lock );
}
/* Helpers */
......@@ -241,10 +200,10 @@ static inline void aout_unlock_volume( aout_instance_t *p_aout )
* possible to take configuration changes into account */
static inline void AoutInputsMarkToRestart( aout_instance_t *p_aout )
{
aout_lock_mixer( p_aout );
aout_lock( p_aout );
if( p_aout->p_input != NULL )
p_aout->p_input->b_restart = true;
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
}
#endif /* !LIBVLC_AOUT_INTERNAL_H */
......@@ -59,10 +59,8 @@ aout_instance_t * __aout_New( vlc_object_t * p_parent )
}
/* Initialize members. */
vlc_mutex_init( &p_aout->input_fifos_lock );
vlc_mutex_init( &p_aout->mixer_lock );
vlc_mutex_init( &p_aout->volume_vars_lock );
vlc_mutex_init( &p_aout->output_fifo_lock );
vlc_mutex_init( &p_aout->volume_lock );
vlc_mutex_init( &p_aout->lock );
p_aout->p_input = NULL;
p_aout->mixer_multiplier = 1.0;
p_aout->p_mixer = NULL;
......@@ -82,45 +80,24 @@ aout_instance_t * __aout_New( vlc_object_t * p_parent )
static void aout_Destructor( vlc_object_t * p_this )
{
aout_instance_t * p_aout = (aout_instance_t *)p_this;
vlc_mutex_destroy( &p_aout->input_fifos_lock );
vlc_mutex_destroy( &p_aout->mixer_lock );
vlc_mutex_destroy( &p_aout->volume_vars_lock );
vlc_mutex_destroy( &p_aout->output_fifo_lock );
vlc_mutex_destroy( &p_aout->volume_lock );
vlc_mutex_destroy( &p_aout->lock );
}
/* Lock ordering rules:
*
* Vars Mixer Input IFIFO OFIFO (< Inner lock)
* Vars No! Yes Yes Yes Yes
* Mixer No! No! Yes Yes Yes
* Input No! No! No! Yes Yes
* In FIFOs No! No! No! No! Yes
* Out FIFOs No! No! No! No! No!
* (^ Outer lock)
*/
#ifdef AOUT_DEBUG
/* Lock debugging */
static __thread unsigned aout_locks = 0;
void aout_lock (unsigned i)
void aout_lock_check (unsigned i)
{
unsigned allowed;
switch (i)
{
case VOLUME_VARS_LOCK:
case VOLUME_LOCK:
allowed = 0;
break;
case MIXER_LOCK:
allowed = VOLUME_VARS_LOCK;
break;
case INPUT_LOCK:
allowed = VOLUME_VARS_LOCK|MIXER_LOCK;
break;
case INPUT_FIFO_LOCK:
allowed = VOLUME_VARS_LOCK|MIXER_LOCK|INPUT_LOCK;
break;
case OUTPUT_FIFO_LOCK:
allowed = VOLUME_VARS_LOCK|MIXER_LOCK|INPUT_LOCK|INPUT_FIFO_LOCK;
case OUTPUT_LOCK:
allowed = VOLUME_LOCK;
break;
default:
abort ();
......@@ -136,7 +113,7 @@ void aout_lock (unsigned i)
aout_locks |= i;
}
void aout_unlock (unsigned i)
void aout_unlock_check (unsigned i)
{
assert (aout_locks & i);
aout_locks &= ~i;
......
......@@ -81,7 +81,6 @@ aout_input_t *aout_DecNew( aout_instance_t *p_aout,
if( !p_input )
return NULL;
vlc_mutex_init( &p_input->lock );
p_input->b_error = true;
p_input->b_paused = false;
p_input->i_pause_date = 0;
......@@ -95,8 +94,7 @@ aout_input_t *aout_DecNew( aout_instance_t *p_aout,
/* We can only be called by the decoder, so no need to lock
* p_input->lock. */
aout_lock_mixer( p_aout );
aout_lock_input_fifos( p_aout );
aout_lock( p_aout );
assert( p_aout->p_input == NULL );
p_aout->p_input = p_input;
......@@ -119,28 +117,18 @@ aout_input_t *aout_DecNew( aout_instance_t *p_aout,
aout_InputNew( p_aout, p_input, p_request_vout );
out:
aout_unlock_input_fifos( p_aout );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
return p_input;
}
/*****************************************************************************
* aout_DecDelete : delete a decoder
*****************************************************************************/
int aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input )
void aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input )
{
/* This function can only be called by the decoder itself, so no need
* to lock p_input->lock. */
aout_lock_mixer( p_aout );
if( p_input != p_aout->p_input )
{
msg_Err( p_aout, "cannot find an input to delete" );
aout_unlock_mixer( p_aout );
return -1;
}
aout_lock( p_aout );
/* Remove the input. */
assert( p_input == p_aout->p_input ); /* buggy decoder? */
p_aout->p_input = NULL;
aout_InputDelete( p_aout, p_input );
......@@ -149,11 +137,8 @@ int aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input )
var_Destroy( p_aout, "audio-device" );
var_Destroy( p_aout, "audio-channels" );
aout_unlock_mixer( p_aout );
vlc_mutex_destroy( &p_input->lock );
aout_unlock( p_aout );
free( p_input );
return 0;
}
......@@ -167,23 +152,9 @@ int aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input )
aout_buffer_t * aout_DecNewBuffer( aout_input_t * p_input,
size_t i_nb_samples )
{
block_t *block;
size_t length;
aout_lock_input( NULL, p_input );
if ( p_input->b_error )
{
aout_unlock_input( NULL, p_input );
return NULL;
}
length = i_nb_samples * p_input->input.i_bytes_per_frame
size_t length = i_nb_samples * p_input->input.i_bytes_per_frame
/ p_input->input.i_frame_length;
block = block_Alloc( length );
aout_unlock_input( NULL, p_input );
block_t *block = block_Alloc( length );
if( likely(block != NULL) )
{
block->i_nb_samples = i_nb_samples;
......@@ -216,50 +187,40 @@ int aout_DecPlay( aout_instance_t * p_aout, aout_input_t * p_input,
p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
/ p_input->input.i_rate;
aout_lock_mixer( p_aout );
aout_lock_input( p_aout, p_input );
aout_lock( p_aout );
if( p_input->b_error )
{
aout_unlock_input( p_aout, p_input );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
aout_BufferFree( p_buffer );
return -1;
}
aout_InputCheckAndRestart( p_aout, p_input );
aout_unlock_mixer( p_aout );
int i_ret = aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
aout_unlock_input( p_aout, p_input );
if( i_ret == -1 )
return -1;
aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
/* Run the mixer if it is able to run. */
aout_lock_mixer( p_aout );
aout_MixerRun( p_aout, p_aout->mixer_multiplier );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
return 0;
}
int aout_DecGetResetLost( aout_instance_t *p_aout, aout_input_t *p_input )
{
aout_lock_input( p_aout, p_input );
int i_value = p_input->i_buffer_lost;
int val;
aout_lock( p_aout );
val = p_input->i_buffer_lost;
p_input->i_buffer_lost = 0;
aout_unlock_input( p_aout, p_input );
aout_unlock( p_aout );
return i_value;
return val;
}
void aout_DecChangePause( aout_instance_t *p_aout, aout_input_t *p_input, bool b_paused, mtime_t i_date )
{
mtime_t i_duration = 0;
aout_lock_input( p_aout, p_input );
aout_lock( p_aout );
assert( p_aout->p_input == p_input );
assert( !p_input->b_paused || !b_paused );
if( p_input->b_paused )
{
......@@ -267,33 +228,31 @@ void aout_DecChangePause( aout_instance_t *p_aout, aout_input_t *p_input, bool b
}
p_input->b_paused = b_paused;
p_input->i_pause_date = i_date;
aout_unlock_input( p_aout, p_input );
if( i_duration != 0 )
{
aout_lock_mixer( p_aout );
for( aout_buffer_t *p = p_input->mixer.fifo.p_first; p != NULL; p = p->p_next )
{
p->i_pts += i_duration;
}
aout_unlock_mixer( p_aout );
}
aout_OutputPause( p_aout, b_paused, i_date );
aout_unlock( p_aout );
}
void aout_DecFlush( aout_instance_t *p_aout, aout_input_t *p_input )
{
aout_lock_input_fifos( p_aout );
aout_lock( p_aout );
aout_FifoSet( &p_input->mixer.fifo, 0 );
aout_unlock_input_fifos( p_aout );
aout_unlock( p_aout );
}
bool aout_DecIsEmpty( aout_instance_t * p_aout, aout_input_t * p_input )
{
mtime_t end_date;
aout_lock_input_fifos( p_aout );
aout_lock( p_aout );
end_date = aout_FifoNextStart( &p_input->mixer.fifo );
aout_unlock_input_fifos( p_aout );
aout_unlock( p_aout );
return end_date <= mdate();
}
......@@ -48,8 +48,7 @@
#include "aout_internal.h"
#define AOUT_ASSERT_MIXER_LOCKED vlc_assert_locked( &p_aout->mixer_lock )
#define AOUT_ASSERT_INPUT_LOCKED vlc_assert_locked( &p_input->lock )
#define AOUT_ASSERT_LOCKED vlc_assert_locked( &p_aout->lock )
static void inputFailure( aout_instance_t *, aout_input_t *, const char * );
static void inputDrop( aout_input_t *, aout_buffer_t * );
......@@ -431,7 +430,7 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input, const aout_
*****************************************************************************/
int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
{
AOUT_ASSERT_MIXER_LOCKED;
AOUT_ASSERT_LOCKED;
if ( p_input->b_error )
return 0;
......@@ -460,14 +459,11 @@ int aout_InputDelete( aout_instance_t * p_aout, aout_input_t * p_input )
*****************************************************************************/
void aout_InputCheckAndRestart( aout_instance_t * p_aout, aout_input_t * p_input )
{
AOUT_ASSERT_MIXER_LOCKED;
AOUT_ASSERT_INPUT_LOCKED;
AOUT_ASSERT_LOCKED;
if( !p_input->b_restart )
return;
aout_lock_input_fifos( p_aout );
/* A little trick to avoid loosing our input fifo and properties */
aout_fifo_t fifo = p_input->mixer.fifo;
......@@ -484,8 +480,6 @@ void aout_InputCheckAndRestart( aout_instance_t * p_aout, aout_input_t * p_input
p_input->i_pause_date = i_pause_date;
p_input->b_restart = false;
aout_unlock_input_fifos( p_aout );
}
/*****************************************************************************
* aout_InputPlay : play a buffer
......@@ -494,16 +488,16 @@ void aout_InputCheckAndRestart( aout_instance_t * p_aout, aout_input_t * p_input
*****************************************************************************/
/* XXX Do not activate it !! */
//#define AOUT_PROCESS_BEFORE_CHEKS
int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
void aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
aout_buffer_t * p_buffer, int i_input_rate )
{
mtime_t start_date;
AOUT_ASSERT_INPUT_LOCKED;
AOUT_ASSERT_LOCKED;
if( i_input_rate != INPUT_RATE_DEFAULT && p_input->p_playback_rate_filter == NULL )
{
inputDrop( p_input, p_buffer );
return 0;
return;
}
#ifdef AOUT_PROCESS_BEFORE_CHEKS
......@@ -511,7 +505,7 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
aout_FiltersPlay( p_aout, p_input->pp_filters, p_input->i_nb_filters,
&p_buffer );
if( !p_buffer )
return 0;
return;
/* Actually run the resampler now. */
if ( p_input->i_nb_resamplers > 0 )
......@@ -523,11 +517,11 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
}
if( !p_buffer )
return 0;
return;
if( p_buffer->i_nb_samples <= 0 )
{
block_Release( p_buffer );
return 0;
return;
}
#endif
......@@ -547,7 +541,6 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
/* We don't care if someone changes the start date behind our back after
* this. We'll deal with that when pushing the buffer, and compensate
* with the next incoming buffer. */
aout_lock_input_fifos( p_aout );
start_date = aout_FifoNextStart( &p_input->mixer.fifo );
if ( start_date != 0 && start_date < now )
......@@ -573,7 +566,7 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
now - p_buffer->i_pts );
inputDrop( p_input, p_buffer );
inputResamplingStop( p_input );
goto out;
return;
}
/* If the audio drift is too big then it's not worth trying to resample
......@@ -602,14 +595,14 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
msg_Warn( p_aout, "buffer way too late (%"PRId64"), dropping buffer",
drift );
inputDrop( p_input, p_buffer );
goto out;
return;
}
#ifndef AOUT_PROCESS_BEFORE_CHEKS
/* Run pre-filters. */
aout_FiltersPlay( p_input->pp_filters, p_input->i_nb_filters, &p_buffer );
if( !p_buffer )
goto out;
return;
#endif
/* Run the resampler if needed.
......@@ -691,20 +684,17 @@ int aout_InputPlay( aout_instance_t * p_aout, aout_input_t * p_input,
}
if( !p_buffer )
goto out;
return;
if( p_buffer->i_nb_samples <= 0 )
{
block_Release( p_buffer );
goto out;
return;
}
#endif
/* Adding the start date will be managed by aout_FifoPush(). */
p_buffer->i_pts = start_date;
aout_FifoPush( &p_input->mixer.fifo, p_buffer );
out:
aout_unlock_input_fifos( p_aout );
return 0;
}
/*****************************************************************************
......@@ -870,10 +860,10 @@ static int ReplayGainCallback( vlc_object_t *p_this, char const *psz_cmd,
VLC_UNUSED(newval); VLC_UNUSED(p_data);
aout_instance_t *p_aout = (aout_instance_t *)p_this;
aout_lock_mixer( p_aout );
aout_lock( p_aout );
if( p_aout->p_input != NULL )
ReplayGainSelect( p_aout, p_aout->p_input );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
return VLC_SUCCESS;
}
......
......@@ -85,12 +85,11 @@ static int commitVolume (vlc_object_t *obj, aout_instance_t *aout,
if (aout != NULL)
{
aout_lock_mixer (aout);
aout_lock_input_fifos (aout);
aout_lock (aout);
#warning FIXME: wrong test. Need to check that aout_output is ready.
if (aout->p_mixer != NULL)
ret = aout->output.pf_volume_set (aout, volume, mute);
aout_unlock_input_fifos (aout);
aout_unlock_mixer (aout);
aout_unlock (aout);
if (ret == 0)
var_TriggerCallback (aout, "intf-change");
......@@ -291,58 +290,46 @@ void aout_VolumeNoneInit( aout_instance_t * p_aout )
*****************************************************************************/
static int aout_Restart( aout_instance_t * p_aout )
{
bool b_error = 0;
aout_input_t *p_input;
aout_lock_mixer( p_aout );
if( p_aout->p_input == NULL )
aout_lock( p_aout );
p_input = p_aout->p_input;
if( p_input == NULL )
{
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
msg_Err( p_aout, "no decoder thread" );
return -1;
}
aout_lock_input( p_aout, p_aout->p_input );
aout_lock_input_fifos( p_aout );
aout_InputDelete( p_aout, p_aout->p_input );
aout_unlock_input_fifos( p_aout );
/* Lock all inputs. */
aout_lock_input_fifos( p_aout );
/* Reinitializes the output */
aout_InputDelete( p_aout, p_input );
aout_MixerDelete( p_aout );
/* Re-open the output plug-in. */
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->p_input->input ) == -1 )
if ( aout_OutputNew( p_aout, &p_input->input ) == -1 )
{
/* Release all locks and report the error. */
vlc_mutex_unlock( &p_aout->p_input->lock );
aout_unlock_input_fifos( p_aout );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
return -1;
}
if ( aout_MixerNew( p_aout ) == -1 )
{
aout_OutputDelete( p_aout );
vlc_mutex_unlock( &p_aout->p_input->lock );
aout_unlock_input_fifos( p_aout );
aout_unlock_mixer( p_aout );
aout_unlock( p_aout );
return -1;
}
/* Re-open the input. */
aout_input_t * p_input = p_aout->p_input;
b_error |= aout_InputNew( p_aout, p_input, &p_input->request_vout );
aout_unlock_input( p_aout, p_input );
aout_unlock_input_fifos( p_aout );
aout_unlock_mixer( p_aout );
return b_error;
if( aout_InputNew( p_aout, p_input, &p_input->request_vout ) )
{
#warning FIXME: deal with errors
aout_unlock( p_aout );
return -1;
}
aout_unlock( p_aout );
return 0;
}
/*****************************************************************************
......
......@@ -44,7 +44,7 @@
int aout_MixerNew( aout_instance_t * p_aout )
{
assert( !p_aout->p_mixer );
vlc_assert_locked( &p_aout->input_fifos_lock );
vlc_assert_locked( &p_aout->lock );
aout_mixer_t *p_mixer = vlc_object_create( p_aout, sizeof(*p_mixer) );
if( !p_mixer )
......@@ -75,14 +75,13 @@ int aout_MixerNew( aout_instance_t * p_aout )
*****************************************************************************/
void aout_MixerDelete( aout_instance_t * p_aout )
{
vlc_assert_locked( &p_aout->lock );
if( !p_aout->p_mixer )
return;
module_unneed( p_aout->p_mixer, p_aout->p_mixer->module );
vlc_object_release( p_aout->p_mixer );
/* */
p_aout->p_mixer = NULL;
}
......@@ -102,8 +101,7 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
* "smart" audio outputs. */
assert( samples > 0 );
aout_lock_input_fifos( p_aout );
aout_lock_output_fifo( p_aout );
vlc_assert_locked( &p_aout->lock );
/* Retrieve the date of the next buffer. */
date_t exact_start_date = p_aout->output.fifo.end_date;
......@@ -121,12 +119,10 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
start_date = 0;
}
aout_unlock_output_fifo( p_aout );
/* See if we have enough data to prepare a new buffer for the audio output. */
aout_buffer_t *p_buffer = p_fifo->p_first;
if( p_buffer == NULL )
goto giveup;
return -1;
/* Find the earliest start date available. */
if ( !start_date )
......@@ -153,7 +149,7 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
p_buffer = p_fifo->p_first;
if( p_buffer == NULL )
goto giveup;
return -1;
}
/* Check that we have enough samples. */
......@@ -161,7 +157,7 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
{
p_buffer = p_buffer->p_next;
if( p_buffer == NULL )
goto giveup;
return -1;
/* Check that all buffers are contiguous. */
if( prev_date != p_buffer->i_pts )
......@@ -191,11 +187,9 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
if( delta < 0 )
{
/* Is it really the best way to do it ? */
aout_lock_output_fifo( p_aout );
aout_FifoSet( &p_aout->output.fifo, 0 );
date_Set( &exact_start_date, 0 );
aout_unlock_output_fifo( p_aout );
goto giveup;
return -1;
}
if( delta > 0 )
{
......@@ -212,7 +206,7 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
p_buffer = block_Alloc( needed );
if( unlikely(p_buffer == NULL) )
/* XXX: should free input buffers */
goto giveup;
return -1;
p_buffer->i_nb_samples = samples;
for( uint8_t *p_out = p_buffer->p_buffer; needed > 0; )
......@@ -254,14 +248,8 @@ static int MixBuffer( aout_instance_t * p_aout, float volume )
/* Run the mixer. */
p_mixer->mix( p_mixer, p_buffer, volume );
aout_unlock_input_fifos( p_aout );
aout_OutputPlay( p_aout, p_buffer );
return 0;
giveup:
/* Interrupted before the end... We can't run. */
aout_unlock_input_fifos( p_aout );
return -1;
}
/*****************************************************************************
......
......@@ -33,6 +33,7 @@
#include <vlc_cpu.h>
#include <vlc_modules.h>
#include "libvlc.h"
#include "aout_internal.h"
/*****************************************************************************
......@@ -43,6 +44,7 @@
int aout_OutputNew( aout_instance_t * p_aout,
const audio_sample_format_t * p_format )
{
vlc_assert_locked( &p_aout->lock );
p_aout->output.output = *p_format;
/* Retrieve user defaults. */
......@@ -155,13 +157,8 @@ int aout_OutputNew( aout_instance_t * p_aout,
aout_FormatPrepare( &p_aout->output.output );
aout_lock_output_fifo( p_aout );
/* Prepare FIFO. */
aout_FifoInit( p_aout, &p_aout->output.fifo, p_aout->output.output.i_rate );
aout_unlock_output_fifo( p_aout );
aout_FormatPrint( p_aout, "output", &p_aout->output.output );
/* Calculate the resulting mixer output format. */
......@@ -202,17 +199,16 @@ int aout_OutputNew( aout_instance_t * p_aout,
*****************************************************************************/
void aout_OutputDelete( aout_instance_t * p_aout )
{
vlc_assert_locked( &p_aout->lock );
if( p_aout->output.p_module == NULL )
return;
module_unneed( p_aout, p_aout->output.p_module );
p_aout->output.p_module = NULL;
aout_FiltersDestroyPipeline( p_aout->output.pp_filters,
p_aout->output.i_nb_filters );
aout_lock_output_fifo( p_aout );
aout_FifoDestroy( &p_aout->output.fifo );
aout_unlock_output_fifo( p_aout );
}
/*****************************************************************************
......@@ -222,9 +218,10 @@ void aout_OutputDelete( aout_instance_t * p_aout )
*****************************************************************************/
void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
{
vlc_assert_locked( &p_aout->lock );
aout_FiltersPlay( p_aout->output.pp_filters, p_aout->output.i_nb_filters,
&p_buffer );
if( !p_buffer )
return;
if( p_buffer->i_buffer == 0 )
......@@ -233,10 +230,8 @@ void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
return;
}
aout_lock_output_fifo( p_aout );
aout_FifoPush( &p_aout->output.fifo, p_buffer );
p_aout->output.pf_play( p_aout );
aout_unlock_output_fifo( p_aout );
}
/**
......@@ -246,10 +241,10 @@ void aout_OutputPlay( aout_instance_t * p_aout, aout_buffer_t * p_buffer )
*/
void aout_OutputPause( aout_instance_t *aout, bool pause, mtime_t date )
{
aout_lock_output_fifo( aout );
vlc_assert_locked( &aout->lock );
if( aout->output.pf_pause != NULL )
aout->output.pf_pause( aout, pause, date );
aout_unlock_output_fifo( aout );
}
/*****************************************************************************
......@@ -268,7 +263,7 @@ aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
aout_buffer_t * p_buffer;
mtime_t now = mdate();
aout_lock_output_fifo( p_aout );
aout_lock( p_aout );
/* Drop the audio sample if the audio output is really late.
* In the case of b_can_sleek, we don't use a resampler so we need to be
......@@ -295,8 +290,7 @@ aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
"audio output is starving (no input), playing silence" );
p_aout->output.b_starving = true;
#endif
aout_unlock_output_fifo( p_aout );
return NULL;
goto out;
}
mtime_t delta = start_date - p_buffer->i_pts;
......@@ -315,8 +309,8 @@ aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
msg_Dbg( p_aout, "audio output is starving (%"PRId64"), "
"playing silence", -delta );
p_aout->output.b_starving = true;
aout_unlock_output_fifo( p_aout );
return NULL;
p_buffer = NULL;
goto out;
}
p_aout->output.b_starving = false;
......@@ -326,18 +320,15 @@ aout_buffer_t * aout_OutputNextBuffer( aout_instance_t * p_aout,
{
if( delta > AOUT_PTS_TOLERANCE || delta < -AOUT_PTS_TOLERANCE )
{
aout_unlock_output_fifo( p_aout );
/* Try to compensate the drift by doing some resampling. */
msg_Warn( p_aout, "output date isn't PTS date, requesting "
"resampling (%"PRId64")", delta );
aout_lock_input_fifos( p_aout );
aout_lock_output_fifo( p_aout );
aout_FifoMoveDates( &p_aout->p_input->mixer.fifo, delta );
aout_FifoMoveDates( p_fifo, delta );
aout_unlock_input_fifos( p_aout );
}
}
aout_unlock_output_fifo( p_aout );
out:
aout_unlock( p_aout );
return p_buffer;
}
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