Remove winepulse-PulseAudio_Support_old patchset

This commit is contained in:
Alistair Leslie-Hughes 2019-05-06 20:41:25 +10:00
parent f0f856a7ea
commit 5f18c8565c
8 changed files with 0 additions and 1204 deletions

View File

@ -1,151 +0,0 @@
From 97f58016012d80373a0edc1fadb7b9d6a353707b Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Wed, 4 Nov 2015 02:57:56 +0100
Subject: winepulse.drv: Use a separate mainloop and ctx for
pulse_test_connect.
---
dlls/winepulse.drv/mmdevdrv.c | 59 ++++++++++++++++++++-----------------------
1 file changed, 27 insertions(+), 32 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 1c38e58..7b1bb7c 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -369,7 +369,7 @@ static DWORD pulse_channel_map_to_channel_mask(const pa_channel_map *map) {
return mask;
}
-static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
+static void pulse_probe_settings(pa_mainloop *ml, pa_context *ctx, int render, WAVEFORMATEXTENSIBLE *fmt) {
WAVEFORMATEX *wfx = &fmt->Format;
pa_stream *stream;
pa_channel_map map;
@@ -388,7 +388,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
attr.minreq = attr.fragsize = pa_frame_size(&ss);
attr.prebuf = 0;
- stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map);
+ stream = pa_stream_new(ctx, "format test stream", &ss, &map);
if (stream)
pa_stream_set_state_callback(stream, pulse_stream_state, NULL);
if (!stream)
@@ -399,7 +399,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
else
ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS);
if (ret >= 0) {
- while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
pa_stream_get_state(stream) == PA_STREAM_CREATING)
{}
if (pa_stream_get_state(stream) == PA_STREAM_READY) {
@@ -410,7 +410,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
else
length = pa_stream_get_buffer_attr(stream)->fragsize;
pa_stream_disconnect(stream);
- while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
pa_stream_get_state(stream) == PA_STREAM_READY)
{}
}
@@ -532,10 +532,12 @@ static HRESULT pulse_test_connect(void)
WCHAR path[MAX_PATH], *name;
char *str;
pa_operation *o;
+ pa_mainloop *ml;
+ pa_context *ctx;
- pulse_ml = pa_mainloop_new();
+ ml = pa_mainloop_new();
- pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
+ pa_mainloop_set_poll_func(ml, pulse_poll_func, NULL);
GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
name = strrchrW(path, '\\');
@@ -547,24 +549,23 @@ static HRESULT pulse_test_connect(void)
str = pa_xmalloc(len);
WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
TRACE("Name: %s\n", str);
- pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
+ ctx = pa_context_new(pa_mainloop_get_api(ml), str);
pa_xfree(str);
- if (!pulse_ctx) {
+ if (!ctx) {
ERR("Failed to create context\n");
- pa_mainloop_free(pulse_ml);
- pulse_ml = NULL;
+ pa_mainloop_free(ml);
return E_FAIL;
}
- pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL);
+ pa_context_set_state_callback(ctx, pulse_contextcallback, NULL);
- TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION);
- if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0)
+ TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(ctx), PA_API_VERSION);
+ if (pa_context_connect(ctx, NULL, 0, NULL) < 0)
goto fail;
/* Wait for connection */
- while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0) {
- pa_context_state_t state = pa_context_get_state(pulse_ctx);
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0) {
+ pa_context_state_t state = pa_context_get_state(ctx);
if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
goto fail;
@@ -573,38 +574,32 @@ static HRESULT pulse_test_connect(void)
break;
}
- if (pa_context_get_state(pulse_ctx) != PA_CONTEXT_READY)
+ if (pa_context_get_state(ctx) != PA_CONTEXT_READY)
goto fail;
TRACE("Test-connected to server %s with protocol version: %i.\n",
- pa_context_get_server(pulse_ctx),
- pa_context_get_server_protocol_version(pulse_ctx));
+ pa_context_get_server(ctx),
+ pa_context_get_server_protocol_version(ctx));
- pulse_probe_settings(1, &pulse_fmt[0]);
- pulse_probe_settings(0, &pulse_fmt[1]);
+ pulse_probe_settings(ml, ctx, 1, &pulse_fmt[0]);
+ pulse_probe_settings(ml, ctx, 0, &pulse_fmt[1]);
g_phys_speakers_mask = 0;
- o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, NULL);
+ o = pa_context_get_sink_info_list(ctx, &pulse_phys_speakers_cb, NULL);
if (o) {
- while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
pa_operation_get_state(o) == PA_OPERATION_RUNNING)
{}
pa_operation_unref(o);
}
- pa_context_unref(pulse_ctx);
- pulse_ctx = NULL;
- pa_mainloop_free(pulse_ml);
- pulse_ml = NULL;
-
+ pa_context_unref(ctx);
+ pa_mainloop_free(ml);
return S_OK;
fail:
- pa_context_unref(pulse_ctx);
- pulse_ctx = NULL;
- pa_mainloop_free(pulse_ml);
- pulse_ml = NULL;
-
+ pa_context_unref(ctx);
+ pa_mainloop_free(ml);
return E_FAIL;
}
--
2.7.1

View File

