]> git.sesse.net Git - vlc/commitdiff
aout: restart output on the decoder thread, safely
authorRémi Denis-Courmont <remi@remlab.net>
Thu, 4 Aug 2011 16:34:51 +0000 (19:34 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Thu, 4 Aug 2011 16:37:37 +0000 (19:37 +0300)
This should fix the remaining crashes and deadlocks when changing
the audio device or the channel map.

src/audio_output/aout_internal.h
src/audio_output/dec.c
src/audio_output/intf.c

index 2b53fd7cc71beb8d200ad37782fc5776621639da..0a4ac0d98dc1ac117266bcc49d09965676c3ba4d 100644 (file)
@@ -108,6 +108,8 @@ typedef struct
     /* Filters between mixer and output */
     filter_t *filters[AOUT_MAX_FILTERS];
     int       nb_filters;
+
+    bool need_restart;
 } aout_owner_t;
 
 typedef struct
index cd09fac9a2ecf7a13f124a2344a8133ef9f06aa5..d5e3727a4b72033512336a231da2fc0b7d0c1f5a 100644 (file)
@@ -36,6 +36,7 @@
 #include <vlc_input.h>
 
 #include "aout_internal.h"
+#include "libvlc.h"
 
 #undef aout_DecNew
 /**
@@ -147,6 +148,43 @@ void aout_DecDelete( audio_output_t * p_aout, aout_input_t * 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
@@ -201,8 +239,10 @@ int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input,
         return -1;
     }
 
-    /* Input */
+    aout_CheckRestart( p_aout );
     aout_InputCheckAndRestart( p_aout, p_input );
+
+    /* Input */
     p_buffer = aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
 
     if( p_buffer != NULL )
index 5b9140183e58043d68c4629e094ae285c150163d..4c9e117ce760010a5a03caa682d57e2528c3e359 100644 (file)
@@ -234,58 +234,18 @@ int aout_SetMute (vlc_object_t *obj, audio_volume_t *volp, bool mute)
  * Pipelines management
  */
 
-/*****************************************************************************
- * aout_Restart : re-open the output device and rebuild the input and output
- *                pipelines
- *****************************************************************************
- * This function is used whenever the parameters of the output plug-in are
- * changed (eg. selecting S/PDIF or PCM).
- *****************************************************************************/
-static int aout_Restart( audio_output_t * p_aout )
+/**
+ * Marks the audio output for restart, to update any parameter of the output
+ * plug-in (e.g. output device or channel mapping).
+ */
+static void aout_Restart (audio_output_t *aout)
 {
-    aout_input_t *p_input;
-    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 );
+    aout_owner_t *owner = aout_owner (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_input->input ) == -1 )
-    {
-        /* 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;
+    aout_lock (aout);
+    if (owner->input != NULL)
+        owner->need_restart = true;
+    aout_unlock (aout);
 }
 
 /*****************************************************************************