[vlc-commits] aout: do not block thread changing volume/mute/device (fixes #8240)

Rémi Denis-Courmont git at videolan.org
Wed Feb 27 20:33:57 CET 2013


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed Feb 27 21:28:12 2013 +0200| [f788153763bf56fda744df5b9abaa893c402378e] | committer: Rémi Denis-Courmont

aout: do not block thread changing volume/mute/device (fixes #8240)

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f788153763bf56fda744df5b9abaa893c402378e
---

 src/audio_output/aout_internal.h |    8 +++
 src/audio_output/output.c        |   99 +++++++++++++++++++++++++++++++-------
 2 files changed, 89 insertions(+), 18 deletions(-)

diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index 58d795a..5c1c9dd 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -54,6 +54,14 @@ typedef struct
 
     struct
     {
+        vlc_mutex_t lock;
+        char *device;
+        float volume;
+        char mute;
+    } req;
+
+    struct
+    {
         mtime_t end; /**< Last seen PTS */
         unsigned resamp_start_drift; /**< Resampler drift absolute value */
         int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 5cd28f2..30f3396 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -25,6 +25,9 @@
 # include "config.h"
 #endif
 
+#include <stdlib.h>
+#include <assert.h>
+
 #include <vlc_common.h>
 #include <vlc_aout.h>
 #include <vlc_modules.h>
@@ -32,6 +35,8 @@
 #include "libvlc.h"
 #include "aout_internal.h"
 
+static const char unset_str[1] = ""; /* Non-NULL constant string pointer */
+
 /* Local functions */
 static void aout_OutputAssertLocked (audio_output_t *aout)
 {
@@ -112,6 +117,11 @@ audio_output_t *aout_New (vlc_object_t *parent)
     aout_owner_t *owner = aout_owner (aout);
 
     vlc_mutex_init (&owner->lock);
+    vlc_mutex_init (&owner->req.lock);
+    owner->req.device = (char *)unset_str;
+    owner->req.volume = -1.f;
+    owner->req.mute = -1;
+
     vlc_object_set_destructor (aout, aout_Destructor);
 
     /* Audio output module callbacks */
@@ -464,11 +474,46 @@ void aout_OutputLock (audio_output_t *aout)
     vlc_mutex_lock (&owner->lock);
 }
 
+static int aout_OutputTryLock (audio_output_t *aout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+
+    return vlc_mutex_trylock (&owner->lock);
+}
+
 void aout_OutputUnlock (audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
 
+    vlc_assert_locked (&owner->lock);
+    vlc_mutex_lock (&owner->req.lock);
+
+    if (owner->req.device != unset_str)
+    {
+        aout_OutputDeviceSet (aout, owner->req.device);
+        free (owner->req.device);
+        owner->req.device = (char *)unset_str;
+    }
+
+    if (owner->req.volume >= 0.f)
+    {
+        aout_OutputVolumeSet (aout, owner->req.volume);
+        owner->req.volume = -1.f;
+    }
+
+    if (owner->req.mute >= 0)
+    {
+        aout_OutputMuteSet (aout, owner->req.mute);
+        owner->req.mute = -1;
+    }
+
     vlc_mutex_unlock (&owner->lock);
+    /* If another thread is blocked waiting for owner->req.lock at this point,
+     * this aout_OutputUnlock() call will not see and apply its change request.
+     * The other thread will need to apply the change request itself, which
+     * implies it is able to (try-)lock owner->lock. Therefore this thread must
+     * release owner->lock _before_ owner->req.lock. Do not reorder!!! */
+    vlc_mutex_unlock (&owner->req.lock);
 }
 
 /**
@@ -484,16 +529,20 @@ float aout_VolumeGet (audio_output_t *aout)
 /**
  * Sets the volume of the audio output stream.
  * \note The mute status is not changed.
- * \return 0 on success, -1 on failure.
+ * \return 0 on success, -1 on failure (TODO).
  */
 int aout_VolumeSet (audio_output_t *aout, float vol)
 {
-    int ret;
+    aout_owner_t *owner = aout_owner (aout);
 
-    aout_OutputLock (aout);
-    ret = aout_OutputVolumeSet (aout, vol);
-    aout_OutputUnlock (aout);
-    return ret;
+    assert (vol >= 0.f);
+    vlc_mutex_lock (&owner->req.lock);
+    owner->req.volume = vol;
+    vlc_mutex_unlock (&owner->req.lock);
+
+    if (aout_OutputTryLock (aout) == 0)
+        aout_OutputUnlock (aout);
+    return 0;
 }
 
 /**
@@ -507,16 +556,19 @@ int aout_MuteGet (audio_output_t *aout)
 
 /**
  * Sets the audio output stream mute flag.
- * \return 0 on success, -1 on failure.
+ * \return 0 on success, -1 on failure (TODO).
  */
 int aout_MuteSet (audio_output_t *aout, bool mute)
 {
-    int ret;
+    aout_owner_t *owner = aout_owner (aout);
 
-    aout_OutputLock (aout);
-    ret = aout_OutputMuteSet (aout, mute);
-    aout_OutputUnlock (aout);
-    return ret;
+    vlc_mutex_lock (&owner->req.lock);
+    owner->req.mute = mute;
+    vlc_mutex_unlock (&owner->req.lock);
+
+    if (aout_OutputTryLock (aout) == 0)
+        aout_OutputUnlock (aout);
+    return 0;
 }
 
 /**
@@ -532,16 +584,27 @@ char *aout_DeviceGet (audio_output_t *aout)
 /**
  * Selects an audio output device.
  * \param id device ID to select, or NULL for the default device
- * \return zero on success, non-zero on error.
+ * \return zero on success, non-zero on error (TODO).
  */
 int aout_DeviceSet (audio_output_t *aout, const char *id)
 {
-    int ret;
+    aout_owner_t *owner = aout_owner (aout);
 
-    aout_OutputLock (aout);
-    ret = aout_OutputDeviceSet (aout, id);
-    aout_OutputUnlock (aout);
-    return ret;
+    char *dev = NULL;
+    if (id != NULL)
+    {
+        dev = strdup (id);
+        if (unlikely(dev == NULL))
+            return -1;
+    }
+
+    vlc_mutex_lock (&owner->req.lock);
+    owner->req.device = dev;
+    vlc_mutex_unlock (&owner->req.lock);
+
+    if (aout_OutputTryLock (aout) == 0)
+        aout_OutputUnlock (aout);
+    return 0;
 }
 
 /**



More information about the vlc-commits mailing list