@ -1,416 +0,0 @@
From 50f78e94f4cf277297ee04479d050526b100e319 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Mon, 3 Nov 2014 02:06:40 +0000
Subject: winepulse: expose audio devices directly to programs
At present, winepulse only exposes one input device and one output device. This
patch adds support for individual audio devices, allowing (among other things)
the same program to record from two devices at the same time. It also brings
winepulse more in line with both winealsa et al. and Windows itself. The
moveable "Pulseaudio" devices are still present, and should presumably be
used by default.
Changes by Sebastian Lackner <sebastian@fds-team.de>:
* Merge functions set_device_guid and get_device_guid as they are always used together
* Fixed compiler warnings with -Werror
* Some style fixes and better error handling
* Move initialization code to pulse_test_connect()
---
dlls/winepulse.drv/mmdevdrv.c | 260 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 230 insertions(+), 30 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index c23656e..d57e528 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -79,12 +79,25 @@ static pthread_mutex_t pulse_lock;
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
static struct list g_sessions = LIST_INIT(g_sessions);
+typedef struct _PhysDevice {
+ struct list entry;
+ GUID guid;
+ WCHAR name[0];
+} PhysDevice;
+
static UINT g_phys_speakers_mask = 0;
+static struct list g_phys_speakers = LIST_INIT(g_phys_speakers);
+static struct list g_phys_sources = LIST_INIT(g_phys_sources);
/* Mixer format + period times */
static WAVEFORMATEXTENSIBLE pulse_fmt[2];
static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
+static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\',
+ 'W','i','n','e','\\','D','r','i','v','e','r','s','\\',
+ 'w','i','n','e','p','u','l','s','e','.','d','r','v','\\','d','e','v','i','c','e','s',0};
+static const WCHAR guidW[] = {'g','u','i','d',0};
+
static GUID pulse_render_guid =
{ 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
static GUID pulse_capture_guid =
@@ -103,6 +116,13 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
if (pthread_mutex_init(&pulse_lock, &attr) != 0)
pthread_mutex_init(&pulse_lock, NULL);
} else if (reason == DLL_PROCESS_DETACH) {
+ PhysDevice *dev, *dev_next;
+
+ LIST_FOR_EACH_ENTRY_SAFE(dev, dev_next, &g_phys_speakers, PhysDevice, entry)
+ HeapFree(GetProcessHeap(), 0, dev);
+ LIST_FOR_EACH_ENTRY_SAFE(dev, dev_next, &g_phys_sources, PhysDevice, entry)
+ HeapFree(GetProcessHeap(), 0, dev);
+
if (pulse_thread)
SetThreadPriority(pulse_thread, 0);
if (pulse_ctx) {
@@ -164,6 +184,7 @@ struct ACImpl {
IMMDevice *parent;
struct list entry;
float vol[PA_CHANNELS_MAX];
+ char device[256];
LONG ref;
EDataFlow dataflow;
@@ -190,8 +211,6 @@ struct ACImpl {
struct list packet_filled_head;
};
-static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0};
-
static const IAudioClientVtbl AudioClient_Vtbl;
static const IAudioRenderClientVtbl AudioRenderClient_Vtbl;
static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl;
@@ -514,12 +533,92 @@ fail:
return E_FAIL;
}
-/* For default PulseAudio render device, OR together all of the
- * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
+static BOOL get_device_guid(EDataFlow flow, const char *device, GUID *guid)
+{
+ HKEY key, dev_key;
+ DWORD type, size = sizeof(*guid);
+ WCHAR key_name[258];
+
+ key_name[0] = (flow == eCapture) ? '1' : '0';
+ key_name[1] = ',';
+ if (!MultiByteToWideChar(CP_UTF8, 0, device, -1, key_name + 2,
+ (sizeof(key_name) / sizeof(*key_name)) - 2))
+ return FALSE;
+
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0,
+ KEY_WRITE|KEY_READ, NULL, &key, NULL) != ERROR_SUCCESS){
+ ERR("Failed to open registry key %s\n", debugstr_w(drv_key_devicesW));
+ return FALSE;
+ }
+
+ if (RegCreateKeyExW(key, key_name, 0, NULL, 0, KEY_WRITE|KEY_READ,
+ NULL, &dev_key, NULL) != ERROR_SUCCESS){
+ ERR("Failed to open registry key for device %s\n", debugstr_w(key_name));
+ RegCloseKey(key);
+ return FALSE;
+ }
+
+ if (RegQueryValueExW(dev_key, guidW, 0, &type, (BYTE *)guid,
+ &size) == ERROR_SUCCESS){
+ if (type == REG_BINARY && size == sizeof(*guid)){
+ RegCloseKey(dev_key);
+ RegCloseKey(key);
+ return TRUE;
+ }
+
+ ERR("Invalid type for device %s GUID: %u; ignoring and overwriting\n",
+ wine_dbgstr_w(key_name), type);
+ }
+
+ /* generate new GUID for this device */
+ CoCreateGuid(guid);
+
+ if (RegSetValueExW(dev_key, guidW, 0, REG_BINARY, (BYTE *)guid,
+ sizeof(GUID)) != ERROR_SUCCESS)
+ ERR("Failed to store device GUID for %s to registry\n", device);
+
+ RegCloseKey(dev_key);
+ RegCloseKey(key);
+ return TRUE;
+}
+
+static void pulse_add_device(struct list *list, GUID *guid, const char *name)
+{
+ int len = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, NULL, 0);
+ if (len) {
+ PhysDevice *dev = HeapAlloc(GetProcessHeap(), 0, offsetof(PhysDevice, name[len]));
+ if (dev) {
+ MultiByteToWideChar(CP_UNIXCP, 0, name, -1, dev->name, len);
+ dev->guid = *guid;
+ list_add_tail(list, &dev->entry);
+ }
+ }
+}
+
static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
{
- if (i)
+ GUID guid;
+
+ if (i) {
+ /* For default PulseAudio render device, OR together all of the
+ * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
g_phys_speakers_mask |= pulse_channel_map_to_channel_mask(&i->channel_map);
+
+ if (!get_device_guid(eRender, i->name, &guid))
+ CoCreateGuid(&guid);
+ pulse_add_device(&g_phys_speakers, &guid, i->description);
+ }
+}
+
+static void pulse_phys_sources_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata)
+{
+ GUID guid;
+
+ if (i) {
+ if (!get_device_guid(eCapture, i->name, &guid))
+ CoCreateGuid(&guid);
+ pulse_add_device(&g_phys_sources, &guid, i->description);
+ }
}
/* some poorly-behaved applications call audio functions during DllMain, so we
@@ -535,6 +634,10 @@ static HRESULT pulse_test_connect(void)
pa_mainloop *ml;
pa_context *ctx;
+ /* Make sure we never run this function twice accidentially */
+ if (!list_empty(&g_phys_speakers))
+ return S_OK;
+
ml = pa_mainloop_new();
pa_mainloop_set_poll_func(ml, pulse_poll_func, NULL);
@@ -585,6 +688,9 @@ static HRESULT pulse_test_connect(void)
pulse_probe_settings(ml, ctx, 0, &pulse_fmt[1]);
g_phys_speakers_mask = 0;
+ pulse_add_device(&g_phys_speakers, &pulse_render_guid, "Pulseaudio");
+ pulse_add_device(&g_phys_sources, &pulse_capture_guid, "Pulseaudio");
+
o = pa_context_get_sink_info_list(ctx, &pulse_phys_speakers_cb, NULL);
if (o) {
while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
@@ -593,6 +699,14 @@ static HRESULT pulse_test_connect(void)
pa_operation_unref(o);
}
+ o = pa_context_get_source_info_list(ctx, &pulse_phys_sources_cb, NULL);
+ if (o) {
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
+ pa_operation_get_state(o) == PA_OPERATION_RUNNING)
+ {}
+ pa_operation_unref(o);
+ }
+
pa_context_unref(ctx);
pa_mainloop_free(ml);
return S_OK;
@@ -852,6 +966,9 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
char buffer[64];
static LONG number;
pa_buffer_attr attr;
+ int moving = 0;
+ const char *dev = NULL;
+
if (This->stream) {
pa_stream_disconnect(This->stream);
while (pa_stream_get_state(This->stream) == PA_STREAM_READY)
@@ -876,12 +993,21 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
attr.maxlength = attr.tlength = This->bufsize_bytes;
attr.prebuf = pa_frame_size(&This->ss);
dump_attr(&attr);
+
+ /* If device name is given use exactly the specified device */
+ if (This->device[0]){
+ moving = PA_STREAM_DONT_MOVE;
+ dev = This->device;
+ }
+
if (This->dataflow == eRender)
- ret = pa_stream_connect_playback(This->stream, NULL, &attr,
- PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
+ ret = pa_stream_connect_playback(This->stream, dev, &attr,
+ PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|
+ PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS|moving, NULL, NULL);
else
- ret = pa_stream_connect_record(This->stream, NULL, &attr,
- PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS);
+ ret = pa_stream_connect_record(This->stream, dev, &attr,
+ PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|
+ PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS|moving);
if (ret < 0) {
WARN("Returns %i\n", ret);
return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
@@ -900,39 +1026,53 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
return S_OK;
}
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys,
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **keys,
UINT *num, UINT *def_index)
{
+ struct list *list = (flow == eRender) ? &g_phys_speakers : &g_phys_sources;
+ PhysDevice *dev;
+ DWORD count;
WCHAR *id;
TRACE("%d %p %p %p\n", flow, ids, num, def_index);
- *num = 1;
+ *num = count = list_count(list);
*def_index = 0;
- *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids));
- *keys = NULL;
- if (!*ids)
- return E_OUTOFMEMORY;
-
- (*ids)[0] = id = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
- *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys));
- if (!*keys || !id) {
- HeapFree(GetProcessHeap(), 0, id);
- HeapFree(GetProcessHeap(), 0, *keys);
- HeapFree(GetProcessHeap(), 0, *ids);
+ if (!count) {
*ids = NULL;
*keys = NULL;
- return E_OUTOFMEMORY;
+ return E_FAIL;
}
- memcpy(id, defaultW, sizeof(defaultW));
- if (flow == eRender)
- (*keys)[0] = pulse_render_guid;
- else
- (*keys)[0] = pulse_capture_guid;
+ *ids = HeapAlloc(GetProcessHeap(), 0, count * sizeof(**ids));
+ *keys = HeapAlloc(GetProcessHeap(), 0, count * sizeof(**keys));
+ if (!*ids || !*keys) {
+ count = 0;
+ goto err;
+ }
+
+ count = 0;
+ LIST_FOR_EACH_ENTRY(dev, list, PhysDevice, entry) {
+ id = HeapAlloc(GetProcessHeap(), 0, (strlenW(dev->name) + 1) * sizeof(WCHAR));
+ if (!id)
+ goto err;
+ (*ids)[count] = id;
+ (*keys)[count] = dev->guid;
+ strcpyW(id, dev->name);
+ count++;
+ }
return S_OK;
+
+err:
+ while (count)
+ HeapFree(GetProcessHeap(), 0, (*ids)[--count]);
+ HeapFree(GetProcessHeap(), 0, *keys);
+ HeapFree(GetProcessHeap(), 0, *ids);
+ *ids = NULL;
+ *keys = NULL;
+ return E_OUTOFMEMORY;
}
int WINAPI AUDDRV_GetPriority(void)
@@ -944,20 +1084,79 @@ int WINAPI AUDDRV_GetPriority(void)
return SUCCEEDED(hr) ? Priority_Preferred : Priority_Unavailable;
}
+static BOOL get_pulse_name_by_guid(const GUID *guid, char *name, DWORD name_size, EDataFlow *flow)
+{
+ HKEY key;
+ DWORD index = 0;
+ WCHAR key_name[258];
+ DWORD key_name_size;
+
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ,
+ &key) != ERROR_SUCCESS){
+ ERR("No devices found in registry?\n");
+ return FALSE;
+ }
+
+ while(1){
+ HKEY dev_key;
+ DWORD size, type;
+ GUID reg_guid;
+
+ key_name_size = sizeof(key_name)/sizeof(WCHAR);
+ if(RegEnumKeyExW(key, index++, key_name, &key_name_size, NULL,
+ NULL, NULL, NULL) != ERROR_SUCCESS)
+ break;
+
+ if (RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) != ERROR_SUCCESS){
+ ERR("Couldn't open key: %s\n", wine_dbgstr_w(key_name));
+ continue;
+ }
+
+ size = sizeof(reg_guid);
+ if (RegQueryValueExW(dev_key, guidW, 0, &type, (BYTE *)&reg_guid, &size) == ERROR_SUCCESS){
+ if (type == REG_BINARY && size == sizeof(reg_guid) && IsEqualGUID(&reg_guid, guid)){
+ RegCloseKey(dev_key);
+ RegCloseKey(key);
+
+ TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name));
+
+ if (key_name[0] == '0')
+ *flow = eRender;
+ else if (key_name[0] == '1')
+ *flow = eCapture;
+ else{
+ ERR("Unknown device type: %c\n", key_name[0]);
+ return FALSE;
+ }
+
+ return WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL);
+ }
+ }
+
+ RegCloseKey(dev_key);
+ }
+
+ RegCloseKey(key);
+ WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid));
+ return FALSE;
+}
+
HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
{
+ char pulse_name[256] = {0};
ACImpl *This;
int i;
EDataFlow dataflow;
HRESULT hr;
TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
+
if (IsEqualGUID(guid, &pulse_render_guid))
dataflow = eRender;
else if (IsEqualGUID(guid, &pulse_capture_guid))
dataflow = eCapture;
- else
- return E_UNEXPECTED;
+ else if(!get_pulse_name_by_guid(guid, pulse_name, sizeof(pulse_name), &dataflow))
+ return AUDCLNT_E_DEVICE_INVALIDATED;
*out = NULL;
@@ -975,6 +1174,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
This->parent = dev;
for (i = 0; i < PA_CHANNELS_MAX; ++i)
This->vol[i] = 1.f;
+ strcpy(This->device, pulse_name);
hr = CoCreateFreeThreadedMarshaler((IUnknown*)&This->IAudioClient_iface, &This->marshal);
if (hr) {
--
2.9.0

View File

@ -1,109 +0,0 @@
From cdce4bcc5ef26e60400ba611421c2d79decaf519 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Tue, 18 Nov 2014 18:35:31 +0000
Subject: winepulse: implement exclusive mode
---
dlls/mmdevapi/tests/render.c | 5 +++--
dlls/winepulse.drv/mmdevdrv.c | 46 ++++++++++++++++++-------------------------
2 files changed, 22 insertions(+), 29 deletions(-)
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c
index 9c42f3a..77d024f 100644
--- a/dlls/mmdevapi/tests/render.c
+++ b/dlls/mmdevapi/tests/render.c
@@ -952,8 +952,9 @@ static void test_clock(int share)
ok(gbsize == bufsize,
"BufferSize %u at rate %u\n", gbsize, pwfx->nSamplesPerSec);
else
- ok(gbsize == parts * fragment || gbsize == MulDiv(bufsize, 1, 1024) * 1024,
- "BufferSize %u misfits fragment size %u at rate %u\n", gbsize, fragment, pwfx->nSamplesPerSec);
+ todo_wine
+ ok(gbsize == parts * fragment || gbsize == MulDiv(bufsize, 1, 1024) * 1024,
+ "BufferSize %u misfits fragment size %u at rate %u\n", gbsize, fragment, pwfx->nSamplesPerSec);
/* In shared mode, GetCurrentPadding decreases in multiples of
* fragment size (i.e. updated only at period ticks), whereas
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index f8f9f18..7c76e89 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -1510,6 +1510,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
const GUID *sessionguid)
{
ACImpl *This = impl_from_IAudioClient(iface);
+ REFERENCE_TIME def, min;
HRESULT hr = S_OK;
UINT period_bytes;
@@ -1521,8 +1522,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
return AUDCLNT_E_NOT_INITIALIZED;
- if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
- return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
AUDCLNT_STREAMFLAGS_LOOPBACK |
@@ -1556,27 +1555,26 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
if (FAILED(hr))
goto exit;
- if (mode == AUDCLNT_SHAREMODE_SHARED) {
- REFERENCE_TIME def = pulse_def_period[This->dataflow == eCapture];
- REFERENCE_TIME min = pulse_min_period[This->dataflow == eCapture];
+ def = pulse_def_period[This->dataflow == eCapture];
+ min = pulse_min_period[This->dataflow == eCapture];
- /* Switch to low latency mode if below 2 default periods,
- * which is 20 ms by default, this will increase the amount
- * of interrupts but allows very low latency. In dsound I
- * managed to get a total latency of ~8ms, which is well below
- * default
- */
- if (duration < 2 * def)
- period = min;
- else
- period = def;
- if (duration < 2 * period)
- duration = 2 * period;
+ /* Switch to low latency mode if below 2 default periods,
+ * which is 20 ms by default, this will increase the amount
+ * of interrupts but allows very low latency. In dsound I
+ * managed to get a total latency of ~8ms, which is well below
+ * default
+ */
+ if (duration < 2 * def)
+ period = min;
+ else
+ period = def;
+ if (duration < 2 * period)
+ duration = 2 * period;
+
+ /* Uh oh, really low latency requested.. */
+ if (duration <= 2 * period)
+ period /= 2;
- /* Uh oh, really low latency requested.. */
- if (duration <= 2 * period)
- period /= 2;
- }
period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
if (duration < 20000000)
@@ -1892,12 +1890,6 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
else
*out = closest;
- /* Winepulse does not currently support exclusive mode, if you know of an
- * application that uses it, I will correct this..
- */
- if (hr == S_OK && exclusive)
- return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
-
TRACE("returning: %08x %p\n", hr, out ? *out : NULL);
return hr;
}
--
2.8.0

