Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/winepulse.drv/mmdevdrv.c | 170 ++++++---------------------------- dlls/winepulse.drv/pulse.c | 81 ++++++++++++++++ dlls/winepulse.drv/unixlib.h | 2 + 3 files changed, 109 insertions(+), 144 deletions(-)
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
On Tue, May 11, 2021 at 06:30:17PM +0200, Jacek Caban wrote:
Signed-off-by: Jacek Caban jacek@codeweavers.com
dlls/winepulse.drv/mmdevdrv.c | 170 ++++++---------------------------- dlls/winepulse.drv/pulse.c | 81 ++++++++++++++++ dlls/winepulse.drv/unixlib.h | 2 + 3 files changed, 109 insertions(+), 144 deletions(-)
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index 59806f28465..0bb3491a577 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -23,7 +23,6 @@ #define _GNU_SOURCE
#include "config.h" -#include <poll.h>
#include <stdarg.h> #include <unistd.h> @@ -74,9 +73,6 @@ enum DriverPriority {
static struct pulse_config pulse_config;
-static pa_context *pulse_ctx; -static pa_mainloop *pulse_ml;
static HANDLE pulse_thread; static struct list g_sessions = LIST_INIT(g_sessions);
@@ -95,14 +91,7 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) if (__wine_init_unix_lib(dll, reason, NULL, &pulse)) return FALSE; } else if (reason == DLL_PROCESS_DETACH) {
if (pulse_thread)
SetThreadPriority(pulse_thread, 0);
if (pulse_ctx) {
pa_context_disconnect(pulse_ctx);
pa_context_unref(pulse_ctx);
}
if (pulse_ml)
pa_mainloop_quit(pulse_ml, 0);
__wine_init_unix_lib(dll, reason, NULL, NULL); if (pulse_thread) { WaitForSingleObject(pulse_thread, INFINITE); CloseHandle(pulse_thread);
@@ -244,65 +233,9 @@ static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); }
-/* Following pulseaudio design here, mainloop has the lock taken whenever
- it is handling something for pulse, and the lock is required whenever
- doing any pa_* call that can affect the state in any way
- pa_cond_wait is used when waiting on results, because the mainloop needs
- the same lock taken to affect the state
- This is basically the same as the pa_threaded_mainloop implementation,
- but that cannot be used because it uses pthread_create directly
- pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
- pa_threaded_mainloop_signal -> pthread_cond_broadcast
- pa_threaded_mainloop_wait -> pthread_cond_wait
- */
-static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
- int r;
- pulse->unlock();
- r = poll(ufds, nfds, timeout);
- pulse->lock();
- return r;
-}
static DWORD CALLBACK pulse_mainloop_thread(void *tmp) {
- int ret;
- pulse_ml = pa_mainloop_new();
- pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
- pulse->lock();
- pulse->broadcast();
- pa_mainloop_run(pulse_ml, &ret);
- pulse->unlock();
- pa_mainloop_free(pulse_ml);
- return ret;
-}
-static void pulse_contextcallback(pa_context *c, void *userdata) -{
- switch (pa_context_get_state(c)) {
default:
FIXME("Unhandled state: %i\n", pa_context_get_state(c));
return;
case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME:
case PA_CONTEXT_TERMINATED:
TRACE("State change to %i\n", pa_context_get_state(c));
return;
case PA_CONTEXT_READY:
TRACE("Ready\n");
break;
case PA_CONTEXT_FAILED:
WARN("Context failed: %s\n", pa_strerror(pa_context_errno(c)));
break;
- }
- pulse->broadcast();
- pulse->main_loop();
- return 0;
}
static void pulse_stream_state(pa_stream *s, void *user) @@ -352,73 +285,6 @@ static char *get_application_name(void) return str; }
-static HRESULT pulse_connect(void) -{
- int len;
- WCHAR path[MAX_PATH], *name;
- char *str;
- if (!pulse_thread)
- {
if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL)))
{
ERR("Failed to create mainloop thread.\n");
return E_FAIL;
}
SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
pulse->cond_wait();
- }
- if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx)))
return S_OK;
- if (pulse_ctx)
pa_context_unref(pulse_ctx);
- GetModuleFileNameW(NULL, path, ARRAY_SIZE(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);
- TRACE("Name: %s\n", str);
- pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
- pa_xfree(str);
- if (!pulse_ctx) {
ERR("Failed to create context\n");
return E_FAIL;
- }
- pa_context_set_state_callback(pulse_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)
goto fail;
- /* Wait for connection */
- while (pulse->cond_wait()) {
pa_context_state_t state = pa_context_get_state(pulse_ctx);
if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
goto fail;
if (state == PA_CONTEXT_READY)
break;
- }
- TRACE("Connected to server %s with protocol version: %i.\n",
pa_context_get_server(pulse_ctx),
pa_context_get_server_protocol_version(pulse_ctx));
- return S_OK;
-fail:
- pa_context_unref(pulse_ctx);
- pulse_ctx = NULL;
- return E_FAIL;
-}
static HRESULT pulse_stream_valid(ACImpl *This) { if (!This->stream) return AUDCLNT_E_NOT_INITIALIZED; @@ -831,7 +697,7 @@ static DWORD WINAPI pulse_timer_cb(void *user) return 0; }
-static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) { +static HRESULT pulse_stream_connect(ACImpl *This, pa_context *pulse_ctx, UINT32 period_bytes) { int ret; char buffer[64]; static LONG number; @@ -1318,6 +1184,8 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, const GUID *sessionguid) { ACImpl *This = impl_from_IAudioClient3(iface);
- pa_context *pulse_ctx;
- char *name; HRESULT hr = S_OK; UINT32 bufsize_bytes;
@@ -1348,15 +1216,29 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
pulse->lock();
- hr = pulse_connect();
- if (FAILED(hr)) {
- if (This->stream) { pulse->unlock();
return hr;
}return AUDCLNT_E_ALREADY_INITIALIZED;
- if (This->stream) {
- if (!pulse_thread)
- {
if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL)))
{
ERR("Failed to create mainloop thread.\n");
pulse->unlock();
return E_FAIL;
}
SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL);
pulse->cond_wait();
- }
- name = get_application_name();
- hr = pulse->connect(name, &pulse_ctx);
- free(name);
- if (FAILED(hr)) { pulse->unlock();
return AUDCLNT_E_ALREADY_INITIALIZED;
return hr;
}
hr = pulse_spec_from_waveformat(This, fmt);
@@ -1378,7 +1260,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
This->share = mode; This->flags = flags;
- hr = pulse_stream_connect(This, This->period_bytes);
- hr = pulse_stream_connect(This, pulse_ctx, This->period_bytes); if (SUCCEEDED(hr)) { UINT32 unalign; const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream);
diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 4b4d2497314..5369d5d08a5 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -76,6 +76,20 @@ static void WINAPI pulse_broadcast(void) pthread_cond_broadcast(&pulse_cond); }
+/* Following pulseaudio design here, mainloop has the lock taken whenever
- it is handling something for pulse, and the lock is required whenever
- doing any pa_* call that can affect the state in any way
- pa_cond_wait is used when waiting on results, because the mainloop needs
- the same lock taken to affect the state
- This is basically the same as the pa_threaded_mainloop implementation,
- but that cannot be used because it uses pthread_create directly
- pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock
- pa_threaded_mainloop_signal -> pthread_cond_broadcast
- pa_threaded_mainloop_wait -> pthread_cond_wait
- */
static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { int r; @@ -85,6 +99,18 @@ static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, return r; }
+static void WINAPI pulse_main_loop(void) +{
- int ret;
- pulse_ml = pa_mainloop_new();
- pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL);
- pulse_lock();
- pulse_broadcast();
- pa_mainloop_run(pulse_ml, &ret);
- pulse_unlock();
- pa_mainloop_free(pulse_ml);
+}
static void pulse_contextcallback(pa_context *c, void *userdata) { switch (pa_context_get_state(c)) { @@ -118,6 +144,50 @@ static void pulse_stream_state(pa_stream *s, void *user) pulse_broadcast(); }
+static HRESULT WINAPI pulse_connect(const char *name, pa_context **ctx) +{
- if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx))) {
*ctx = pulse_ctx;
return S_OK;
- }
- if (pulse_ctx)
pa_context_unref(pulse_ctx);
- pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), name);
- if (!pulse_ctx) {
ERR("Failed to create context\n");
return E_FAIL;
- }
- pa_context_set_state_callback(pulse_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)
goto fail;
- /* Wait for connection */
- while (pulse_cond_wait()) {
pa_context_state_t state = pa_context_get_state(pulse_ctx);
if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED)
goto fail;
if (state == PA_CONTEXT_READY)
break;
- }
- TRACE("Connected to server %s with protocol version: %i.\n",
pa_context_get_server(pulse_ctx),
pa_context_get_server_protocol_version(pulse_ctx));
- *ctx = pulse_ctx;
- return S_OK;
+fail:
- pa_context_unref(pulse_ctx);
- pulse_ctx = NULL;
- return E_FAIL;
+}
static DWORD pulse_channel_map_to_channel_mask(const pa_channel_map *map) { int i; @@ -412,6 +482,8 @@ static const struct unix_funcs unix_funcs = pulse_unlock, pulse_cond_wait, pulse_broadcast,
- pulse_main_loop,
- pulse_connect, pulse_test_connect,
};
@@ -430,6 +502,15 @@ NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *pt
*(const struct unix_funcs **)ptr_out = &unix_funcs; break;
case DLL_PROCESS_DETACH:
if (pulse_ctx)
{
pa_context_disconnect(pulse_ctx);
pa_context_unref(pulse_ctx);
}
if (pulse_ml)
pa_mainloop_quit(pulse_ml, 0);
}
return STATUS_SUCCESS;
diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h index 865a6f31ec6..f2bb7c78c82 100644 --- a/dlls/winepulse.drv/unixlib.h +++ b/dlls/winepulse.drv/unixlib.h @@ -33,5 +33,7 @@ struct unix_funcs void (WINAPI *unlock)(void); int (WINAPI *cond_wait)(void); void (WINAPI *broadcast)(void);
- void (WINAPI *main_loop)(void);
- HRESULT (WINAPI *connect)(const char *name, pa_context **ret); HRESULT (WINAPI *test_connect)(const char *name, struct pulse_config *config);
};