[PATCH v4 2/3] winepulse: Return device-specific values for GetMixFormat

Claire Girka wine at gitlab.winehq.org
Mon Jul 4 05:05:38 CDT 2022


From: Claire Girka <claire at sitedethib.com>

When GetMixFormat is used, return values specific to the selected device
instead of those of the default one. This is especially useful when the
default audio device features less channels than one specifically selected
by the application.
---
 dlls/winepulse.drv/mmdevdrv.c |  9 +++++-
 dlls/winepulse.drv/pulse.c    | 55 +++++++++++++++++++++++++++++++++++
 dlls/winepulse.drv/unixlib.h  | 12 ++++++++
 3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 3cbbc1d8115..8c5d0cf7214 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -1135,6 +1135,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface,
 static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
         WAVEFORMATEX **pwfx)
 {
+    struct get_device_settings_params params;
     ACImpl *This = impl_from_IAudioClient3(iface);
 
     TRACE("(%p)->(%p)\n", This, pwfx);
@@ -1142,7 +1143,13 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface,
     if (!pwfx)
         return E_POINTER;
 
-    *pwfx = clone_format(&pulse_config.modes[This->dataflow == eCapture].format.Format);
+    params.render = This->dataflow == eRender;
+    params.pulse_name = This->pulse_name;
+    params.config = &pulse_config;
+    pulse_call(get_device_settings, &params);
+
+    *pwfx = clone_format(&params.fmt.Format);
+
     if (!*pwfx)
         return E_OUTOFMEMORY;
     dump_fmt(*pwfx);
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c
index 5a6e260c590..477876f4430 100644
--- a/dlls/winepulse.drv/pulse.c
+++ b/dlls/winepulse.drv/pulse.c
@@ -740,6 +740,33 @@ static void pulse_probe_settings(int render, const CHAR *pulse_name, WAVEFORMATE
         fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 }
 
+static NTSTATUS pulse_get_device_settings(void *args)
+{
+    struct get_device_settings_params *params = args;
+    struct pulse_config *config = params->config;
+    struct list *list = params->render ? &g_phys_speakers : &g_phys_sources;
+    PhysDevice *dev;
+
+    LIST_FOR_EACH_ENTRY(dev, list, PhysDevice, entry) {
+        if (strcmp(params->pulse_name, dev->pulse_name))
+            continue;
+
+        params->fmt = dev->fmt;
+        params->def_period = dev->def_period;
+        params->min_period = dev->min_period;
+        params->result = S_OK;
+
+        return STATUS_SUCCESS;
+    }
+
+    params->fmt = config->modes[!params->render].format;
+    params->def_period = config->modes[!params->render].def_period;
+    params->min_period = config->modes[!params->render].min_period;
+    params->result = S_OK;
+
+    return STATUS_SUCCESS;
+}
+
 /* some poorly-behaved applications call audio functions during DllMain, so we
  * have to do as much as possible without creating a new thread. this function
  * sets up a synchronous connection to verify the server is running and query
@@ -2317,6 +2344,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     pulse_test_connect,
     pulse_is_started,
     pulse_get_prop_value,
+    pulse_get_device_settings,
 };
 
 #ifdef _WIN64
@@ -2671,6 +2699,32 @@ static NTSTATUS pulse_wow64_get_prop_value(void *args)
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS pulse_wow64_get_device_settings(void *args)
+{
+    struct
+    {
+        PTR32 pulse_name;
+        PTR32 config;
+        BOOL render;
+        HRESULT result;
+        WAVEFORMATEXTENSIBLE fmt;
+        REFERENCE_TIME def_period;
+        REFERENCE_TIME min_period;
+    } *params32 = args;
+    struct get_device_settings_params params =
+    {
+        .pulse_name = ULongToPtr(params32->pulse_name),
+        .config = ULongToPtr(params32->config), /* struct pulse_config is identical */
+        .render = params32->render,
+    };
+    pulse_get_device_settings(&params);
+    params32->result = params.result;
+    params32->fmt = params.fmt;
+    params32->def_period = params.def_period;
+    params32->min_period = params.min_period;
+    return STATUS_SUCCESS;
+}
+
 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
 {
     pulse_process_attach,
@@ -2698,6 +2752,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
     pulse_wow64_test_connect,
     pulse_is_started,
     pulse_wow64_get_prop_value,
+    pulse_wow64_get_device_settings,
 };
 
 #endif /* _WIN64 */
diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h
index f224f26c909..576a0bfb326 100644
--- a/dlls/winepulse.drv/unixlib.h
+++ b/dlls/winepulse.drv/unixlib.h
@@ -159,6 +159,17 @@ struct get_current_padding_params
     UINT32 *padding;
 };
 
+struct get_device_settings_params
+{
+    const char *pulse_name;
+    struct pulse_config *config;
+    BOOL render;
+    HRESULT result;
+    WAVEFORMATEXTENSIBLE fmt;
+    REFERENCE_TIME def_period;
+    REFERENCE_TIME min_period;
+};
+
 struct get_next_packet_size_params
 {
     stream_handle stream;
@@ -252,4 +263,5 @@ enum unix_funcs
     test_connect,
     is_started,
     get_prop_value,
+    get_device_settings,
 };
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/337



More information about the wine-devel mailing list