[vlc-commits] [Git][videolan/vlc][master] 10 commits: mmdevice: avoid using NULL as (wide) string format argument

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Sun Dec 28 13:59:07 UTC 2025



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
8c9665b4 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: avoid using NULL as (wide) string format argument

IMMNotificationClient::OnDefaultDeviceChanged() can give a NULL pointer [^1].

[^1]: https://learn.microsoft.com/en-us/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immnotificationclient-ondefaultdevicechanged#parameters

- - - - -
f39b6c88 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: fix potential leak on exit

- - - - -
507cd9c4 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: avoid setting acquired_device to a device we can't select

Try to use the default device instead.

- - - - -
5028d30f by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: set the initialisation_status to FAILED when we don't have a device

The hr error is set and MMSession() will return that value.

- - - - -
e2a874bd by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: use a single string pointer for the device name

We only care about the name before getting sys->dev and we keep it
in case of restart on the same device.

We also need a way to tell if sys->dev has been acquired or if we failed
to do so. NULL alone in sys->dev can't tell that.

In OnDefaultDeviceChange() we don't care if the device was acquired or not.
We only care if we are using the default device when it changes.

- - - - -
847f7e10 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: use NULL for the default device name

That's what the core uses.

- - - - -
019cfc36 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: merge initialisation_status and device_status

The initialization fails or succeeds if the device was properly acquired.
We don't need the initialisation_status only used for initialization.

- - - - -
e197614b by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: only log the device we are going to use

On error we log, which device name failed. "using default device" will be logged next.

- - - - -
61c1715d by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: rename request_device_restart to default_device_changed

- - - - -
5a666ee2 by Steve Lhomme at 2025-12-28T14:30:24+01:00
mmdevice: always log the default device change

- - - - -


1 changed file:

- modules/audio_output/mmdevice.c


Changes:

=====================================
modules/audio_output/mmdevice.c
=====================================
@@ -72,13 +72,12 @@ static void LeaveMTA(void)
     CoUninitialize();
 }
 
-static wchar_t default_device[1] = L"";
 static char default_device_b[1] = "";
 
