[PATCH 3/5] winepulse.drv: Implement GetPropValue.

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Feb 9 08:10:56 CST 2022


Based on a patch by Mark Harmstone <mark at harmstone.com>.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/winepulse.drv/mmdevdrv.c | 57 +++++++++++++++++++++++++++++
 dlls/winepulse.drv/pulse.c    | 69 ++++++++++++++++++++++++++++++++---
 dlls/winepulse.drv/unixlib.h  | 18 +++++++++
 3 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 0e4fe9e..f07b0ca 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -2524,8 +2524,49 @@ HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
     return S_OK;
 }
 
+static HRESULT get_device_path(struct get_device_info_params *params, GUID *guid, PROPVARIANT *out)
+{
+    UINT serial_number;
+    const WCHAR *fmt;
+    WCHAR path[128];
+    int len;
+
+    switch (params->bus_type) {
+    case phys_device_bus_pci:
+        fmt = L"{1}.HDAUDIO\\FUNC_01&VEN_%04X&DEV_%04X\\%u&%08X";
+        break;
+    case phys_device_bus_usb:
+        fmt = L"{1}.USB\\VID_%04X&PID_%04X\\%u&%08X";
+        break;
+    default:
+        return E_FAIL;
+    }
+
+    /* As hardly any audio devices have serial numbers, Windows instead
+       appears to use a persistent random number. We emulate this here
+       by instead using the last 8 hex digits of the GUID. */
+    serial_number = (guid->Data4[4] << 24) | (guid->Data4[5] << 16) | (guid->Data4[6] << 8) | guid->Data4[7];
+
+    len = swprintf(path, ARRAY_SIZE(path), fmt, params->vendor_id, params->product_id, params->index, serial_number);
+    if (len < 0)
+        return E_FAIL;
+
+    out->vt = VT_LPWSTR;
+    out->pwszVal = CoTaskMemAlloc((len + 1) * sizeof(WCHAR));
+    if (!out->pwszVal)
+        return E_OUTOFMEMORY;
+
+    wcscpy(out->pwszVal, path);
+    return S_OK;
+}
+
 HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
 {
+    static const PROPERTYKEY devicepath_key = { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */
+        {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
+    };
+    struct get_device_info_params params;
+
     TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
 
     if (IsEqualGUID(guid, &pulse_render_guid) && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) {
@@ -2535,5 +2576,21 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI
         return out->ulVal ? S_OK : E_FAIL;
     }
 
+    if (!get_pulse_name_by_guid(guid, params.device, &params.dataflow))
+        return E_FAIL;
+
+    pulse_call(get_device_info, &params);
+    if (params.result != S_OK)
+        return params.result;
+
+    if (IsEqualPropertyKey(*prop, devicepath_key))
+        return get_device_path(&params, guid, out);
+
+    if (IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_FormFactor)) {
+        out->vt = VT_UI4;
+        out->ulVal = params.form;
+        return S_OK;
+    }
+
     return E_NOTIMPL;
 }
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c
index 8934387..3204c08 100644
--- a/dlls/winepulse.drv/pulse.c
+++ b/dlls/winepulse.drv/pulse.c
@@ -83,6 +83,10 @@ typedef struct _ACPacket
 
 typedef struct _PhysDevice {
     struct list entry;
+    enum phys_device_bus_type bus_type;
+    USHORT vendor_id, product_id;
+    EndpointFormFactor form;
+    UINT index;
     char device[0];
 } PhysDevice;
 
@@ -468,7 +472,33 @@ done:
     free(wname);
 }
 
-static void pulse_add_device(struct list *list, const char *device)
+static void fill_device_info(PhysDevice *dev, pa_proplist *p)
+{
+    const char *buffer;
+
+    dev->bus_type = phys_device_bus_invalid;
+    dev->vendor_id = 0;
+    dev->product_id = 0;
+
+    if (!p)
+        return;
+
+    if ((buffer = pa_proplist_gets(p, PA_PROP_DEVICE_BUS))) {
+        if (!strcmp(buffer, "usb"))
+            dev->bus_type = phys_device_bus_usb;
+        else if (!strcmp(buffer, "pci"))
+            dev->bus_type = phys_device_bus_pci;
+    }
+
+    if ((buffer = pa_proplist_gets(p, PA_PROP_DEVICE_VENDOR_ID)))
+        dev->vendor_id = strtol(buffer, NULL, 16);
+
+    if ((buffer = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_ID)))
+        dev->product_id = strtol(buffer, NULL, 16);
+}
+
+static void pulse_add_device(struct list *list, pa_proplist *proplist, int index, EndpointFormFactor form,
+        const char *device)
 {
     DWORD len = strlen(device);
     PhysDevice *dev = malloc(FIELD_OFFSET(PhysDevice, device[len + 1]));
@@ -476,6 +506,9 @@ static void pulse_add_device(struct list *list, const char *device)
     if (!dev)
         return;
     memcpy(dev->device, device, len + 1);
+    dev->form = form;
+    dev->index = index;
+    fill_device_info(dev, proplist);
 
     list_add_tail(list, &dev->entry);
 }