View File

@ -1,24 +0,0 @@
From 604101f933555f08d75d54cbb1fe016eff1b02e5 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Tue, 18 Nov 2014 18:39:58 +0000
Subject: winepulse: fix segfault in pulse_rd_loop
---
dlls/winepulse.drv/mmdevdrv.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index 5c00a88..c6f4830 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -790,6 +790,7 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
size_t src_len, copy, rem = This->capture_period;
if (!(p = (ACPacket*)list_head(&This->packet_free_head))) {
p = (ACPacket*)list_head(&This->packet_filled_head);
+ if (!p) return;
if (!p->discont) {
next = (ACPacket*)p->entry.next;
next->discont = 1;
--
2.6.2

View File

@ -1,197 +0,0 @@
From 8ef6739f373d4e7a23da7280e9fcaedc6b594f37 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Thu, 4 Dec 2014 21:36:42 +0000
Subject: winepulse: implement GetPropValue
---
dlls/winepulse.drv/mmdevdrv.c | 116 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 109 insertions(+), 7 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index c6f4830..f9f421a 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -82,6 +82,8 @@ static struct list g_sessions = LIST_INIT(g_sessions);
typedef struct _PhysDevice {
struct list entry;
GUID guid;
+ EndpointFormFactor form;
+ WCHAR device[128];
WCHAR name[0];
} PhysDevice;
@@ -572,14 +574,67 @@ static BOOL get_device_guid(EDataFlow flow, const char *device, GUID *guid)
return TRUE;
}
-static void pulse_add_device(struct list *list, GUID *guid, const char *name)
+static BOOL get_device_path(pa_proplist *p, int index, GUID *guid, WCHAR path[128])
{
+ static const WCHAR usbformatW[] = { '{','1','}','.','U','S','B','\\','V','I','D','_',
+ '%','0','4','X','&','P','I','D','_','%','0','4','X','\\',
+ '%','u','&','%','0','8','X',0 }; /* "{1}.USB\VID_%04X&PID_%04X\%u&%08X" */
+ static const WCHAR pciformatW[] = { '{','1','}','.','H','D','A','U','D','I','O','\\','F','U','N','C','_','0','1','&',
+ 'V','E','N','_','%','0','4','X','&','D','E','V','_',
+ '%','0','4','X','\\','%','u','&','%','0','8','X',0 }; /* "{1}.HDAUDIO\FUNC_01&VEN_%04X&DEV_%04X\%u&%08X" */
+
+ USHORT vendor_id, product_id;
+ const char *buffer;
+ UINT serial_number;
+ BOOL is_usb;
+
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
+ if (!buffer)
+ return FALSE;
+
+ if (!strcmp(buffer,"usb"))
+ is_usb = TRUE;
+ else if (!strcmp(buffer,"pci"))
+ is_usb = FALSE;
+ else
+ return FALSE;
+
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_VENDOR_ID);
+ if (buffer)
+ vendor_id = strtol(buffer, NULL, 16);
+ else
+ return FALSE;
+
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_ID);
+ if (buffer)
+ product_id = strtol(buffer, NULL, 16);
+ else
+ return FALSE;
+
+ /* 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];
+
+ if (is_usb)
+ sprintfW( path, usbformatW, vendor_id, product_id, index, serial_number);
+ else
+ sprintfW( path, pciformatW, vendor_id, product_id, index, serial_number);
+
+ return TRUE;
+}
+
+static void pulse_add_device(struct list *list, GUID *guid, EndpointFormFactor form, WCHAR device[128], const char *name)
+{
+ static const WCHAR emptyW[] = {0};
int len = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, NULL, 0);
if (len) {
PhysDevice *dev = HeapAlloc(GetProcessHeap(), 0, offsetof(PhysDevice, name[len]));
if (dev) {
- MultiByteToWideChar(CP_UNIXCP, 0, name, -1, dev->name, len);
dev->guid = *guid;
+ dev->form = form;
+ strcpyW(dev->device, device ? device : emptyW);
+ MultiByteToWideChar(CP_UNIXCP, 0, name, -1, dev->name, len);
list_add_tail(list, &dev->entry);
}
}
@@ -587,6 +642,7 @@ static void pulse_add_device(struct list *list, GUID *guid, const char *name)
static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
{
+ WCHAR device[128];
GUID guid;
if (i) {
@@ -596,18 +652,25 @@ static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol
if (!get_device_guid(eRender, i->name, &guid))
CoCreateGuid(&guid);
- pulse_add_device(&g_phys_speakers, &guid, i->description);
+ if (!get_device_path(i->proplist, i->index, &guid, device))
+ device[0] = 0;
+ pulse_add_device(&g_phys_speakers, &guid, Speakers, device, i->description);
}
}
static void pulse_phys_sources_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata)
{
+ EndpointFormFactor form;
+ WCHAR device[128];
GUID guid;
if (i) {
+ form = (i->monitor_of_sink == PA_INVALID_INDEX) ? Microphone : LineLevel;
if (!get_device_guid(eCapture, i->name, &guid))
CoCreateGuid(&guid);
- pulse_add_device(&g_phys_sources, &guid, i->description);
+ if (!get_device_path(i->proplist, i->index, &guid, device))
+ device[0] = 0;
+ pulse_add_device(&g_phys_sources, &guid, form, device, i->description);
}
}
@@ -675,8 +738,8 @@ static HRESULT pulse_test_connect(void)
pulse_probe_settings(ml, ctx, 0, &pulse_fmt[1]);
g_phys_speakers_mask = 0;
- pulse_add_device(&g_phys_speakers, &pulse_render_guid, "Pulseaudio");
- pulse_add_device(&g_phys_sources, &pulse_capture_guid, "Pulseaudio");
+ pulse_add_device(&g_phys_speakers, &pulse_render_guid, Speakers, NULL, "Pulseaudio");
+ pulse_add_device(&g_phys_sources, &pulse_capture_guid, Microphone, NULL, "Pulseaudio");
o = pa_context_get_sink_info_list(ctx, &pulse_phys_speakers_cb, NULL);
if (o) {
@@ -3418,8 +3481,36 @@ HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
return S_OK;
}
+static const PROPERTYKEY devicepath_key = { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */
+ {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2
+};
+
+static HRESULT pulse_device_get_prop_value(PhysDevice *dev, const PROPERTYKEY *prop, PROPVARIANT *out)
+{
+ if (IsEqualPropertyKey(*prop, devicepath_key)) {
+ if (!dev->device[0])
+ return E_FAIL;
+
+ out->vt = VT_LPWSTR;
+ out->u.pwszVal = CoTaskMemAlloc((strlenW(dev->device) + 1) * sizeof(WCHAR));
+ if (!out->u.pwszVal)
+ return E_OUTOFMEMORY;
+
+ strcpyW(out->u.pwszVal, dev->device);
+ return S_OK;
+ } else if (IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_FormFactor)) {
+ out->vt = VT_UI4;
+ out->u.ulVal = dev->form;
+ return S_OK;
+ }
+
+ return E_NOTIMPL;
+}
+
HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
{
+ PhysDevice *dev;
+
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)) {
@@ -3429,5 +3520,16 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI
return out->u.ulVal ? S_OK : E_FAIL;
}
- return E_NOTIMPL;
+ LIST_FOR_EACH_ENTRY(dev, &g_phys_speakers, PhysDevice, entry) {
+ if (IsEqualGUID(guid, &dev->guid))
+ return pulse_device_get_prop_value(dev, prop, out);
+ }
+
+ LIST_FOR_EACH_ENTRY(dev, &g_phys_sources, PhysDevice, entry) {
+ if (IsEqualGUID(guid, &dev->guid))
+ return pulse_device_get_prop_value(dev, prop, out);
+ }
+
+ WARN("Unknown GUID %s\n", debugstr_guid(guid));
+ return E_FAIL;
}
--
2.6.2

