[vlc-devel] [RFC PATH] mmdevice: update device if the previous one failed

Thomas Guillem thomas at gllm.fr
Thu Sep 15 11:10:09 CEST 2016


s->owner.device need to be updated with the new dev after DeviceSelect is
called.

This fix a crash when trying to load 2 time the same failing device (Once you
got a AUDCLNT_E_DEVICE_INVALIDATED error, you shouldn't use this device again).

closes #17391

== RFC ==

Not really sure about the lock in Start(). sys->dev need to be protected by
sys->lock since it can be modified from the MMThread. I'm affraid
vlc_module_load can take too much time and block callbacks that need this lock
(like vlc_AudioSessionEvents_OnSimpleVolumeChanged)
---
 modules/audio_output/mmdevice.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/modules/audio_output/mmdevice.c b/modules/audio_output/mmdevice.c
index b48dbb3..170d316 100644
--- a/modules/audio_output/mmdevice.c
+++ b/modules/audio_output/mmdevice.c
@@ -732,7 +732,7 @@ static int DevicesEnum(audio_output_t *aout, IMMDeviceEnumerator *it)
     return n;
 }
 
-static int DeviceSelect(audio_output_t *aout, const char *id)
+static int DeviceSelectLocked(audio_output_t *aout, const char *id)
 {
     aout_sys_t *sys = aout->sys;
     wchar_t *device;
@@ -746,14 +746,12 @@ static int DeviceSelect(audio_output_t *aout, const char *id)
     else
         device = default_device;
 
-    EnterCriticalSection(&sys->lock);
     assert(sys->device == NULL);
     sys->device = device;
 
     WakeConditionVariable(&sys->work);
     while (sys->device != NULL)
         SleepConditionVariableCS(&sys->ready, &sys->lock, INFINITE);
-    LeaveCriticalSection(&sys->lock);
 
     if (sys->stream != NULL && sys->dev != NULL)
         /* Request restart of stream with the new device */
@@ -761,6 +759,14 @@ static int DeviceSelect(audio_output_t *aout, const char *id)
     return (sys->dev != NULL) ? 0 : -1;
 }
 
+static int DeviceSelect(audio_output_t *aout, const char *id)
+{
+    EnterCriticalSection(&aout->sys->lock);
+    int ret = DeviceSelectLocked(aout, id);
+    LeaveCriticalSection(&aout->sys->lock);
+    return ret;
+}
+
 /*** Initialization / deinitialization **/
 static wchar_t *var_InheritWide(vlc_object_t *obj, const char *name)
 {
@@ -1080,20 +1086,22 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
     if (unlikely(s == NULL))
         return -1;
 
-    s->owner.device = sys->dev;
     s->owner.activate = ActivateDevice;
 
     EnterMTA();
+    EnterCriticalSection(&sys->lock);
     for (;;)
     {
         HRESULT hr;
+        s->owner.device = sys->dev;
 
         /* TODO: Do not overload the "aout" configuration item. */
         sys->module = vlc_module_load(s, "aout stream", "$aout", false,
                                       aout_stream_Start, s, fmt, &hr);
-        if (hr != AUDCLNT_E_DEVICE_INVALIDATED || DeviceSelect(aout, NULL))
+        if (hr != AUDCLNT_E_DEVICE_INVALIDATED || DeviceSelectLocked(aout, NULL))
             break;
     }
+    LeaveCriticalSection(&sys->lock);
     LeaveMTA();
 
     if (sys->module == NULL)
-- 
2.9.3



More information about the vlc-devel mailing list