From: Claire Girka <claire(a)sitedethib.com>
Some games, like Deathloop, enumerate all unavailable audio devices, including
unavailable ones, and stop at the first one matching the ContainerID.
Depending on how ContainerIDs end up being attributed, an active device may end
up sharing a ContainerID with an unplugged device that was previously plugged
in the same physical port. Depending on the audio backend, the same audio
device plugged in the same port may be seen as a different audio device by Wine
depending on things like in which order devices were discovered.
In those cases, a game might find an inactive matching device before the active
one, and thus fail to open the audio output.
By invalidating the ContainerID of unavailable devices, we this issue can be
avoided.
---
dlls/mmdevapi/devenum.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c
index bf0fc4728d1..09fb3c44875 100644
--- a/dlls/mmdevapi/devenum.c
+++ b/dlls/mmdevapi/devenum.c
@@ -207,6 +207,26 @@ static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow,
REFPROPERT
return hr;
}
+static HRESULT MMDevice_DeletePropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY
key)
+{
+ WCHAR buffer[80];
+ const GUID *id = &key->fmtid;
+ HRESULT hr;
+ HKEY regkey;
+ LONG ret;
+
+ hr = MMDevPropStore_OpenPropKey(devguid, flow, ®key);
+ if (FAILED(hr))
+ return hr;
+ wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3,
+ id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
+ id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7],
key->pid );
+ ret = RegDeleteValueW(regkey, buffer);
+ RegCloseKey(regkey);
+ TRACE("Deleting %s returned %lu\n", debugstr_w(buffer), ret);
+ return hr;
+}
+
static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key,
REFPROPVARIANT pv)
{
WCHAR buffer[80];
@@ -391,7 +411,14 @@ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow
flow, DWORD st
MMDevice_SetPropValue(id, flow, (const
PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv);
MMDevice_SetPropValue(id, flow, (const
PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv);
- set_driver_prop_value(id, flow, (const
PROPERTYKEY*)&DEVPKEY_Device_ContainerId);
+ /* The mechanism we use to attribute Container IDs is not very robust and
could end up making
+ an active device share a ContainerID with inactive devices, and some games
enumerate even
+ inactive devices, stopping at the first matching one.
+ To avoid issues, invalidate the ContainerID of devices that are not
present. */
+ if (state & DEVICE_STATE_ACTIVE)
+ set_driver_prop_value(id, flow, (const
PROPERTYKEY*)&DEVPKEY_Device_ContainerId);
+ else if (state & DEVICE_STATE_NOTPRESENT)
+ MMDevice_DeletePropValue(id, flow, (const
PROPERTYKEY*)&DEVPKEY_Device_ContainerId);
pv.pwszVal = guidstr;
MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/359