Some games with support for the haptic feedback and speaker features of the Sony DualSense controller select the controller's audio output by filtering on the ContainerId IMMDevice property to find one that matches the controller's HID's. This MR, together with !359, adds support for exposing such a ContainerId to applications.
I marked this MR as a draft because I understand that the way the “guid” is generated is far from ideal. Furthermore, I will need to map from sysfs to container Id in other components as well (`winebus` for the HID device, and possibly `winealsa` and other audio drivers), so moving that part elsewhere would make sense. However, I think I will need help with those tasks.
-- v2: winepulse: Add support for containerId property from sysfs path winepulse: Store PulseAudio device's sysfs path when available
From: Claire Girka claire@sitedethib.com
--- dlls/winepulse.drv/pulse.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index bd918b6f260..268d59a71ab 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -93,6 +93,7 @@ typedef struct _PhysDevice { UINT index; REFERENCE_TIME min_period, def_period; WAVEFORMATEXTENSIBLE fmt; + char *sysfs_path; char pulse_name[0]; } PhysDevice;
@@ -154,6 +155,8 @@ static void free_phys_device_lists(void) do { LIST_FOR_EACH_ENTRY_SAFE(dev, dev_next, *list, PhysDevice, entry) { free(dev->name); + if (dev->sysfs_path) + free(dev->sysfs_path); free(dev); } } while (*(++list)); @@ -508,6 +511,7 @@ static void fill_device_info(PhysDevice *dev, pa_proplist *p) dev->bus_type = phys_device_bus_invalid; dev->vendor_id = 0; dev->product_id = 0; + dev->sysfs_path = NULL;
if (!p) return; @@ -524,6 +528,9 @@ static void fill_device_info(PhysDevice *dev, pa_proplist *p)
if ((buffer = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_ID))) dev->product_id = strtol(buffer, NULL, 16); + + if ((buffer = pa_proplist_gets(p, "sysfs.path"))) + dev->sysfs_path = strdup(buffer); }
static void pulse_add_device(struct list *list, pa_proplist *proplist, int index, EndpointFormFactor form,
From: Claire Girka claire@sitedethib.com
--- dlls/winepulse.drv/mmdevdrv.c | 5 ++++ dlls/winepulse.drv/pulse.c | 55 +++++++++++++++++++++++++++++++++++ dlls/winepulse.drv/unixlib.h | 1 + 3 files changed, 61 insertions(+)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index 446354fb9a5..1ac9ee1e0a8 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -2681,6 +2681,11 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI return E_OUTOFMEMORY; memcpy(out->pwszVal, params.wstr, size); break; + case VT_CLSID: + if (!(out->puuid = CoTaskMemAlloc(sizeof(GUID)))) + return E_OUTOFMEMORY; + memcpy(out->puuid, ¶ms.uuid, sizeof(GUID)); + break; case VT_UI4: out->ulVal = params.ulVal; break; diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 268d59a71ab..1be3ae38771 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -41,6 +41,8 @@
#include "wine/debug.h"
+#include "devpkey.h" + WINE_DEFAULT_DEBUG_CHANNEL(pulse);
struct pulse_stream @@ -2301,6 +2303,55 @@ static BOOL get_device_path(PhysDevice *dev, struct get_prop_value_params *param return TRUE; }
+static BOOL get_device_container(PhysDevice *dev, struct get_prop_value_params *params) +{ + char buffer[10]; + char *path, *p; + + if (dev->sysfs_path == NULL) + return FALSE; + + path = malloc(strlen(dev->sysfs_path) + strlen("/sys") + strlen("/removable") + 1); + strcpy(path, "/sys"); + strcat(path, dev->sysfs_path); + + while ((p = strrchr(path, '/'))) { + FILE *f; + + strcpy(p, "/removable"); + f = fopen(path, "r"); + *p = 0; + + if (f) { + if (fgets(buffer, 10, f)) { + if (strcmp(buffer, "fixed") != 0) { + /* It's a potentially removable device, so treat it as a container */ + fclose(f); + break; + } + } + fclose(f); + } + } + + if (p && (p - path) > 4) { + char *guid = (char*) ¶ms->uuid; + memset(¶ms->uuid, 0, sizeof(GUID)); + + for (int i = strlen(path); i > 4; i--) { + guid[i % 16] ^= path[i]; + } + + params->vt = VT_CLSID; + + free(path); + return TRUE; + } + + free(path); + return FALSE; +} + static NTSTATUS pulse_get_prop_value(void *args) { static const GUID PKEY_AudioEndpoint_GUID = { @@ -2321,6 +2372,10 @@ static NTSTATUS pulse_get_prop_value(void *args) if (!get_device_path(dev, params)) break; return STATUS_SUCCESS; + } else if (IsEqualPropertyKey(*params->prop, DEVPKEY_Device_ContainerId)) { + if (!get_device_container(dev, params)) + break; + return STATUS_SUCCESS; } else if (IsEqualGUID(¶ms->prop->fmtid, &PKEY_AudioEndpoint_GUID)) { switch (params->prop->pid) { case 0: /* FormFactor */ diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h index 1481a5db4b8..b13048369ef 100644 --- a/dlls/winepulse.drv/unixlib.h +++ b/dlls/winepulse.drv/unixlib.h @@ -227,6 +227,7 @@ struct get_prop_value_params union { WCHAR wstr[128]; + GUID uuid; ULONG ulVal; }; };