View File

@ -1,177 +0,0 @@
From f6619eb1fb100c8f6f39b4828030434f0aab9a38 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Sun, 21 Dec 2014 23:49:41 +0000
Subject: winepulse: fetch actual program name if possible
Changes by Sebastian Lackner <sebastian@fds-team.de>:
* Improved error handling, fix memory leak
* Remove check for UTF16, there are several examples where this doesn't work
(for example with VLC media player)
* Simplify algorithm to choose best translation.
---
dlls/winepulse.drv/Makefile.in | 2 +-
dlls/winepulse.drv/mmdevdrv.c | 123 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 116 insertions(+), 9 deletions(-)
diff --git a/dlls/winepulse.drv/Makefile.in b/dlls/winepulse.drv/Makefile.in
index d660063..2448789 100644
--- a/dlls/winepulse.drv/Makefile.in
+++ b/dlls/winepulse.drv/Makefile.in
@@ -1,5 +1,5 @@
MODULE = winepulse.drv
-IMPORTS = dxguid uuid winmm user32 advapi32 ole32
+IMPORTS = dxguid uuid winmm user32 advapi32 ole32 version
EXTRALIBS = $(PULSE_LIBS) $(PTHREAD_LIBS)
EXTRAINCL = $(PULSE_CFLAGS)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index bf9f3c0..2f20873 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -43,6 +43,7 @@
#include "wine/list.h"
#include "ole2.h"
+#include "mimeole.h"
#include "dshow.h"
#include "dsound.h"
#include "propsys.h"
@@ -468,6 +469,109 @@ static void pulse_probe_settings(pa_mainloop *ml, pa_context *ctx, int render, W
fmt->dwChannelMask = pulse_channel_map_to_channel_mask(&map);
}
+typedef struct tagLANGANDCODEPAGE
+{
+ WORD wLanguage;
+ WORD wCodePage;
+} LANGANDCODEPAGE;
+
+static BOOL query_productname(void *data, LANGANDCODEPAGE *lang, LPVOID *buffer, DWORD *len)
+{
+ static const WCHAR productnameW[] = {'\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
+ '\\','%','0','4','x','%','0','4','x',
+ '\\','P','r','o','d','u','c','t','N','a','m','e',0};
+ WCHAR pn[37];
+ sprintfW(pn, productnameW, lang->wLanguage, lang->wCodePage);
+ return VerQueryValueW(data, pn, buffer, len) && *len;
+}
+
+static char* get_programname(WCHAR *path)
+{
+ static const WCHAR translationW[] = {'\\','V','a','r','F','i','l','e','I','n','f','o',
+ '\\','T','r','a','n','s','l','a','t','i','o','n',0};
+ UINT translate_size, productname_size;
+ LANGANDCODEPAGE *translate;
+ LPVOID productname;
+ BOOL found = FALSE;
+ void *data = NULL;
+ char *ret = NULL;
+ unsigned int i;
+ LCID locale;
+ DWORD size;
+
+ size = GetFileVersionInfoSizeW(path, NULL);
+ if (!size)
+ goto out;
+
+ data = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!data)
+ goto out;
+
+ if (!GetFileVersionInfoW(path, 0, size, data))
+ goto out;
+
+ if (!VerQueryValueW(data, translationW, (LPVOID *)&translate, &translate_size))
+ goto out;
+
+ /* no translations found */
+ if (translate_size < sizeof(LANGANDCODEPAGE))
+ goto out;
+
+ /* The following code will try to find the best translation. We first search for an
+ * exact match of the language, then a match of the language PRIMARYLANGID, then we
+ * search for a LANG_NEUTRAL match, and if that still doesn't work we pick the
+ * first entry which contains a proper productname. */
+
+ locale = GetThreadLocale();
+
+ for (i = 0; i < translate_size / sizeof(LANGANDCODEPAGE); i++) {
+ if (translate[i].wLanguage == locale &&
+ query_productname(data, &translate[i], &productname, &productname_size)) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ for (i = 0; i < translate_size / sizeof(LANGANDCODEPAGE); i++) {
+ if (PRIMARYLANGID(translate[i].wLanguage) == PRIMARYLANGID(locale) &&
+ query_productname(data, &translate[i], &productname, &productname_size)) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ for (i = 0; i < translate_size / sizeof(LANGANDCODEPAGE); i++) {
+ if (PRIMARYLANGID(translate[i].wLanguage) == LANG_NEUTRAL &&
+ query_productname(data, &translate[i], &productname, &productname_size)) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ for (i = 0; i < translate_size / sizeof(LANGANDCODEPAGE); i++) {
+ if (query_productname(data, &translate[i], &productname, &productname_size)) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ int len = WideCharToMultiByte(CP_UTF8, 0, productname, -1, NULL, 0, NULL, NULL);
+ ret = pa_xmalloc(len);
+ if (ret) WideCharToMultiByte(CP_UTF8, 0, productname, -1, ret, len, NULL, NULL);
+ }
+
+out:
+ HeapFree(GetProcessHeap(), 0, data);
+ return ret;
+}
+
static HRESULT pulse_connect(void)
{
int len;
@@ -491,14 +595,17 @@ static HRESULT pulse_connect(void)
pa_context_unref(pulse_ctx);
GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
- name = strrchrW(path, '\\');
- if (!name)
- name = path;
- else
- name++;
- len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
- str = pa_xmalloc(len);
- WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
+ str = get_programname(path);
+ if (!str) {
+ name = strrchrW(path, '\\');
+ if (!name)
+ name = path;
+ else
+ name++;
+ len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL);
+ str = pa_xmalloc(len);
+ WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL);
+ }
TRACE("Name: %s\n", str);
pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
pa_xfree(str);
--
2.7.1

View File

@ -1,123 +0,0 @@
From cf16191045db5ad2278c43730453405c7935ab29 Mon Sep 17 00:00:00 2001
From: Mark Harmstone <mark@harmstone.com>
Date: Wed, 10 Dec 2014 18:08:41 +0000
Subject: winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop
Changes by Sebastian Lackner <sebastian@fds-team.de>:
* Rework logic to get all channel masks in pulse_test_connect.
---
dlls/winepulse.drv/mmdevdrv.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
index ca60dcb..03cfed5 100644
--- a/dlls/winepulse.drv/mmdevdrv.c
+++ b/dlls/winepulse.drv/mmdevdrv.c
@@ -84,11 +84,11 @@ typedef struct _PhysDevice {
struct list entry;
GUID guid;
EndpointFormFactor form;
+ DWORD channel_mask;
WCHAR device[128];
WCHAR name[0];
} PhysDevice;
-static UINT g_phys_speakers_mask = 0;
static struct list g_phys_speakers = LIST_INIT(g_phys_speakers);
static struct list g_phys_sources = LIST_INIT(g_phys_sources);
@@ -731,7 +731,8 @@ static BOOL get_device_path(pa_proplist *p, int index, GUID *guid, WCHAR path[12
return TRUE;
}
-static void pulse_add_device(struct list *list, GUID *guid, EndpointFormFactor form, WCHAR device[128], const char *name)
+static void pulse_add_device(struct list *list, GUID *guid, EndpointFormFactor form, DWORD channel_mask,
+ WCHAR device[128], const char *name)
{
static const WCHAR emptyW[] = {0};
int len = MultiByteToWideChar(CP_UNIXCP, 0, name, -1, NULL, 0);
@@ -740,6 +741,7 @@ static void pulse_add_device(struct list *list, GUID *guid, EndpointFormFactor f
if (dev) {
dev->guid = *guid;
dev->form = form;
+ dev->channel_mask = channel_mask;
strcpyW(dev->device, device ? device : emptyW);
MultiByteToWideChar(CP_UNIXCP, 0, name, -1, dev->name, len);
list_add_tail(list, &dev->entry);
@@ -749,19 +751,25 @@ static void pulse_add_device(struct list *list, GUID *guid, EndpointFormFactor f
static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
{
+ struct list *speaker;
+ DWORD channel_mask;
WCHAR device[128];
GUID guid;
if (i) {
+ channel_mask = pulse_channel_map_to_channel_mask(&i->channel_map);
+
/* For default PulseAudio render device, OR together all of the
* PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
- g_phys_speakers_mask |= pulse_channel_map_to_channel_mask(&i->channel_map);
+ speaker = list_head(&g_phys_speakers);
+ if (speaker)
+ LIST_ENTRY(speaker, PhysDevice, entry)->channel_mask |= channel_mask;
if (!get_device_guid(eRender, i->name, &guid))
CoCreateGuid(&guid);
if (!get_device_path(i->proplist, i->index, &guid, device))
device[0] = 0;
- pulse_add_device(&g_phys_speakers, &guid, Speakers, device, i->description);
+ pulse_add_device(&g_phys_speakers, &guid, Speakers, channel_mask, device, i->description);
}
}
@@ -777,7 +785,7 @@ static void pulse_phys_sources_cb(pa_context *c, const pa_source_info *i, int eo
CoCreateGuid(&guid);
if (!get_device_path(i->proplist, i->index, &guid, device))
device[0] = 0;
- pulse_add_device(&g_phys_sources, &guid, form, device, i->description);
+ pulse_add_device(&g_phys_sources, &guid, form, 0, device, i->description);
}
}
@@ -844,9 +852,8 @@ static HRESULT pulse_test_connect(void)
pulse_probe_settings(ml, ctx, 1, &pulse_fmt[0]);
pulse_probe_settings(ml, ctx, 0, &pulse_fmt[1]);
- g_phys_speakers_mask = 0;
- pulse_add_device(&g_phys_speakers, &pulse_render_guid, Speakers, NULL, "Pulseaudio");
- pulse_add_device(&g_phys_sources, &pulse_capture_guid, Microphone, NULL, "Pulseaudio");
+ pulse_add_device(&g_phys_speakers, &pulse_render_guid, Speakers, 0, NULL, "Pulseaudio");
+ pulse_add_device(&g_phys_sources, &pulse_capture_guid, Microphone, 0, NULL, "Pulseaudio");
o = pa_context_get_sink_info_list(ctx, &pulse_phys_speakers_cb, NULL);
if (o) {
@@ -3609,6 +3616,10 @@ static HRESULT pulse_device_get_prop_value(PhysDevice *dev, const PROPERTYKEY *p
out->vt = VT_UI4;
out->u.ulVal = dev->form;
return S_OK;
+ } else if (IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) {
+ out->vt = VT_UI4;
+ out->u.ulVal = dev->channel_mask;
+ return out->u.ulVal ? S_OK : E_FAIL;
}
return E_NOTIMPL;
@@ -3620,13 +3631,6 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI
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)) {
- out->vt = VT_UI4;
- out->u.ulVal = g_phys_speakers_mask;
-
- return out->u.ulVal ? S_OK : E_FAIL;
- }
-
LIST_FOR_EACH_ENTRY(dev, &g_phys_speakers, PhysDevice, entry) {
if (IsEqualGUID(guid, &dev->guid))
return pulse_device_get_prop_value(dev, prop, out);
--
2.6.2

View File

@ -1,7 +0,0 @@
Fixes: Allow selection of audio device for PulseAudio backend
Fixes: [37042] Implement exclusive mode in PulseAudio backend
Fixes: Fix possible segfault in pulse_rd_loop of PulseAudio backend
Fixes: Add support for GetPropValue to PulseAudio backend
Fixes: Use actual program name if available to describe PulseAudio streams
Fixes: Expose PKEY_AudioEndpoint_PhysicalSpeakers device property in PulseAudio driver
Disabled: true