-enum initialisation_status_t {
-    INITIALISATION_PENDING,
-    INITIALISATION_FAILED,
-    INITIALISATION_SUCCEEDED,
+enum device_acquisition_status {
+    DEVICE_PENDING,
+    DEVICE_ACQUISITION_FAILED,
+    DEVICE_ACQUIRED,
 };
 
 typedef struct
@@ -96,13 +95,12 @@ typedef struct
     unsigned ducks;
     float gain; /**< Current software gain volume */
 
-    wchar_t *requested_device; /**< Requested device identifier, NULL if none */
     float requested_volume; /**< Requested volume, negative if none */
     signed char requested_mute; /**< Requested mute, negative if none */
-    wchar_t *acquired_device; /**< Acquired device identifier, NULL if none */
-    bool request_device_restart;
+    enum device_acquisition_status device_status;
+    wchar_t *device_name; /**< device identifier to use, NULL if default */
+    bool default_device_changed;
     HANDLE work_event;
-    enum initialisation_status_t initialisation_status;
     vlc_mutex_t lock;
     vlc_cond_t ready;
     vlc_thread_t thread; /**< Thread for audio session control */
@@ -579,13 +577,13 @@ vlc_MMNotificationClient_OnDefaultDeviceChange(IMMNotificationClient *this,
         return S_OK;
 
     vlc_mutex_lock(&sys->lock);
-    if (sys->acquired_device == NULL || sys->acquired_device == default_device)
+    if (sys->device_name == NULL)
     {
-        msg_Dbg(aout, "default device changed: %ls", wid);
-        sys->request_device_restart = true;
+        sys->default_device_changed = true;
         aout_RestartRequest(aout, true);
     }
     vlc_mutex_unlock(&sys->lock);
+    msg_Dbg(aout, "default device changed: %ls", wid ? wid : L"(disabled)");
 
     return S_OK;
 }
@@ -728,12 +726,12 @@ static HRESULT DevicesEnum(IMMDeviceEnumerator *it,
 static int DeviceRequestLocked(audio_output_t *aout)
 {
     aout_sys_t *sys = aout->sys;
-    assert(sys->requested_device);
+    assert(sys->device_status == DEVICE_PENDING);
 
-    sys->request_device_restart = false;
+    sys->default_device_changed = false;
 
     SetEvent(sys->work_event);
-    while (sys->requested_device != NULL)
+    while (sys->device_status == DEVICE_PENDING)
         vlc_cond_wait(&sys->ready, &sys->lock);
 
     if (sys->stream != NULL && sys->dev != NULL)
@@ -745,16 +743,17 @@ static int DeviceRequestLocked(audio_output_t *aout)
 static int DeviceSelectLocked(audio_output_t *aout, const char *id)
 {
     aout_sys_t *sys = aout->sys;
-    assert(sys->requested_device == NULL);
+    assert(sys->device_status != DEVICE_PENDING);
 
+    sys->device_status = DEVICE_PENDING;
     if (id != NULL && strcmp(id, default_device_b) != 0)
     {
-        sys->requested_device = ToWide(id); /* FIXME leak */
-        if (unlikely(sys->requested_device == NULL))
+        sys->device_name = ToWide(id); /* FIXME leak */
+        if (unlikely(sys->device_name == NULL))
             return -1;
     }
     else
-        sys->requested_device = default_device;
+        sys->device_name = NULL;
 
     return DeviceRequestLocked(aout);
 }
@@ -762,9 +761,8 @@ static int DeviceSelectLocked(audio_output_t *aout, const char *id)
 static int DeviceRestartLocked(audio_output_t *aout)
 {
     aout_sys_t *sys = aout->sys;
-    assert(sys->requested_device == NULL);
-    sys->requested_device = sys->acquired_device ? sys->acquired_device
-                                                 : default_device;
+    assert(sys->device_status != DEVICE_PENDING);
+    sys->device_status = DEVICE_PENDING;
     return DeviceRequestLocked(aout);
 }
 
@@ -790,7 +788,7 @@ static void MMSessionMainloop(audio_output_t *aout, ISimpleAudioVolume *volume)
     bool report_volume = true;
     bool report_mute = true;
 
-    while (sys->requested_device == NULL)
+    while (sys->device_status != DEVICE_PENDING)
     {
         if (volume != NULL)
         {
@@ -866,7 +864,8 @@ static void MMSessionMainloop(audio_output_t *aout, ISimpleAudioVolume *volume)
             if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
                          hr == AUDCLNT_E_RESOURCES_INVALIDATED))
             {
-                sys->requested_device = default_device;
+                sys->device_name = NULL;
+                sys->device_status = DEVICE_PENDING;
                 /* The restart of the stream will be requested asynchronously */
             }
         }
@@ -895,22 +894,25 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
     void *pv;
     HRESULT hr;
 
-    assert(sys->requested_device != NULL);
+    assert(sys->device_status == DEVICE_PENDING);
     assert(sys->dev == NULL);
 
     /* Yes, it's perfectly valid to request the same device, see Start()
      * comments. */
-    if (sys->acquired_device != sys->requested_device
-     && sys->acquired_device != default_device)
-        free(sys->acquired_device);
-    if (sys->requested_device != default_device) /* Device selected explicitly */
+    if (sys->device_name != NULL) /* Device selected explicitly */
     {
-        msg_Dbg(aout, "using selected device %ls", sys->requested_device);
-        hr = IMMDeviceEnumerator_GetDevice(it, sys->requested_device, &sys->dev);
+        hr = IMMDeviceEnumerator_GetDevice(it, sys->device_name, &sys->dev);
         if (FAILED(hr))
+        {
             msg_Err(aout, "cannot get selected device %ls (error 0x%lX)",
-                    sys->requested_device, hr);
-        sys->acquired_device = sys->requested_device;
+                    sys->device_name, hr);
+            hr = AUDCLNT_E_DEVICE_INVALIDATED;
+        }
+        else
+        {
+            msg_Dbg(aout, "using selected device %ls", sys->device_name);
+            sys->device_status = DEVICE_ACQUIRED;
+        }
     }
     else
         hr = AUDCLNT_E_DEVICE_INVALIDATED;
@@ -924,21 +926,23 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
         if (FAILED(hr))
         {
             msg_Err(aout, "cannot get default device (error 0x%lX)", hr);
-            sys->acquired_device = NULL;
+            sys->device_status = DEVICE_ACQUISITION_FAILED;
+            sys->device_name = NULL;
         }
         else
-            sys->acquired_device = default_device;
+        {
+            sys->device_status = DEVICE_ACQUIRED;
+            sys->device_name = NULL;
+        }
     }
 
