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

aout: restart output on the decoder thread, safely

This should fix the remaining crashes and deadlocks when changing
the audio device or the channel map.
parent 655ba892
...@@ -108,6 +108,8 @@ typedef struct ...@@ -108,6 +108,8 @@ typedef struct
/* Filters between mixer and output */ /* Filters between mixer and output */
filter_t *filters[AOUT_MAX_FILTERS]; filter_t *filters[AOUT_MAX_FILTERS];
int nb_filters; int nb_filters;
bool need_restart;
} aout_owner_t; } aout_owner_t;
typedef struct typedef struct
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <vlc_input.h> #include <vlc_input.h>
#include "aout_internal.h" #include "aout_internal.h"
#include "libvlc.h"
#undef aout_DecNew #undef aout_DecNew
/** /**
...@@ -147,6 +148,43 @@ void aout_DecDelete( audio_output_t * p_aout, aout_input_t * p_input ) ...@@ -147,6 +148,43 @@ void aout_DecDelete( audio_output_t * p_aout, aout_input_t * p_input )
free( p_input ); free( p_input );
} }
static void aout_CheckRestart (audio_output_t *aout)
{
aout_owner_t *owner = aout_owner (aout);
aout_input_t *input = owner->input;
aout_assert_locked (aout);
if (likely(!owner->need_restart))
return;
owner->need_restart = false;
/* Reinitializes the output */
aout_InputDelete (aout, owner->input);
aout_MixerDelete (owner->volume.mixer);
owner->volume.mixer = NULL;
aout_OutputDelete (aout);
if (aout_OutputNew (aout, &input->input))
{
error:
input->b_error = true;
return; /* we are officially screwed */
}
owner->volume.mixer = aout_MixerNew (aout, owner->mixer_format.i_format);
if (owner->volume.mixer == NULL)
{
aout_OutputDelete (aout);
goto error;
}
if (aout_InputNew (aout, input, &input->request_vout))
assert (input->b_error);
else
assert (!input->b_error);
}
/* /*
* Buffer management * Buffer management
...@@ -201,8 +239,10 @@ int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input, ...@@ -201,8 +239,10 @@ int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input,
return -1; return -1;
} }
/* Input */ aout_CheckRestart( p_aout );
aout_InputCheckAndRestart( p_aout, p_input ); aout_InputCheckAndRestart( p_aout, p_input );
/* Input */
p_buffer = aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate ); p_buffer = aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
if( p_buffer != NULL ) if( p_buffer != NULL )
......
...@@ -234,58 +234,18 @@ int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute) ...@@ -234,58 +234,18 @@ int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute)
* Pipelines management * Pipelines management
*/ */
/***************************************************************************** /**
* aout_Restart : re-open the output device and rebuild the input and output * Marks the audio output for restart, to update any parameter of the output
* pipelines * plug-in (e.g. output device or channel mapping).
***************************************************************************** */
* This function is used whenever the parameters of the output plug-in are static void aout_Restart (audio_output_t *aout)
* changed (eg. selecting S/PDIF or PCM).
*****************************************************************************/
static int aout_Restart( audio_output_t * p_aout )
{ {
aout_input_t *p_input; aout_owner_t *owner = aout_owner (aout);
aout_owner_t *owner = aout_owner (p_aout);
aout_lock( p_aout );
p_input = owner->input;
if( p_input == NULL )
{
aout_unlock( p_aout );
msg_Err( p_aout, "no decoder thread" );
return -1;
}
/* Reinitializes the output */
aout_InputDelete( p_aout, p_input );
aout_MixerDelete (owner->volume.mixer);
owner->volume.mixer = NULL;
aout_OutputDelete( p_aout );
/* FIXME: This function is notoriously dangerous/unsafe. aout_lock (aout);
* By the way, if OutputNew or MixerNew fails, we are totally screwed. */ if (owner->input != NULL)
if ( aout_OutputNew( p_aout, &p_input->input ) == -1 ) owner->need_restart = true;
{ aout_unlock (aout);
/* Release all locks and report the error. */
aout_unlock( p_aout );
return -1;
}
owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format);
if (owner->volume.mixer == NULL)
{
aout_OutputDelete( p_aout );
aout_unlock( p_aout );
return -1;
}
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;
} }
/***************************************************************************** /*****************************************************************************
......
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