@@ -488,7 +521,7 @@ static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol
         g_phys_speakers_mask |= pulse_channel_map_to_channel_mask(&i->channel_map);
 
         store_device_info(eRender, i->name, i->description);
-        pulse_add_device(&g_phys_speakers, i->name);
+        pulse_add_device(&g_phys_speakers, i->proplist, i->index, Speakers, i->name);
     }
 }
 
@@ -496,7 +529,8 @@ static void pulse_phys_sources_cb(pa_context *c, const pa_source_info *i, int eo
 {
     if (i && i->name && i->name[0]) {
         store_device_info(eCapture, i->name, i->description);
-        pulse_add_device(&g_phys_sources, i->name);
+        pulse_add_device(&g_phys_sources, i->proplist, i->index,
+                (i->monitor_of_sink == PA_INVALID_INDEX) ? Microphone : LineLevel, i->name);
     }
 }
 
@@ -720,8 +754,8 @@ static NTSTATUS pulse_test_connect(void *args)
     g_phys_speakers_mask = 0;
 
     devices_key = open_devices_key();
-    pulse_add_device(&g_phys_speakers, "");
-    pulse_add_device(&g_phys_sources, "");
+    pulse_add_device(&g_phys_speakers, NULL, 0, Speakers, "");
+    pulse_add_device(&g_phys_sources, NULL, 0, Microphone, "");
 
     o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, NULL);
     if (o) {
@@ -768,6 +802,30 @@ fail:
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS pulse_get_device_info(void *args)
+{
+    struct get_device_info_params *params = args;
+    const struct list *const list = (params->dataflow == eRender) ? &g_phys_speakers : &g_phys_sources;
+    const char *device = params->device;
+    PhysDevice *dev;
+
+    LIST_FOR_EACH_ENTRY(dev, list, PhysDevice, entry) {
+        if (!strcmp(device, dev->device)) {
+            params->bus_type     = dev->bus_type;
+            params->vendor_id    = dev->vendor_id;
+            params->product_id   = dev->product_id;
+            params->index        = dev->index;
+            params->form         = dev->form;
+            params->result       = S_OK;
+            return STATUS_SUCCESS;
+        }
+    }
+
+    WARN("Unknown device %s\n", device);
+    params->result = E_FAIL;
+    return STATUS_SUCCESS;
+}
+
 static DWORD get_channel_mask(unsigned int channels)
 {
     switch(channels) {
@@ -2144,5 +2202,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     pulse_set_volumes,
     pulse_set_event_handle,
     pulse_test_connect,
+    pulse_get_device_info,
     pulse_is_started,
 };
diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h
index 5445a0f..7383110 100644
--- a/dlls/winepulse.drv/unixlib.h
+++ b/dlls/winepulse.drv/unixlib.h
@@ -181,6 +181,23 @@ struct test_connect_params
     struct pulse_config *config;
 };
 
+enum phys_device_bus_type {
+    phys_device_bus_invalid = -1,
+    phys_device_bus_pci,
+    phys_device_bus_usb
+};
+
+struct get_device_info_params
+{
+    char device[256];
+    EDataFlow dataflow;
+    enum phys_device_bus_type bus_type;
+    USHORT vendor_id, product_id;
+    EndpointFormFactor form;
+    UINT index;
+    HRESULT result;
+};
+
 struct is_started_params
 {
     struct pulse_stream *stream;
@@ -211,5 +228,6 @@ enum unix_funcs
     set_volumes,
     set_event_handle,
     test_connect,
+    get_device_info,
     is_started,
 };
-- 
2.34.1




More information about the wine-devel mailing list