-    sys->requested_device = NULL;
-    sys->initialisation_status = INITIALISATION_SUCCEEDED;
     vlc_cond_signal(&sys->ready);
 
     if (SUCCEEDED(hr))
     {   /* Report actual device */
         LPWSTR wdevid;
 
-        if (sys->acquired_device == default_device)
+        if (sys->device_name == NULL)
             aout_DeviceReport(aout, default_device_b);
         else
         {
@@ -1132,7 +1136,7 @@ static void *MMThread(void *data)
     vlc_mutex_lock(&sys->lock);
 
     do
-        if (sys->requested_device == NULL || FAILED(MMSession(aout, it)))
+        if (sys->device_status != DEVICE_PENDING || FAILED(MMSession(aout, it)))
         {
             vlc_mutex_unlock(&sys->lock);
             WaitForSingleObject(sys->work_event, INFINITE);
@@ -1150,7 +1154,7 @@ static void *MMThread(void *data)
 
 error:
     vlc_mutex_lock(&sys->lock);
-    sys->initialisation_status = INITIALISATION_FAILED;
+    sys->device_status = DEVICE_ACQUISITION_FAILED;
     vlc_cond_signal(&sys->ready);
     vlc_mutex_unlock(&sys->lock);
     return NULL;
@@ -1212,7 +1216,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
     EnterMTA();
     vlc_mutex_lock(&sys->lock);
 
-    if ((sys->request_device_restart && DeviceRestartLocked(aout) != 0)
+    if ((sys->default_device_changed && DeviceRestartLocked(aout) != 0)
       || sys->dev == NULL)
     {
         /* Error if the device restart failed or if a request previously
@@ -1338,8 +1342,8 @@ static int Open(vlc_object_t *obj)
     sys->gain = 1.f;
     sys->requested_volume = -1.f;
     sys->requested_mute = -1;
-    sys->acquired_device = NULL;
-    sys->request_device_restart = false;
+    sys->device_name = NULL;
+    sys->default_device_changed = false;
 
     if (!var_CreateGetBool(aout, "volume-save"))
         VolumeSetLocked(aout, var_InheritFloat(aout, "mmdevice-volume"));
@@ -1356,28 +1360,28 @@ static int Open(vlc_object_t *obj)
     char *saved_device_b = var_InheritString(aout, "mmdevice-audio-device");
     if (saved_device_b != NULL && strcmp(saved_device_b, default_device_b) != 0)
     {
-        sys->requested_device = ToWide(saved_device_b); /* FIXME leak */
+        sys->device_name = ToWide(saved_device_b); /* FIXME leak */
         free(saved_device_b);
 
-        if (unlikely(sys->requested_device == NULL))
+        if (unlikely(sys->device_name == NULL))
             goto error;
     }
     else
     {
         free(saved_device_b);
-        sys->requested_device = default_device;
+        sys->device_name = NULL;
     }
+    sys->device_status = DEVICE_PENDING;
 
-    sys->initialisation_status = INITIALISATION_PENDING;
     if (vlc_clone(&sys->thread, MMThread, aout))
         goto error;
 
     vlc_mutex_lock(&sys->lock);
-    while (sys->initialisation_status == INITIALISATION_PENDING)
+    while (sys->device_status == DEVICE_PENDING)
         vlc_cond_wait(&sys->ready, &sys->lock);
     vlc_mutex_unlock(&sys->lock);
 
-    if (sys->initialisation_status == INITIALISATION_FAILED)
+    if (sys->device_status == DEVICE_ACQUISITION_FAILED)
     {
         vlc_join(sys->thread, NULL);
         goto error;
@@ -1407,10 +1411,15 @@ static void Close(vlc_object_t *obj)
     aout_sys_t *sys = aout->sys;
 
     vlc_mutex_lock(&sys->lock);
-    sys->requested_device = default_device; /* break out of MMSession() loop */
+    wchar_t *previous = sys->device_name;
+    sys->device_name = NULL;
+    sys->device_status = DEVICE_PENDING; /* break out of MMSession() loop */
     sys->it = NULL; /* break out of MMThread() loop */
     vlc_mutex_unlock(&sys->lock);
 
+    if (previous != NULL)
+        free(previous);
+
     SetEvent(sys->work_event);
 
     vlc_join(sys->thread, NULL);



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/36464b937d97d49a7042889c2be3438906cd8096...5a666ee2df0070786cad7d1fdd1cd34242514c13

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/36464b937d97d49a7042889c2be3438906cd8096...5a666ee2df0070786cad7d1fdd1cd34242514c13
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list