mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
winepulse-PulseAudio_Support: Reenable patchset.
Various patches have been modified to use static initialization of device data, to avoid loader deadlocks when initializing PulseAudio too early. These are very huge changes, so the new patchset should receive some additional testing before the next release.
This commit is contained in:
parent
637b89cefa
commit
91a3fcc513
@ -281,7 +281,7 @@ for more details.*
|
||||
* Support for MPEG2 DXVA2 GPU video decoding through vaapi
|
||||
* Support for NVIDIA video encoder library (nvencodeapi)
|
||||
* Support for NtQuerySection ([Wine Bug #37338](https://bugs.winehq.org/show_bug.cgi?id=37338))
|
||||
* Support for PulseAudio backend for audio ([Wine Bug #10495](https://bugs.winehq.org/show_bug.cgi?id=10495))
|
||||
* ~~Support for PulseAudio backend for audio~~ ([Wine Bug #10495](https://bugs.winehq.org/show_bug.cgi?id=10495))
|
||||
* Support for SHCreateSessionKey ([Wine Bug #35630](https://bugs.winehq.org/show_bug.cgi?id=35630))
|
||||
* Support for WTSEnumerateProcessesW ([Wine Bug #29903](https://bugs.winehq.org/show_bug.cgi?id=29903))
|
||||
* Support for extra large and jumbo icon lists in shell32 ([Wine Bug #24721](https://bugs.winehq.org/show_bug.cgi?id=24721))
|
||||
|
@ -308,6 +308,7 @@ patch_enable_all ()
|
||||
enable_winedbg_Windows_Version="$1"
|
||||
enable_winedevice_Fix_Relocation="$1"
|
||||
enable_winemenubuilder_Desktop_Icon_Path="$1"
|
||||
enable_winepulse_PulseAudio_Support="$1"
|
||||
enable_winex11_CandidateWindowPos="$1"
|
||||
enable_winex11_Clipboard_HTML="$1"
|
||||
enable_winex11_Window_Groups="$1"
|
||||
@ -1023,6 +1024,9 @@ patch_enable ()
|
||||
winemenubuilder-Desktop_Icon_Path)
|
||||
enable_winemenubuilder_Desktop_Icon_Path="$2"
|
||||
;;
|
||||
winepulse-PulseAudio_Support)
|
||||
enable_winepulse_PulseAudio_Support="$2"
|
||||
;;
|
||||
winex11-CandidateWindowPos)
|
||||
enable_winex11_CandidateWindowPos="$2"
|
||||
;;
|
||||
@ -1631,6 +1635,9 @@ if test "$enable_category_stable" -eq 1; then
|
||||
if test "$enable_winemenubuilder_Desktop_Icon_Path" -gt 1; then
|
||||
abort "Patchset winemenubuilder-Desktop_Icon_Path disabled, but category-stable depends on that."
|
||||
fi
|
||||
if test "$enable_winepulse_PulseAudio_Support" -gt 1; then
|
||||
abort "Patchset winepulse-PulseAudio_Support disabled, but category-stable depends on that."
|
||||
fi
|
||||
if test "$enable_winex11_Window_Style" -gt 1; then
|
||||
abort "Patchset winex11-Window_Style disabled, but category-stable depends on that."
|
||||
fi
|
||||
@ -1717,6 +1724,7 @@ if test "$enable_category_stable" -eq 1; then
|
||||
enable_wined3d_resource_check_usage=1
|
||||
enable_wined3d_wined3d_swapchain_present=1
|
||||
enable_winemenubuilder_Desktop_Icon_Path=1
|
||||
enable_winepulse_PulseAudio_Support=1
|
||||
enable_winex11_Window_Style=1
|
||||
enable_winex11_XEMBED=1
|
||||
enable_winex11_wglShareLists=1
|
||||
@ -6192,6 +6200,47 @@ if test "$enable_winemenubuilder_Desktop_Icon_Path" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset winepulse-PulseAudio_Support
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#37042] Implement exclusive mode in PulseAudio backend
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/winepulse.drv/Makefile.in, dlls/winepulse.drv/mmdevdrv.c, dlls/winepulse.drv/winepulse.drv.spec
|
||||
# |
|
||||
if test "$enable_winepulse_PulseAudio_Support" -eq 1; then
|
||||
patch_apply winepulse-PulseAudio_Support/0001-winepulse-handle-stream-create-failing-correctly.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0002-winepulse-Always-mute-buffer.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0003-winepulse-In-Shared-mode-track-device-position-in-by.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0004-winepulse-add-stub-for-GetPropValue.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0005-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0006-winepulse-Prefer-PulseAudio-driver.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0007-winepulse.drv-Use-delay-import-for-winealsa.drv.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0008-winepulse.drv-Use-a-separate-mainloop-and-ctx-for-pu.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0009-winepulse-expose-audio-devices-directly-to-programs.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0010-winepulse-implement-exclusive-mode.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0011-winepulse-fix-segfault-in-pulse_rd_loop.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0012-winepulse-implement-GetPropValue.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0013-winepulse-fetch-actual-program-name-if-possible.patch
|
||||
patch_apply winepulse-PulseAudio_Support/0014-winepulse-return-PKEY_AudioEndpoint_PhysicalSpeakers.patch
|
||||
(
|
||||
echo '+ { "Mark Harmstone", "winepulse: handle stream create failing correctly.", 1 },';
|
||||
echo '+ { "Andrew Eikum", "winepulse: Always mute buffer.", 1 },';
|
||||
echo '+ { "Andrew Eikum", "winepulse: In Shared mode, track device position in bytes.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: add stub for GetPropValue.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop.", 1 },';
|
||||
echo '+ { "Andrew Eikum", "winepulse: Prefer PulseAudio driver.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "winepulse.drv: Use delay import for winealsa.drv.", 1 },';
|
||||
echo '+ { "Sebastian Lackner", "winepulse.drv: Use a separate mainloop and ctx for pulse_test_connect.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: expose audio devices directly to programs.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: implement exclusive mode.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: fix segfault in pulse_rd_loop.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: implement GetPropValue.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: fetch actual program name if possible.", 1 },';
|
||||
echo '+ { "Mark Harmstone", "winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop.", 1 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset winex11-CandidateWindowPos
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
@ -1,418 +0,0 @@
|
||||
From 191d506cfbc49ad6a43632609e1f396ae10a6ca7 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:02 +0200
|
||||
Subject: winepulse: Add initial stub for pulseaudio support
|
||||
|
||||
---
|
||||
configure.ac | 31 +++-
|
||||
dlls/mmdevapi/main.c | 2 +-
|
||||
dlls/winepulse.drv/Makefile.in | 7 +
|
||||
dlls/winepulse.drv/mmdevdrv.c | 290 ++++++++++++++++++++++++++++++++++
|
||||
dlls/winepulse.drv/winepulse.drv.spec | 5 +
|
||||
5 files changed, 332 insertions(+), 3 deletions(-)
|
||||
create mode 100644 dlls/winepulse.drv/Makefile.in
|
||||
create mode 100644 dlls/winepulse.drv/mmdevdrv.c
|
||||
create mode 100644 dlls/winepulse.drv/winepulse.drv.spec
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index d23227a..76aed78 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -73,4 +73,5 @@ AC_ARG_WITH(png, AS_HELP_STRING([--without-png],[do not use PNG]))
|
||||
AC_ARG_WITH(pthread, AS_HELP_STRING([--without-pthread],[do not use the pthread library]),
|
||||
[if test "x$withval" = "xno"; then ac_cv_header_pthread_h=no; fi])
|
||||
+AC_ARG_WITH(pulse, AC_HELP_STRING([--without-pulse],[do not use PulseAudio sound support]))
|
||||
AC_ARG_WITH(sane, AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)]))
|
||||
AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF]))
|
||||
@@ -1548,6 +1549,30 @@ then
|
||||
[GetText ${notice_platform}development files not found (or too old), po files can't be rebuilt.])
|
||||
fi
|
||||
|
||||
+dnl **** Check for PulseAudio ****
|
||||
+AC_SUBST(PULSE_LIBS,"")
|
||||
+AC_SUBST(PULSE_CFLAGS,"")
|
||||
+if test "x$with_pulse" != "xno";
|
||||
+then
|
||||
+ ac_save_CPPFLAGS="$CPPFLAGS"
|
||||
+ if test "$PKG_CONFIG" != "false";
|
||||
+ then
|
||||
+ ac_pulse_libs="`$PKG_CONFIG --libs libpulse 2>/dev/null`"
|
||||
+ ac_pulse_cflags="`$PKG_CONFIG --cflags-only-I libpulse 2>/dev/null`"
|
||||
+
|
||||
+ CPPFLAGS="$CPPFLAGS $ac_pulse_cflags"
|
||||
+ AC_CHECK_HEADERS(pulse/pulseaudio.h,
|
||||
+ [AC_CHECK_LIB(pulse, pa_stream_is_corked,
|
||||
+ [AC_DEFINE(HAVE_PULSEAUDIO, 1, [Define if you have pulseaudio])
|
||||
+ PULSE_LIBS="$ac_pulse_libs"
|
||||
+ PULSE_CFLAGS="$ac_pulse_cflags"],,$ac_pulse_libs)
|
||||
+ ])
|
||||
+ fi
|
||||
+ CPPFLAGS="$ac_save_CPPFLAGS"
|
||||
+fi
|
||||
+WINE_WARNING_WITH(pulse, [test "$ac_cv_lib_pulse_pa_stream_is_corked" != "yes"],
|
||||
+ [libpulse ${notice_platform}development files not found or too old, Pulse won't be supported.])
|
||||
+
|
||||
dnl **** Check for gstreamer ****
|
||||
if test "x$with_gstreamer" != "xno"
|
||||
then
|
||||
@@ -1766,13 +1791,14 @@ fi
|
||||
dnl **** Disable unsupported winmm drivers ****
|
||||
test -n "$ALSA_LIBS" || enable_winealsa_drv=${enable_winealsa_drv:-no}
|
||||
test -n "$COREAUDIO_LIBS" || enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no}
|
||||
+test -n "$PULSE_LIBS" || enable_winepulse_drv=${enable_winepulse_drv:-no}
|
||||
test "x$ac_cv_member_oss_sysinfo_numaudioengines" = xyes || enable_wineoss_drv=${enable_wineoss_drv:-no}
|
||||
test "$ac_cv_header_linux_joystick_h" = "yes" -o "$ac_cv_header_IOKit_hid_IOHIDLib_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
|
||||
|
||||
dnl **** Check for any sound system ****
|
||||
-if test "x$ALSA_LIBS$COREAUDIO_LIBS" = "x" -a \
|
||||
+if test "x$ALSA_LIBS$COREAUDIO_LIBS$PULSE_LIBS" = "x" -a \
|
||||
"x$ac_cv_member_oss_sysinfo_numaudioengines" != xyes -a \
|
||||
- "x$with_alsa$with_coreaudio$with_oss" != xnonono
|
||||
+ "x$with_alsa$with_coreaudio$with_oss$with_pulse" != xnononono
|
||||
then
|
||||
WINE_WARNING([No sound system was found. Windows applications will be silent.])
|
||||
fi
|
||||
@@ -3339,6 +3365,7 @@ WINE_CONFIG_DLL(winemp3.acm)
|
||||
WINE_CONFIG_DLL(wineoss.drv)
|
||||
WINE_CONFIG_DLL(wineps.drv,,[clean,po])
|
||||
WINE_CONFIG_DLL(wineps16.drv16,enable_win16)
|
||||
+WINE_CONFIG_DLL(winepulse.drv)
|
||||
WINE_CONFIG_DLL(wineqtdecoder)
|
||||
WINE_CONFIG_DLL(winex11.drv)
|
||||
WINE_CONFIG_DLL(wing.dll16,enable_win16)
|
||||
diff --git a/dlls/mmdevapi/main.c b/dlls/mmdevapi/main.c
|
||||
index 52cf6f1..aa4baa5 100644
|
||||
--- a/dlls/mmdevapi/main.c
|
||||
+++ b/dlls/mmdevapi/main.c
|
||||
@@ -113,7 +113,7 @@ static BOOL init_driver(void)
|
||||
{
|
||||
static const WCHAR drv_value[] = {'A','u','d','i','o',0};
|
||||
|
||||
- static WCHAR default_list[] = {'a','l','s','a',',','o','s','s',',',
|
||||
+ static WCHAR default_list[] = {'p','u','l','s','e',',','a','l','s','a',',','o','s','s',',',
|
||||
'c','o','r','e','a','u','d','i','o',0};
|
||||
|
||||
DriverFuncs driver;
|
||||
diff --git a/dlls/winepulse.drv/Makefile.in b/dlls/winepulse.drv/Makefile.in
|
||||
new file mode 100644
|
||||
index 0000000..158bbc0
|
||||
--- /dev/null
|
||||
+++ b/dlls/winepulse.drv/Makefile.in
|
||||
@@ -0,0 +1,7 @@
|
||||
+MODULE = winepulse.drv
|
||||
+IMPORTS = dxguid uuid winmm user32 advapi32 ole32
|
||||
+EXTRALIBS = $(PULSE_LIBS) $(PTHREAD_LIBS)
|
||||
+EXTRAINCL = $(PULSE_CFLAGS)
|
||||
+
|
||||
+C_SRCS = \
|
||||
+ mmdevdrv.c
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
new file mode 100644
|
||||
index 0000000..d187bdc
|
||||
--- /dev/null
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -0,0 +1,290 @@
|
||||
+/*
|
||||
+ * Copyright 2011-2012 Maarten Lankhorst
|
||||
+ * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers
|
||||
+ * Copyright 2011 Andrew Eikum for CodeWeavers
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ *
|
||||
+ * Pulseaudio driver support.. hell froze over
|
||||
+ */
|
||||
+
|
||||
+#define NONAMELESSUNION
|
||||
+#define COBJMACROS
|
||||
+#include "config.h"
|
||||
+#include <poll.h>
|
||||
+#include <pthread.h>
|
||||
+
|
||||
+#include <stdarg.h>
|
||||
+#include <unistd.h>
|
||||
+#include <math.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#include <pulse/pulseaudio.h>
|
||||
+
|
||||
+#include "windef.h"
|
||||
+#include "winbase.h"
|
||||
+#include "winnls.h"
|
||||
+#include "winreg.h"
|
||||
+#include "wine/debug.h"
|
||||
+#include "wine/unicode.h"
|
||||
+#include "wine/list.h"
|
||||
+
|
||||
+#include "ole2.h"
|
||||
+#include "dshow.h"
|
||||
+#include "dsound.h"
|
||||
+#include "propsys.h"
|
||||
+
|
||||
+#include "initguid.h"
|
||||
+#include "ks.h"
|
||||
+#include "ksmedia.h"
|
||||
+#include "mmdeviceapi.h"
|
||||
+#include "audioclient.h"
|
||||
+#include "endpointvolume.h"
|
||||
+#include "audiopolicy.h"
|
||||
+
|
||||
+#include "wine/list.h"
|
||||
+
|
||||
+#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
|
||||
+
|
||||
+WINE_DEFAULT_DEBUG_CHANNEL(pulse);
|
||||
+
|
||||
+static const REFERENCE_TIME MinimumPeriod = 30000;
|
||||
+static const REFERENCE_TIME DefaultPeriod = 100000;
|
||||
+
|
||||
+static pa_context *pulse_ctx;
|
||||
+static pa_mainloop *pulse_ml;
|
||||
+
|
||||
+static HANDLE pulse_thread;
|
||||
+static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
+static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
|
||||
+
|
||||
+static DWORD pulse_stream_volume;
|
||||
+
|
||||
+const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
+ 'W','i','n','e','\\','P','u','l','s','e',0};
|
||||
+const WCHAR pulse_streamW[] = { 'S','t','r','e','a','m','V','o','l',0 };
|
||||
+
|
||||
+BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
+{
|
||||
+ if (reason == DLL_PROCESS_ATTACH) {
|
||||
+ HKEY key;
|
||||
+ if (RegOpenKeyW(HKEY_CURRENT_USER, pulse_keyW, &key) == ERROR_SUCCESS) {
|
||||
+ DWORD size = sizeof(pulse_stream_volume);
|
||||
+ RegQueryValueExW(key, pulse_streamW, 0, NULL,
|
||||
+ (BYTE*)&pulse_stream_volume, &size);
|
||||
+ RegCloseKey(key);
|
||||
+ }
|
||||
+ DisableThreadLibraryCalls(dll);
|
||||
+ } else if (reason == 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);
|
||||
+ CloseHandle(pulse_thread);
|
||||
+ }
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0};
|
||||
+
|
||||
+/* 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_signal
|
||||
+ * pa_threaded_mainloop_wait -> pthread_cond_wait
|
||||
+ */
|
||||
+
|
||||
+static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) {
|
||||
+ int r;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ r = poll(ufds, nfds, timeout);
|
||||
+ pthread_mutex_lock(&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);
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+ pa_mainloop_run(pulse_ml, &ret);
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ pa_mainloop_free(pulse_ml);
|
||||
+ CloseHandle(pulse_thread);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void pulse_contextcallback(pa_context *c, void *userdata);
|
||||
+
|
||||
+static HRESULT pulse_connect(void)
|
||||
+{
|
||||
+ int len;
|
||||
+ WCHAR path[PATH_MAX], *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);
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ }
|
||||
+
|
||||
+ 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, 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);
|
||||
+ 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 (pthread_cond_wait(&pulse_cond, &pulse_lock)) {
|
||||
+ 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 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));
|
||||
+ 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:
|
||||
+ ERR("Context failed: %s\n", pa_strerror(pa_context_errno(c)));
|
||||
+ break;
|
||||
+ }
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
|
||||
+ UINT *num, UINT *def_index)
|
||||
+{
|
||||
+ HRESULT hr = S_OK;
|
||||
+ TRACE("%d %p %p %p\n", flow, ids, num, def_index);
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_connect();
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ if (FAILED(hr))
|
||||
+ return hr;
|
||||
+ *num = 1;
|
||||
+ *def_index = 0;
|
||||
+
|
||||
+ *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
|
||||
+ if (!*ids)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+
|
||||
+ (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
|
||||
+ if (!(*ids)[0]) {
|
||||
+ HeapFree(GetProcessHeap(), 0, *ids);
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+
|
||||
+ lstrcpyW((*ids)[0], defaultW);
|
||||
+
|
||||
+ *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
|
||||
+ (*keys)[0] = NULL;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+int WINAPI AUDDRV_GetPriority(void)
|
||||
+{
|
||||
+ HRESULT hr;
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_connect();
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return SUCCEEDED(hr) ? 3 : 0;
|
||||
+}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
+ EDataFlow dataflow, IAudioClient **out)
|
||||
+{
|
||||
+ TRACE("%p %p %d %p\n", key, dev, dataflow, out);
|
||||
+ if (dataflow != eRender && dataflow != eCapture)
|
||||
+ return E_UNEXPECTED;
|
||||
+
|
||||
+ *out = NULL;
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
+ IAudioSessionManager2 **out)
|
||||
+{
|
||||
+ *out = NULL;
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
diff --git a/dlls/winepulse.drv/winepulse.drv.spec b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
new file mode 100644
|
||||
index 0000000..a089166
|
||||
--- /dev/null
|
||||
+++ b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
@@ -0,0 +1,5 @@
|
||||
+# MMDevAPI driver functions
|
||||
+@ stdcall -private GetPriority() AUDDRV_GetPriority
|
||||
+@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
|
||||
+@ stdcall -private GetAudioEndpoint(ptr ptr long ptr) AUDDRV_GetAudioEndpoint
|
||||
+@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
|
||||
--
|
||||
2.3.2
|
||||
|
@ -1,17 +1,18 @@
|
||||
From 2d638b335a2d9cdddfa9cfd7d7b6e889d124503c Mon Sep 17 00:00:00 2001
|
||||
From f83ea4f5911613771d8a6629ddaf5ac39064cd12 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Harmstone <mark@harmstone.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:06 +0200
|
||||
Subject: [PATCH 42/42] winepulse: handle stream create failing correctly
|
||||
Date: Tue, 3 Nov 2015 16:21:41 -0600
|
||||
Subject: winepulse: handle stream create failing correctly
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index f052a08..e755e8a 100644
|
||||
index 6b69488..3895f4c 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -701,6 +701,12 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
|
||||
@@ -753,6 +753,12 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
|
||||
ret = InterlockedIncrement(&number);
|
||||
sprintf(buffer, "audio stream #%i", ret);
|
||||
This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map);
|
||||
@ -25,5 +26,5 @@ index f052a08..e755e8a 100644
|
||||
pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This);
|
||||
pa_stream_set_moved_callback(This->stream, pulse_attr_update, This);
|
||||
--
|
||||
2.0.0
|
||||
2.6.2
|
||||
|
@ -1,172 +0,0 @@
|
||||
From 560601710fa0fae144f31be450e5be556ee5c338 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:02 +0200
|
||||
Subject: [PATCH 10/42] winepulse: Add format and period probing
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 128 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 128 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index d187bdc..40db26d 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -70,6 +70,10 @@ static HANDLE pulse_thread;
|
||||
static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
+/* Mixer format + period times */
|
||||
+static WAVEFORMATEXTENSIBLE pulse_fmt[2];
|
||||
+static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
|
||||
+
|
||||
static DWORD pulse_stream_volume;
|
||||
|
||||
const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
@@ -139,6 +143,121 @@ static DWORD CALLBACK pulse_mainloop_thread(void *tmp) {
|
||||
}
|
||||
|
||||
static void pulse_contextcallback(pa_context *c, void *userdata);
|
||||
+static void pulse_stream_state(pa_stream *s, void *user);
|
||||
+
|
||||
+static const enum pa_channel_position pulse_pos_from_wfx[] = {
|
||||
+ PA_CHANNEL_POSITION_FRONT_LEFT,
|
||||
+ PA_CHANNEL_POSITION_FRONT_RIGHT,
|
||||
+ PA_CHANNEL_POSITION_FRONT_CENTER,
|
||||
+ PA_CHANNEL_POSITION_LFE,
|
||||
+ PA_CHANNEL_POSITION_REAR_LEFT,
|
||||
+ PA_CHANNEL_POSITION_REAR_RIGHT,
|
||||
+ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
|
||||
+ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
|
||||
+ PA_CHANNEL_POSITION_REAR_CENTER,
|
||||
+ PA_CHANNEL_POSITION_SIDE_LEFT,
|
||||
+ PA_CHANNEL_POSITION_SIDE_RIGHT,
|
||||
+ PA_CHANNEL_POSITION_TOP_CENTER,
|
||||
+ PA_CHANNEL_POSITION_TOP_FRONT_LEFT,
|
||||
+ PA_CHANNEL_POSITION_TOP_FRONT_CENTER,
|
||||
+ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT,
|
||||
+ PA_CHANNEL_POSITION_TOP_REAR_LEFT,
|
||||
+ PA_CHANNEL_POSITION_TOP_REAR_CENTER,
|
||||
+ PA_CHANNEL_POSITION_TOP_REAR_RIGHT
|
||||
+};
|
||||
+
|
||||
+static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
|
||||
+ WAVEFORMATEX *wfx = &fmt->Format;
|
||||
+ pa_stream *stream;
|
||||
+ pa_channel_map map;
|
||||
+ pa_sample_spec ss;
|
||||
+ pa_buffer_attr attr;
|
||||
+ int ret, i;
|
||||
+ unsigned int length = 0;
|
||||
+
|
||||
+ pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA);
|
||||
+ ss.rate = 48000;
|
||||
+ ss.format = PA_SAMPLE_FLOAT32LE;
|
||||
+ ss.channels = map.channels;
|
||||
+
|
||||
+ attr.maxlength = -1;
|
||||
+ attr.tlength = -1;
|
||||
+ attr.minreq = attr.fragsize = pa_frame_size(&ss);
|
||||
+ attr.prebuf = 0;
|
||||
+
|
||||
+ stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map);
|
||||
+ if (stream)
|
||||
+ pa_stream_set_state_callback(stream, pulse_stream_state, NULL);
|
||||
+ if (!stream)
|
||||
+ ret = -1;
|
||||
+ else if (render)
|
||||
+ ret = pa_stream_connect_playback(stream, NULL, &attr,
|
||||
+ PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL);
|
||||
+ 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_stream_get_state(stream) == PA_STREAM_CREATING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ if (pa_stream_get_state(stream) == PA_STREAM_READY) {
|
||||
+ ss = *pa_stream_get_sample_spec(stream);
|
||||
+ map = *pa_stream_get_channel_map(stream);
|
||||
+ if (render)
|
||||
+ length = pa_stream_get_buffer_attr(stream)->minreq;
|
||||
+ else
|
||||
+ length = pa_stream_get_buffer_attr(stream)->fragsize;
|
||||
+ pa_stream_disconnect(stream);
|
||||
+ while (pa_stream_get_state(stream) == PA_STREAM_READY)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ }
|
||||
+ }
|
||||
+ if (stream)
|
||||
+ pa_stream_unref(stream);
|
||||
+ if (length)
|
||||
+ pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss);
|
||||
+ else
|
||||
+ pulse_min_period[!render] = MinimumPeriod;
|
||||
+ if (pulse_def_period[!render] <= DefaultPeriod)
|
||||
+ pulse_def_period[!render] = DefaultPeriod;
|
||||
+
|
||||
+ wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
+ wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||
+ wfx->nChannels = ss.channels;
|
||||
+ wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format);
|
||||
+ wfx->nSamplesPerSec = ss.rate;
|
||||
+ wfx->nBlockAlign = pa_frame_size(&ss);
|
||||
+ wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
|
||||
+ if (ss.format != PA_SAMPLE_S24_32LE)
|
||||
+ fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample;
|
||||
+ else
|
||||
+ fmt->Samples.wValidBitsPerSample = 24;
|
||||
+ if (ss.format == PA_SAMPLE_FLOAT32LE)
|
||||
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
+ else
|
||||
+ fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
+
|
||||
+ fmt->dwChannelMask = 0;
|
||||
+ for (i = 0; i < map.channels; ++i)
|
||||
+ switch (map.map[i]) {
|
||||
+ default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map.map[i])); break;
|
||||
+ case PA_CHANNEL_POSITION_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_FRONT_LEFT; break;
|
||||
+ case PA_CHANNEL_POSITION_MONO:
|
||||
+ case PA_CHANNEL_POSITION_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_FRONT_CENTER; break;
|
||||
+ case PA_CHANNEL_POSITION_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_FRONT_RIGHT; break;
|
||||
+ case PA_CHANNEL_POSITION_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_BACK_LEFT; break;
|
||||
+ case PA_CHANNEL_POSITION_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_BACK_CENTER; break;
|
||||
+ case PA_CHANNEL_POSITION_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_BACK_RIGHT; break;
|
||||
+ case PA_CHANNEL_POSITION_LFE: fmt->dwChannelMask |= SPEAKER_LOW_FREQUENCY; break;
|
||||
+ case PA_CHANNEL_POSITION_SIDE_LEFT: fmt->dwChannelMask |= SPEAKER_SIDE_LEFT; break;
|
||||
+ case PA_CHANNEL_POSITION_SIDE_RIGHT: fmt->dwChannelMask |= SPEAKER_SIDE_RIGHT; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_CENTER; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_LEFT; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_CENTER; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_FRONT_RIGHT; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_REAR_LEFT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_LEFT; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_REAR_CENTER: fmt->dwChannelMask |= SPEAKER_TOP_BACK_CENTER; break;
|
||||
+ case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: fmt->dwChannelMask |= SPEAKER_TOP_BACK_RIGHT; break;
|
||||
+ }
|
||||
+}
|
||||
|
||||
static HRESULT pulse_connect(void)
|
||||
{
|
||||
@@ -199,6 +318,8 @@ static HRESULT pulse_connect(void)
|
||||
TRACE("Connected to server %s with protocol version: %i.\n",
|
||||
pa_context_get_server(pulse_ctx),
|
||||
pa_context_get_server_protocol_version(pulse_ctx));
|
||||
+ pulse_probe_settings(1, &pulse_fmt[0]);
|
||||
+ pulse_probe_settings(0, &pulse_fmt[1]);
|
||||
return S_OK;
|
||||
|
||||
fail:
|
||||
@@ -230,6 +351,13 @@ static void pulse_contextcallback(pa_context *c, void *userdata) {
|
||||
pthread_cond_signal(&pulse_cond);
|
||||
}
|
||||
|
||||
+static void pulse_stream_state(pa_stream *s, void *user)
|
||||
+{
|
||||
+ pa_stream_state_t state = pa_stream_get_state(s);
|
||||
+ TRACE("Stream state changed to %i\n", state);
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
|
||||
UINT *num, UINT *def_index)
|
||||
{
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,65 @@
|
||||
From 59f7ed9326957728f0c3040b6c1f3a5cef5cde14 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Tue, 3 Nov 2015 16:21:48 -0600
|
||||
Subject: winepulse: Always mute buffer
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 24 ++++++++++++++----------
|
||||
1 file changed, 14 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 3895f4c..0e2bc08 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -572,6 +572,11 @@ static HRESULT pulse_stream_valid(ACImpl *This) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+static void silence_buffer(pa_sample_format_t format, BYTE *buffer, UINT32 bytes)
|
||||
+{
|
||||
+ memset(buffer, format == PA_SAMPLE_U8 ? 0x80 : 0, bytes);
|
||||
+}
|
||||
+
|
||||
static void dump_attr(const pa_buffer_attr *attr) {
|
||||
TRACE("maxlength: %u\n", attr->maxlength);
|
||||
TRACE("minreq: %u\n", attr->minreq);
|
||||
@@ -1315,7 +1320,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
else {
|
||||
ACPacket *cur_packet = (ACPacket*)((char*)This->tmp_buffer + This->bufsize_bytes);
|
||||
BYTE *data = This->tmp_buffer;
|
||||
- memset(This->tmp_buffer, This->ss.format == PA_SAMPLE_U8 ? 0x80 : 0, This->bufsize_bytes);
|
||||
+ silence_buffer(This->ss.format, This->tmp_buffer, This->bufsize_bytes);
|
||||
list_init(&This->packet_free_head);
|
||||
list_init(&This->packet_filled_head);
|
||||
for (i = 0; i < capture_packets; ++i, ++cur_packet) {
|
||||
@@ -1985,18 +1990,17 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
return AUDCLNT_E_INVALID_SIZE;
|
||||
}
|
||||
|
||||
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
- if (This->ss.format == PA_SAMPLE_U8)
|
||||
- memset(This->tmp_buffer, 128, written_bytes);
|
||||
- else
|
||||
- memset(This->tmp_buffer, 0, written_bytes);
|
||||
- }
|
||||
-
|
||||
This->locked = 0;
|
||||
- if (This->locked_ptr)
|
||||
+ if (This->locked_ptr) {
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
+ silence_buffer(This->ss.format, This->locked_ptr, written_bytes);
|
||||
pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
- else
|
||||
+ } else {
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
+ silence_buffer(This->ss.format, This->tmp_buffer, written_bytes);
|
||||
pa_stream_write(This->stream, This->tmp_buffer, written_bytes, pulse_free_noop, 0, PA_SEEK_RELATIVE);
|
||||
+ }
|
||||
+
|
||||
This->pad += written_bytes;
|
||||
This->locked_ptr = NULL;
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
--
|
||||
2.6.2
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,17 +1,18 @@
|
||||
From ca6122875e93dbcde90fcdb361c84a67ad1a5d44 Mon Sep 17 00:00:00 2001
|
||||
From 7479a9a46a748bd2a6b386bb20d3fe1c7c467d11 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Mon, 5 Jan 2015 11:31:56 +0100
|
||||
Date: Tue, 3 Nov 2015 16:21:53 -0600
|
||||
Subject: winepulse: In Shared mode, track device position in bytes
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 13 ++++++++++---
|
||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 1ef2ea2..3463cd8 100644
|
||||
index 0e2bc08..e5ba869 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -2154,8 +2154,12 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
|
||||
@@ -2207,8 +2207,12 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
|
||||
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
hr = pulse_stream_valid(This);
|
||||
@ -26,7 +27,7 @@ index 1ef2ea2..3463cd8 100644
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return hr;
|
||||
}
|
||||
@@ -2180,6 +2184,9 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
@@ -2233,6 +2237,9 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
|
||||
*pos = This->clock_written;
|
||||
|
||||
@ -36,7 +37,7 @@ index 1ef2ea2..3463cd8 100644
|
||||
/* Make time never go backwards */
|
||||
if (*pos < This->clock_lastpos)
|
||||
*pos = This->clock_lastpos;
|
||||
@@ -2248,7 +2255,7 @@ static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
|
||||
@@ -2301,7 +2308,7 @@ static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioClock2(iface);
|
||||
HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
|
||||
@ -46,5 +47,5 @@ index 1ef2ea2..3463cd8 100644
|
||||
return hr;
|
||||
}
|
||||
--
|
||||
2.2.1
|
||||
2.6.2
|
||||
|
@ -1,352 +0,0 @@
|
||||
From ad8e16a8030be3579609e4dc9ce9727b3dbce2da Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 12/42] winepulse: Add IAudioRenderClient and
|
||||
IAudioCaptureClient
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 301 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 301 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 37d85ff..01cfd25 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -146,12 +146,27 @@ struct ACImpl {
|
||||
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;
|
||||
+static const IAudioClockVtbl AudioClock_Vtbl;
|
||||
+static const IAudioClock2Vtbl AudioClock2_Vtbl;
|
||||
+static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
|
||||
|
||||
static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
|
||||
}
|
||||
|
||||
+static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface);
|
||||
+}
|
||||
+
|
||||
+static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_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
|
||||
@@ -701,6 +716,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl;
|
||||
+ This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
|
||||
+ This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl;
|
||||
+ This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl;
|
||||
+ This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl;
|
||||
+ This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
|
||||
This->dataflow = dataflow;
|
||||
This->parent = dev;
|
||||
This->clock_pulse = PA_USEC_INVALID;
|
||||
@@ -1421,6 +1441,16 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
+ if (IsEqualIID(riid, &IID_IAudioRenderClient)) {
|
||||
+ if (This->dataflow != eRender)
|
||||
+ return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
|
||||
+ *ppv = &This->IAudioRenderClient_iface;
|
||||
+ } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
|
||||
+ if (This->dataflow != eCapture)
|
||||
+ return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
|
||||
+ *ppv = &This->IAudioCaptureClient_iface;
|
||||
+ }
|
||||
+
|
||||
if (*ppv) {
|
||||
IUnknown_AddRef((IUnknown*)*ppv);
|
||||
return S_OK;
|
||||
@@ -1449,6 +1479,277 @@ static const IAudioClientVtbl AudioClient_Vtbl =
|
||||
AudioClient_GetService
|
||||
};
|
||||
|
||||
+static HRESULT WINAPI AudioRenderClient_QueryInterface(
|
||||
+ IAudioRenderClient *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioRenderClient))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
+ return AudioClient_AddRef(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
+ return AudioClient_Release(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
|
||||
+ UINT32 frames, BYTE **data)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
+ UINT32 avail, pad, req, bytes = frames * pa_frame_size(&This->ss);
|
||||
+ HRESULT hr = S_OK;
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ TRACE("(%p)->(%u, %p)\n", This, frames, data);
|
||||
+
|
||||
+ if (!data)
|
||||
+ return E_POINTER;
|
||||
+ *data = NULL;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (FAILED(hr) || This->locked) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
|
||||
+ }
|
||||
+ if (!frames) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ ACImpl_GetRenderPad(This, &pad);
|
||||
+ avail = This->bufsize_frames - pad;
|
||||
+ if (avail < frames || bytes > This->bufsize_bytes) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ WARN("Wanted to write %u, but only %u available\n", frames, avail);
|
||||
+ return AUDCLNT_E_BUFFER_TOO_LARGE;
|
||||
+ }
|
||||
+
|
||||
+ This->locked = frames;
|
||||
+ req = bytes;
|
||||
+ ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
|
||||
+ if (ret < 0 || req < bytes) {
|
||||
+ FIXME("%p Not using pulse locked data: %i %u/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
|
||||
+ if (ret >= 0)
|
||||
+ pa_stream_cancel_write(This->stream);
|
||||
+ *data = This->tmp_buffer;
|
||||
+ This->locked_ptr = NULL;
|
||||
+ } else
|
||||
+ *data = This->locked_ptr;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
+ IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
+ UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
|
||||
+
|
||||
+ TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ if (!This->locked || !written_frames) {
|
||||
+ if (This->locked_ptr)
|
||||
+ pa_stream_cancel_write(This->stream);
|
||||
+ This->locked = 0;
|
||||
+ This->locked_ptr = NULL;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK;
|
||||
+ }
|
||||
+
|
||||
+ if (This->locked < written_frames) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return AUDCLNT_E_INVALID_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
+ if (This->ss.format == PA_SAMPLE_U8)
|
||||
+ memset(This->tmp_buffer, 128, written_bytes);
|
||||
+ else
|
||||
+ memset(This->tmp_buffer, 0, written_bytes);
|
||||
+ }
|
||||
+
|
||||
+ This->locked = 0;
|
||||
+ if (This->locked_ptr)
|
||||
+ pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
+ else
|
||||
+ pa_stream_write(This->stream, This->tmp_buffer, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
+ This->pad += written_bytes;
|
||||
+ This->locked_ptr = NULL;
|
||||
+ TRACE("Released %u, pad %u\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
+ assert(This->pad <= This->bufsize_bytes);
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
|
||||
+ AudioRenderClient_QueryInterface,
|
||||
+ AudioRenderClient_AddRef,
|
||||
+ AudioRenderClient_Release,
|
||||
+ AudioRenderClient_GetBuffer,
|
||||
+ AudioRenderClient_ReleaseBuffer
|
||||
+};
|
||||
+
|
||||
+static HRESULT WINAPI AudioCaptureClient_QueryInterface(
|
||||
+ IAudioCaptureClient *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioCaptureClient))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
+ return IAudioClient_AddRef(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
+ return IAudioClient_Release(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
|
||||
+ BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos,
|
||||
+ UINT64 *qpcpos)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
+ HRESULT hr;
|
||||
+ ACPacket *packet;
|
||||
+
|
||||
+ TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags,
|
||||
+ devpos, qpcpos);
|
||||
+
|
||||
+ if (!data || !frames || !flags)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (FAILED(hr) || This->locked) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER;
|
||||
+ }
|
||||
+
|
||||
+ ACImpl_GetCapturePad(This, NULL);
|
||||
+ if ((packet = This->locked_ptr)) {
|
||||
+ *frames = This->capture_period / pa_frame_size(&This->ss);
|
||||
+ *flags = 0;
|
||||
+ if (packet->discont)
|
||||
+ *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY;
|
||||
+ if (devpos) {
|
||||
+ if (packet->discont)
|
||||
+ *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss);
|
||||
+ else
|
||||
+ *devpos = This->clock_written / pa_frame_size(&This->ss);
|
||||
+ }
|
||||
+ if (qpcpos)
|
||||
+ *qpcpos = packet->qpcpos;
|
||||
+ *data = packet->data;
|
||||
+ }
|
||||
+ else
|
||||
+ *frames = 0;
|
||||
+ This->locked = *frames;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
|
||||
+ IAudioCaptureClient *iface, UINT32 done)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%u)\n", This, done);
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ if (!This->locked && done) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return AUDCLNT_E_OUT_OF_ORDER;
|
||||
+ }
|
||||
+ if (done && This->locked != done) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return AUDCLNT_E_INVALID_SIZE;
|
||||
+ }
|
||||
+ if (done) {
|
||||
+ ACPacket *packet = This->locked_ptr;
|
||||
+ This->locked_ptr = NULL;
|
||||
+ This->pad -= This->capture_period;
|
||||
+ if (packet->discont)
|
||||
+ This->clock_written += 2 * This->capture_period;
|
||||
+ else
|
||||
+ This->clock_written += This->capture_period;
|
||||
+ list_add_tail(&This->packet_free_head, &packet->entry);
|
||||
+ }
|
||||
+ This->locked = 0;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
|
||||
+ IAudioCaptureClient *iface, UINT32 *frames)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
+ ACPacket *p;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, frames);
|
||||
+ if (!frames)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ ACImpl_GetCapturePad(This, NULL);
|
||||
+ p = This->locked_ptr;
|
||||
+ if (p)
|
||||
+ *frames = This->capture_period / pa_frame_size(&This->ss);
|
||||
+ else
|
||||
+ *frames = 0;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
|
||||
+{
|
||||
+ AudioCaptureClient_QueryInterface,
|
||||
+ AudioCaptureClient_AddRef,
|
||||
+ AudioCaptureClient_Release,
|
||||
+ AudioCaptureClient_GetBuffer,
|
||||
+ AudioCaptureClient_ReleaseBuffer,
|
||||
+ AudioCaptureClient_GetNextPacketSize
|
||||
+};
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
IAudioSessionManager2 **out)
|
||||
{
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,50 @@
|
||||
From f7f8676db491fee877020ad654fe46f0099e7274 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Harmstone <mark@harmstone.com>
|
||||
Date: Tue, 3 Nov 2015 16:22:09 -0600
|
||||
Subject: winepulse: add stub for GetPropValue
|
||||
|
||||
Edited by Maarten Lankhorst: No support for multiple devices in winepulse yet.
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 7 +++++++
|
||||
dlls/winepulse.drv/winepulse.drv.spec | 1 +
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index e5ba869..64e6c2a 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "initguid.h"
|
||||
#include "ks.h"
|
||||
#include "ksmedia.h"
|
||||
+#include "propkey.h"
|
||||
#include "mmdeviceapi.h"
|
||||
#include "audioclient.h"
|
||||
#include "endpointvolume.h"
|
||||
@@ -3198,3 +3199,9 @@ HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
*out = &This->IAudioSessionManager2_iface;
|
||||
return S_OK;
|
||||
}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
|
||||
+{
|
||||
+ TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
diff --git a/dlls/winepulse.drv/winepulse.drv.spec b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
index 288de87..7aeb175 100644
|
||||
--- a/dlls/winepulse.drv/winepulse.drv.spec
|
||||
+++ b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
@@ -3,6 +3,7 @@
|
||||
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
|
||||
@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint
|
||||
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
|
||||
+@ stdcall -private GetPropValue(ptr ptr ptr) AUDDRV_GetPropValue
|
||||
|
||||
# WinMM driver functions
|
||||
@ stdcall -private DriverProc(long long long long long) winealsa.drv.DriverProc
|
||||
--
|
||||
2.6.2
|
||||
|
@ -1,209 +0,0 @@
|
||||
From d9c51b0534a261c95cea362195dcba1688be815b Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 13/42] winepulse: Add IAudioClock and IAudioClock2
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 172 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 172 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 01cfd25..3ed2288 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -167,6 +167,16 @@ static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
|
||||
}
|
||||
|
||||
+static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
|
||||
+}
|
||||
+
|
||||
+static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_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
|
||||
@@ -1449,6 +1459,8 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
|
||||
if (This->dataflow != eCapture)
|
||||
return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
|
||||
*ppv = &This->IAudioCaptureClient_iface;
|
||||
+ } else if (IsEqualIID(riid, &IID_IAudioClock)) {
|
||||
+ *ppv = &This->IAudioClock_iface;
|
||||
}
|
||||
|
||||
if (*ppv) {
|
||||
@@ -1750,6 +1762,166 @@ static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl =
|
||||
AudioCaptureClient_GetNextPacketSize
|
||||
};
|
||||
|
||||
+static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
|
||||
+ REFIID riid, void **ppv)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock))
|
||||
+ *ppv = iface;
|
||||
+ else if (IsEqualIID(riid, &IID_IAudioClock2))
|
||||
+ *ppv = &This->IAudioClock2_iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+ return IAudioClient_AddRef(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioClock_Release(IAudioClock *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+ return IAudioClient_Release(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, freq);
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ *freq = This->ss.rate * pa_frame_size(&This->ss);
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
+ UINT64 *qpctime)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+ pa_usec_t time;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
|
||||
+
|
||||
+ if (!pos)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (FAILED(hr)) {
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return hr;
|
||||
+ }
|
||||
+
|
||||
+ *pos = This->clock_written;
|
||||
+ if (This->clock_pulse != PA_USEC_INVALID && pa_stream_get_time(This->stream, &time) >= 0) {
|
||||
+ UINT32 delta = pa_usec_to_bytes(time - This->clock_pulse, &This->ss);
|
||||
+ if (delta < This->pad)
|
||||
+ *pos += delta;
|
||||
+ else
|
||||
+ *pos += This->pad;
|
||||
+ }
|
||||
+
|
||||
+ /* Make time never go backwards */
|
||||
+ if (*pos < This->clock_lastpos)
|
||||
+ *pos = This->clock_lastpos;
|
||||
+ else
|
||||
+ This->clock_lastpos = *pos;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+
|
||||
+ TRACE("%p Position: %u\n", This, (unsigned)*pos);
|
||||
+
|
||||
+ if (qpctime) {
|
||||
+ LARGE_INTEGER stamp, freq;
|
||||
+ QueryPerformanceCounter(&stamp);
|
||||
+ QueryPerformanceFrequency(&freq);
|
||||
+ *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
|
||||
+ }
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface,
|
||||
+ DWORD *chars)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, chars);
|
||||
+
|
||||
+ if (!chars)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IAudioClockVtbl AudioClock_Vtbl =
|
||||
+{
|
||||
+ AudioClock_QueryInterface,
|
||||
+ AudioClock_AddRef,
|
||||
+ AudioClock_Release,
|
||||
+ AudioClock_GetFrequency,
|
||||
+ AudioClock_GetPosition,
|
||||
+ AudioClock_GetCharacteristics
|
||||
+};
|
||||
+
|
||||
+static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface,
|
||||
+ REFIID riid, void **ppv)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock2(iface);
|
||||
+ return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock2(iface);
|
||||
+ return IAudioClient_AddRef(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock2(iface);
|
||||
+ return IAudioClient_Release(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface,
|
||||
+ UINT64 *pos, UINT64 *qpctime)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioClock2(iface);
|
||||
+ HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ *pos /= pa_frame_size(&This->ss);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static const IAudioClock2Vtbl AudioClock2_Vtbl =
|
||||
+{
|
||||
+ AudioClock2_QueryInterface,
|
||||
+ AudioClock2_AddRef,
|
||||
+ AudioClock2_Release,
|
||||
+ AudioClock2_GetDevicePosition
|
||||
+};
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
IAudioSessionManager2 **out)
|
||||
{
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,17 +1,31 @@
|
||||
From 044624c3318488cb5c540797bd03994e18a221fd Mon Sep 17 00:00:00 2001
|
||||
From 690e73e4d7201a602f06b6d7d6896ed766f1c9f2 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Harmstone <mark@harmstone.com>
|
||||
Date: Wed, 10 Dec 2014 18:08:41 +0000
|
||||
Date: Tue, 3 Nov 2015 16:22:28 -0600
|
||||
Subject: winepulse: return PKEY_AudioEndpoint_PhysicalSpeakers device prop
|
||||
|
||||
Edited by Maarten Lankhorst: No support for multiple devices in winepulse yet.
|
||||
|
||||
Synchronous static data initialization by Andrew Eikum <aeikum@codeweavers.com>
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 91 +++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 67 insertions(+), 24 deletions(-)
|
||||
dlls/winepulse.drv/mmdevdrv.c | 84 +++++++++++++++++++++++++++++++------------
|
||||
1 file changed, 61 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 445c242..c66ba54 100644
|
||||
index 64e6c2a..9aa1537 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -322,13 +322,44 @@ static const enum pa_channel_position pulse_pos_from_wfx[] = {
|
||||
@@ -79,6 +79,8 @@ static pthread_mutex_t pulse_lock;
|
||||
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
|
||||
static struct list g_sessions = LIST_INIT(g_sessions);
|
||||
|
||||
+static UINT g_phys_speakers_mask = 0;
|
||||
+
|
||||
/* Mixer format + period times */
|
||||
static WAVEFORMATEXTENSIBLE pulse_fmt[2];
|
||||
static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
|
||||
@@ -330,13 +332,44 @@ static const enum pa_channel_position pulse_pos_from_wfx[] = {
|
||||
PA_CHANNEL_POSITION_TOP_REAR_RIGHT
|
||||
};
|
||||
|
||||
@ -57,7 +71,7 @@ index 445c242..c66ba54 100644
|
||||
unsigned int length = 0;
|
||||
|
||||
pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA);
|
||||
@@ -391,28 +422,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
|
||||
@@ -401,28 +434,7 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
|
||||
else
|
||||
fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
|
||||
@ -86,70 +100,60 @@ index 445c242..c66ba54 100644
|
||||
+ fmt->dwChannelMask = pulse_channel_map_to_channel_mask(&map);
|
||||
}
|
||||
|
||||
typedef struct tagLANGANDCODEPAGE
|
||||
@@ -3632,6 +3642,10 @@ static void pulse_prop_values_sink_info_cb(pa_context *c, const pa_sink_info *i,
|
||||
st->pv->vt = VT_UI4;
|
||||
st->pv->u.ulVal = Speakers;
|
||||
st->hr = S_OK;
|
||||
+ } else if (IsEqualPropertyKey(*st->prop, PKEY_AudioEndpoint_PhysicalSpeakers)) {
|
||||
+ st->pv->vt = VT_UI4;
|
||||
+ st->pv->u.ulVal = pulse_channel_map_to_channel_mask(&i->channel_map);
|
||||
+ st->hr = S_OK;
|
||||
} else
|
||||
st->hr = E_NOTIMPL;
|
||||
}
|
||||
@@ -3658,6 +3672,16 @@ static void pulse_prop_values_source_info_cb(pa_context *c, const pa_source_info
|
||||
pthread_cond_signal(&pulse_cond);
|
||||
static HRESULT pulse_connect(void)
|
||||
@@ -492,6 +504,14 @@ fail:
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
+/* For default Pulseaudio render device, OR together all of the
|
||||
+ * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
|
||||
+static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
|
||||
+{
|
||||
+ PROPVARIANT *pv = userdata;
|
||||
+
|
||||
+ if (i)
|
||||
+ pv->u.ulVal |= pulse_channel_map_to_channel_mask(&i->channel_map);
|
||||
+
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+ g_phys_speakers_mask |= pulse_channel_map_to_channel_mask(&i->channel_map);
|
||||
+}
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
|
||||
{
|
||||
struct pulse_prop_values_info_cb_data userdata;
|
||||
@@ -3667,6 +3691,24 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI
|
||||
/* 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
|
||||
@@ -501,6 +521,7 @@ static HRESULT pulse_test_connect(void)
|
||||
int len, ret;
|
||||
WCHAR path[PATH_MAX], *name;
|
||||
char *str;
|
||||
+ pa_operation *o;
|
||||
|
||||
TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
|
||||
pulse_ml = pa_mainloop_new();
|
||||
|
||||
+ if (IsEqualGUID(guid, &pulse_render_guid) && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) {
|
||||
+ /* For default Pulseaudio render device, OR together all of the
|
||||
+ * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */
|
||||
+
|
||||
+ out->vt = VT_UI4;
|
||||
+ out->u.ulVal = 0;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, out);
|
||||
+ if (o) {
|
||||
+ while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ pa_operation_unref(o);
|
||||
+ }
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return o ? S_OK : E_FAIL;
|
||||
@@ -549,6 +570,15 @@ static HRESULT pulse_test_connect(void)
|
||||
pulse_probe_settings(1, &pulse_fmt[0]);
|
||||
pulse_probe_settings(0, &pulse_fmt[1]);
|
||||
|
||||
+ g_phys_speakers_mask = 0;
|
||||
+ o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, NULL);
|
||||
+ if (o) {
|
||||
+ while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 &&
|
||||
+ pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ {}
|
||||
+ pa_operation_unref(o);
|
||||
+ }
|
||||
+
|
||||
if (IsEqualGUID(guid, &pulse_render_guid) || IsEqualGUID(guid, &pulse_capture_guid))
|
||||
return E_NOTIMPL;
|
||||
|
||||
@@ -3676,7 +3718,8 @@ HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARI
|
||||
}
|
||||
|
||||
if (!IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_FormFactor) &&
|
||||
- !IsEqualPropertyKey(*prop, devicepath_key)) {
|
||||
+ !IsEqualPropertyKey(*prop, devicepath_key) &&
|
||||
+ (flow == eCapture || !IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers))) {
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
pa_context_unref(pulse_ctx);
|
||||
pulse_ctx = NULL;
|
||||
pa_mainloop_free(pulse_ml);
|
||||
@@ -3203,5 +3233,13 @@ HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
|
||||
{
|
||||
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;
|
||||
+ }
|
||||
+
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
--
|
||||
2.2.1
|
||||
2.6.2
|
||||
|
@ -1,285 +0,0 @@
|
||||
From 9cefd9930adad40581db955cf9291708e282d8b5 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 14/42] winepulse: Add audiostreamvolume
|
||||
|
||||
---
|
||||
Pulse allows streams to set volume, but for various reasons it's
|
||||
better off being disabled by default.
|
||||
|
||||
It can be enabled with HKCU\Software\Wine\Pulse\StreamVol=0x1
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 236 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 236 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 3ed2288..b7414c2 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -177,6 +177,11 @@ static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface)
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface);
|
||||
}
|
||||
|
||||
+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
|
||||
@@ -444,6 +449,12 @@ static void pulse_op_cb(pa_stream *s, int success, void *user) {
|
||||
pthread_cond_signal(&pulse_cond);
|
||||
}
|
||||
|
||||
+static void pulse_ctx_op_cb(pa_context *c, int success, void *user) {
|
||||
+ TRACE("Success: %i\n", success);
|
||||
+ *(int*)user = success;
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
static void pulse_attr_update(pa_stream *s, void *user) {
|
||||
const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s);
|
||||
TRACE("New attributes or device moved:\n");
|
||||
@@ -1461,6 +1472,8 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
|
||||
*ppv = &This->IAudioCaptureClient_iface;
|
||||
} else if (IsEqualIID(riid, &IID_IAudioClock)) {
|
||||
*ppv = &This->IAudioClock_iface;
|
||||
+ } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) {
|
||||
+ *ppv = &This->IAudioStreamVolume_iface;
|
||||
}
|
||||
|
||||
if (*ppv) {
|
||||
@@ -1922,6 +1935,229 @@ static const IAudioClock2Vtbl AudioClock2_Vtbl =
|
||||
AudioClock2_GetDevicePosition
|
||||
};
|
||||
|
||||
+static HRESULT WINAPI AudioStreamVolume_QueryInterface(
|
||||
+ IAudioStreamVolume *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioStreamVolume))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ return IAudioClient_AddRef(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ return IAudioClient_Release(&This->IAudioClient_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
|
||||
+ IAudioStreamVolume *iface, UINT32 *out)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, out);
|
||||
+
|
||||
+ if (!out)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ *out = This->ss.channels;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+struct pulse_info_cb_data {
|
||||
+ UINT32 n;
|
||||
+ float *levels;
|
||||
+};
|
||||
+
|
||||
+static void pulse_sink_input_info_cb(pa_context *c, const pa_sink_input_info *info, int eol, void *data)
|
||||
+{
|
||||
+ struct pulse_info_cb_data *d = data;
|
||||
+ int i;
|
||||
+ if (eol)
|
||||
+ return;
|
||||
+ for (i = 0; i < d->n; ++i)
|
||||
+ d->levels[i] = (float)info->volume.values[i] / (float)PA_VOLUME_NORM;
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+static void pulse_source_info_cb(pa_context *c, const pa_source_info *info, int eol, void *data)
|
||||
+{
|
||||
+ struct pulse_info_cb_data *d = data;
|
||||
+ int i;
|
||||
+ if (eol)
|
||||
+ return;
|
||||
+ for (i = 0; i < d->n; ++i)
|
||||
+ d->levels[i] = (float)info->volume.values[i] / (float)PA_VOLUME_NORM;
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
|
||||
+ IAudioStreamVolume *iface, UINT32 count, const float *levels)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ pa_operation *o;
|
||||
+ HRESULT hr;
|
||||
+ int success = 0, i;
|
||||
+ pa_cvolume cv;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p)\n", This, count, levels);
|
||||
+
|
||||
+ if (!levels)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ if (count != This->ss.channels)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (FAILED(hr))
|
||||
+ goto out;
|
||||
+
|
||||
+ if (pulse_stream_volume) {
|
||||
+ cv.channels = count;
|
||||
+ for (i = 0; i < cv.channels; ++i)
|
||||
+ cv.values[i] = levels[i] * (float)PA_VOLUME_NORM;
|
||||
+ if (This->dataflow == eRender)
|
||||
+ o = pa_context_set_sink_input_volume(pulse_ctx, pa_stream_get_index(This->stream), &cv, pulse_ctx_op_cb, &success);
|
||||
+ else
|
||||
+ o = pa_context_set_source_volume_by_index(pulse_ctx, pa_stream_get_device_index(This->stream), &cv, pulse_ctx_op_cb, &success);
|
||||
+ if (o) {
|
||||
+ while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ pa_operation_unref(o);
|
||||
+ }
|
||||
+ if (!success)
|
||||
+ hr = AUDCLNT_E_BUFFER_ERROR;
|
||||
+ } else {
|
||||
+ int i;
|
||||
+ for (i = 0; i < count; ++i)
|
||||
+ This->vol[i] = levels[i];
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
|
||||
+ IAudioStreamVolume *iface, UINT32 count, float *levels)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ pa_operation *o;
|
||||
+ HRESULT hr;
|
||||
+ struct pulse_info_cb_data info;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p)\n", This, count, levels);
|
||||
+
|
||||
+ if (!levels)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ if (count != This->ss.channels)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ hr = pulse_stream_valid(This);
|
||||
+ if (FAILED(hr))
|
||||
+ goto out;
|
||||
+
|
||||
+ if (pulse_stream_volume) {
|
||||
+ info.n = count;
|
||||
+ info.levels = levels;
|
||||
+ if (This->dataflow == eRender)
|
||||
+ o = pa_context_get_sink_input_info(pulse_ctx, pa_stream_get_index(This->stream), pulse_sink_input_info_cb, &info);
|
||||
+ else
|
||||
+ o = pa_context_get_source_info_by_index(pulse_ctx, pa_stream_get_device_index(This->stream), pulse_source_info_cb, &info);
|
||||
+ if (o) {
|
||||
+ while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ pa_operation_unref(o);
|
||||
+ } else
|
||||
+ hr = AUDCLNT_E_BUFFER_ERROR;
|
||||
+ } else {
|
||||
+ int i;
|
||||
+ for (i = 0; i < count; ++i)
|
||||
+ levels[i] = This->vol[i];
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
|
||||
+ IAudioStreamVolume *iface, UINT32 index, float level)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ HRESULT hr;
|
||||
+ float volumes[PA_CHANNELS_MAX];
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %f)\n", This, index, level);
|
||||
+
|
||||
+ if (level < 0.f || level > 1.f)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ if (index >= This->ss.channels)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes);
|
||||
+ volumes[index] = level;
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ hr = AudioStreamVolume_SetAllVolumes(iface, This->ss.channels, volumes);
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
|
||||
+ IAudioStreamVolume *iface, UINT32 index, float *level)
|
||||
+{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+ float volumes[PA_CHANNELS_MAX];
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p)\n", This, index, level);
|
||||
+
|
||||
+ if (!level)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ if (index >= This->ss.channels)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes);
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ *level = volumes[index];
|
||||
+ return hr;
|
||||
+}
|
||||
+
|
||||
+static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
|
||||
+{
|
||||
+ AudioStreamVolume_QueryInterface,
|
||||
+ AudioStreamVolume_AddRef,
|
||||
+ AudioStreamVolume_Release,
|
||||
+ AudioStreamVolume_GetChannelCount,
|
||||
+ AudioStreamVolume_SetChannelVolume,
|
||||
+ AudioStreamVolume_GetChannelVolume,
|
||||
+ AudioStreamVolume_SetAllVolumes,
|
||||
+ AudioStreamVolume_GetAllVolumes
|
||||
+};
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
IAudioSessionManager2 **out)
|
||||
{
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,26 @@
|
||||
From 9d4e023a3c2f57e3e85ac406135a8a41064b3311 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Tue, 3 Nov 2015 16:22:53 -0600
|
||||
Subject: winepulse: Prefer PulseAudio driver
|
||||
|
||||
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 9aa1537..b2f83c8 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -869,7 +869,7 @@ int WINAPI AUDDRV_GetPriority(void)
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
hr = pulse_test_connect();
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
- return SUCCEEDED(hr) ? Priority_Low : Priority_Unavailable;
|
||||
+ return SUCCEEDED(hr) ? Priority_Preferred : Priority_Unavailable;
|
||||
}
|
||||
|
||||
HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
|
||||
--
|
||||
2.6.2
|
||||
|
@ -1,936 +0,0 @@
|
||||
From 5672b4a48c95114e55577c676ebc68d00e5b6908 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 15/42] winepulse: Add session support
|
||||
|
||||
---
|
||||
Copied verbatim from winealsa
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 849 +++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 848 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index b7414c2..64ee62e 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -69,6 +69,7 @@ static pa_mainloop *pulse_ml;
|
||||
static HANDLE pulse_thread;
|
||||
static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
|
||||
+static struct list g_sessions = LIST_INIT(g_sessions);
|
||||
|
||||
/* Mixer format + period times */
|
||||
static WAVEFORMATEXTENSIBLE pulse_fmt[2];
|
||||
@@ -105,6 +106,31 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
|
||||
typedef struct ACImpl ACImpl;
|
||||
|
||||
+typedef struct _AudioSession {
|
||||
+ GUID guid;
|
||||
+ struct list clients;
|
||||
+
|
||||
+ IMMDevice *device;
|
||||
+
|
||||
+ float master_vol;
|
||||
+ UINT32 channel_count;
|
||||
+ float *channel_vols;
|
||||
+ BOOL mute;
|
||||
+
|
||||
+ struct list entry;
|
||||
+} AudioSession;
|
||||
+
|
||||
+typedef struct _AudioSessionWrapper {
|
||||
+ IAudioSessionControl2 IAudioSessionControl2_iface;
|
||||
+ IChannelAudioVolume IChannelAudioVolume_iface;
|
||||
+ ISimpleAudioVolume ISimpleAudioVolume_iface;
|
||||
+
|
||||
+ LONG ref;
|
||||
+
|
||||
+ ACImpl *client;
|
||||
+ AudioSession *session;
|
||||
+} AudioSessionWrapper;
|
||||
+
|
||||
typedef struct _ACPacket {
|
||||
struct list entry;
|
||||
UINT64 qpcpos;
|
||||
@@ -139,6 +165,8 @@ struct ACImpl {
|
||||
INT64 clock_lastpos, clock_written;
|
||||
pa_usec_t clock_pulse;
|
||||
|
||||
+ AudioSession *session;
|
||||
+ AudioSessionWrapper *session_wrapper;
|
||||
struct list packet_free_head;
|
||||
struct list packet_filled_head;
|
||||
};
|
||||
@@ -148,10 +176,15 @@ 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;
|
||||
+static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl;
|
||||
+static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl;
|
||||
+static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl;
|
||||
static const IAudioClockVtbl AudioClock_Vtbl;
|
||||
static const IAudioClock2Vtbl AudioClock2_Vtbl;
|
||||
static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl;
|
||||
|
||||
+static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client);
|
||||
+
|
||||
static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface);
|
||||
@@ -167,6 +200,21 @@ static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface)
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface);
|
||||
}
|
||||
|
||||
+static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface);
|
||||
+}
|
||||
+
|
||||
+static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface);
|
||||
+}
|
||||
+
|
||||
+static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface);
|
||||
+}
|
||||
+
|
||||
static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface);
|
||||
@@ -897,6 +945,85 @@ static DWORD get_channel_mask(unsigned int channels)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void session_init_vols(AudioSession *session, UINT channels)
|
||||
+{
|
||||
+ if (session->channel_count < channels) {
|
||||
+ UINT i;
|
||||
+
|
||||
+ if (session->channel_vols)
|
||||
+ session->channel_vols = HeapReAlloc(GetProcessHeap(), 0,
|
||||
+ session->channel_vols, sizeof(float) * channels);
|
||||
+ else
|
||||
+ session->channel_vols = HeapAlloc(GetProcessHeap(), 0,
|
||||
+ sizeof(float) * channels);
|
||||
+ if (!session->channel_vols)
|
||||
+ return;
|
||||
+
|
||||
+ for(i = session->channel_count; i < channels; ++i)
|
||||
+ session->channel_vols[i] = 1.f;
|
||||
+
|
||||
+ session->channel_count = channels;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static AudioSession *create_session(const GUID *guid, IMMDevice *device,
|
||||
+ UINT num_channels)
|
||||
+{
|
||||
+ AudioSession *ret;
|
||||
+
|
||||
+ ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession));
|
||||
+ if (!ret)
|
||||
+ return NULL;
|
||||
+
|
||||
+ memcpy(&ret->guid, guid, sizeof(GUID));
|
||||
+
|
||||
+ ret->device = device;
|
||||
+
|
||||
+ list_init(&ret->clients);
|
||||
+
|
||||
+ list_add_head(&g_sessions, &ret->entry);
|
||||
+
|
||||
+ session_init_vols(ret, num_channels);
|
||||
+
|
||||
+ ret->master_vol = 1.f;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/* if channels == 0, then this will return or create a session with
|
||||
+ * matching dataflow and GUID. otherwise, channels must also match */
|
||||
+static HRESULT get_audio_session(const GUID *sessionguid,
|
||||
+ IMMDevice *device, UINT channels, AudioSession **out)
|
||||
+{
|
||||
+ AudioSession *session;
|
||||
+
|
||||
+ if (!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)) {
|
||||
+ *out = create_session(&GUID_NULL, device, channels);
|
||||
+ if (!*out)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ *out = NULL;
|
||||
+ LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry) {
|
||||
+ if (session->device == device &&
|
||||
+ IsEqualGUID(sessionguid, &session->guid)) {
|
||||
+ session_init_vols(session, channels);
|
||||
+ *out = session;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!*out) {
|
||||
+ *out = create_session(sessionguid, device, channels);
|
||||
+ if (!*out)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
{
|
||||
pa_channel_map_init(&This->map);
|
||||
@@ -1083,6 +1210,10 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
assert(!capture_packets || data - This->bufsize_bytes == This->tmp_buffer);
|
||||
}
|
||||
}
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ hr = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session);
|
||||
+ if (SUCCEEDED(hr))
|
||||
+ list_add_tail(&This->session->clients, &This->entry);
|
||||
|
||||
exit:
|
||||
if (FAILED(hr)) {
|
||||
@@ -1474,6 +1605,20 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid,
|
||||
*ppv = &This->IAudioClock_iface;
|
||||
} else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) {
|
||||
*ppv = &This->IAudioStreamVolume_iface;
|
||||
+ } else if (IsEqualIID(riid, &IID_IAudioSessionControl) ||
|
||||
+ IsEqualIID(riid, &IID_IChannelAudioVolume) ||
|
||||
+ IsEqualIID(riid, &IID_ISimpleAudioVolume)) {
|
||||
+ if (!This->session_wrapper) {
|
||||
+ This->session_wrapper = AudioSessionWrapper_Create(This);
|
||||
+ if (!This->session_wrapper)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+ if (IsEqualIID(riid, &IID_IAudioSessionControl))
|
||||
+ *ppv = &This->session_wrapper->IAudioSessionControl2_iface;
|
||||
+ else if (IsEqualIID(riid, &IID_IChannelAudioVolume))
|
||||
+ *ppv = &This->session_wrapper->IChannelAudioVolume_iface;
|
||||
+ else if (IsEqualIID(riid, &IID_ISimpleAudioVolume))
|
||||
+ *ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
|
||||
}
|
||||
|
||||
if (*ppv) {
|
||||
@@ -2158,9 +2303,711 @@ static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl =
|
||||
AudioStreamVolume_GetAllVolumes
|
||||
};
|
||||
|
||||
+static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client)
|
||||
+{
|
||||
+ AudioSessionWrapper *ret;
|
||||
+
|
||||
+ ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
+ sizeof(AudioSessionWrapper));
|
||||
+ if (!ret)
|
||||
+ return NULL;
|
||||
+
|
||||
+ ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl;
|
||||
+ ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl;
|
||||
+ ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl;
|
||||
+
|
||||
+ ret->ref = !client;
|
||||
+
|
||||
+ ret->client = client;
|
||||
+ if (client) {
|
||||
+ ret->session = client->session;
|
||||
+ AudioClient_AddRef(&client->IAudioClient_iface);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_QueryInterface(
|
||||
+ IAudioSessionControl2 *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioSessionControl) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioSessionControl2))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+ ULONG ref;
|
||||
+ ref = InterlockedIncrement(&This->ref);
|
||||
+ TRACE("(%p) Refcount now %u\n", This, ref);
|
||||
+ return ref;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+ ULONG ref;
|
||||
+ ref = InterlockedDecrement(&This->ref);
|
||||
+ TRACE("(%p) Refcount now %u\n", This, ref);
|
||||
+ if (!ref) {
|
||||
+ if (This->client) {
|
||||
+ This->client->session_wrapper = NULL;
|
||||
+ AudioClient_Release(&This->client->IAudioClient_iface);
|
||||
+ }
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ }
|
||||
+ return ref;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
|
||||
+ AudioSessionState *state)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+ ACImpl *client;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, state);
|
||||
+
|
||||
+ if (!state)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ if (list_empty(&This->session->clients)) {
|
||||
+ *state = AudioSessionStateExpired;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry) {
|
||||
+ if (client->started) {
|
||||
+ *state = AudioSessionStateActive;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+ *state = AudioSessionStateInactive;
|
||||
+
|
||||
+out:
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetDisplayName(
|
||||
+ IAudioSessionControl2 *iface, WCHAR **name)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, name);
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_SetDisplayName(
|
||||
+ IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session));
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetIconPath(
|
||||
+ IAudioSessionControl2 *iface, WCHAR **path)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, path);
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_SetIconPath(
|
||||
+ IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session));
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetGroupingParam(
|
||||
+ IAudioSessionControl2 *iface, GUID *group)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, group);
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_SetGroupingParam(
|
||||
+ IAudioSessionControl2 *iface, const GUID *group, const GUID *session)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group),
|
||||
+ debugstr_guid(session));
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification(
|
||||
+ IAudioSessionControl2 *iface, IAudioSessionEvents *events)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, events);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification(
|
||||
+ IAudioSessionControl2 *iface, IAudioSessionEvents *events)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, events);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier(
|
||||
+ IAudioSessionControl2 *iface, WCHAR **id)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, id);
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier(
|
||||
+ IAudioSessionControl2 *iface, WCHAR **id)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, id);
|
||||
+
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_GetProcessId(
|
||||
+ IAudioSessionControl2 *iface, DWORD *pid)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", This, pid);
|
||||
+
|
||||
+ if (!pid)
|
||||
+ return E_POINTER;
|
||||
+
|
||||
+ *pid = GetCurrentProcessId();
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession(
|
||||
+ IAudioSessionControl2 *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ TRACE("(%p)\n", This);
|
||||
+
|
||||
+ return S_FALSE;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionControl_SetDuckingPreference(
|
||||
+ IAudioSessionControl2 *iface, BOOL optout)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
|
||||
+
|
||||
+ TRACE("(%p)->(%d)\n", This, optout);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl =
|
||||
+{
|
||||
+ AudioSessionControl_QueryInterface,
|
||||
+ AudioSessionControl_AddRef,
|
||||
+ AudioSessionControl_Release,
|
||||
+ AudioSessionControl_GetState,
|
||||
+ AudioSessionControl_GetDisplayName,
|
||||
+ AudioSessionControl_SetDisplayName,
|
||||
+ AudioSessionControl_GetIconPath,
|
||||
+ AudioSessionControl_SetIconPath,
|
||||
+ AudioSessionControl_GetGroupingParam,
|
||||
+ AudioSessionControl_SetGroupingParam,
|
||||
+ AudioSessionControl_RegisterAudioSessionNotification,
|
||||
+ AudioSessionControl_UnregisterAudioSessionNotification,
|
||||
+ AudioSessionControl_GetSessionIdentifier,
|
||||
+ AudioSessionControl_GetSessionInstanceIdentifier,
|
||||
+ AudioSessionControl_GetProcessId,
|
||||
+ AudioSessionControl_IsSystemSoundsSession,
|
||||
+ AudioSessionControl_SetDuckingPreference
|
||||
+};
|
||||
+
|
||||
+typedef struct _SessionMgr {
|
||||
+ IAudioSessionManager2 IAudioSessionManager2_iface;
|
||||
+
|
||||
+ LONG ref;
|
||||
+
|
||||
+ IMMDevice *device;
|
||||
+} SessionMgr;
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface,
|
||||
+ REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioSessionManager) ||
|
||||
+ IsEqualIID(riid, &IID_IAudioSessionManager2))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface)
|
||||
+{
|
||||
+ return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ ULONG ref;
|
||||
+ ref = InterlockedIncrement(&This->ref);
|
||||
+ TRACE("(%p) Refcount now %u\n", This, ref);
|
||||
+ return ref;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ ULONG ref;
|
||||
+ ref = InterlockedDecrement(&This->ref);
|
||||
+ TRACE("(%p) Refcount now %u\n", This, ref);
|
||||
+ if (!ref)
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ return ref;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl(
|
||||
+ IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
|
||||
+ IAudioSessionControl **out)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ AudioSession *session;
|
||||
+ AudioSessionWrapper *wrapper;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
|
||||
+ flags, out);
|
||||
+
|
||||
+ hr = get_audio_session(session_guid, This->device, 0, &session);
|
||||
+ if (FAILED(hr))
|
||||
+ return hr;
|
||||
+
|
||||
+ wrapper = AudioSessionWrapper_Create(NULL);
|
||||
+ if (!wrapper)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+
|
||||
+ wrapper->session = session;
|
||||
+
|
||||
+ *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume(
|
||||
+ IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags,
|
||||
+ ISimpleAudioVolume **out)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ AudioSession *session;
|
||||
+ AudioSessionWrapper *wrapper;
|
||||
+ HRESULT hr;
|
||||
+
|
||||
+ TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid),
|
||||
+ flags, out);
|
||||
+
|
||||
+ hr = get_audio_session(session_guid, This->device, 0, &session);
|
||||
+ if (FAILED(hr))
|
||||
+ return hr;
|
||||
+
|
||||
+ wrapper = AudioSessionWrapper_Create(NULL);
|
||||
+ if (!wrapper)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+
|
||||
+ wrapper->session = session;
|
||||
+
|
||||
+ *out = &wrapper->ISimpleAudioVolume_iface;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator(
|
||||
+ IAudioSessionManager2 *iface, IAudioSessionEnumerator **out)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, out);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification(
|
||||
+ IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, notification);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification(
|
||||
+ IAudioSessionManager2 *iface, IAudioSessionNotification *notification)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, notification);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification(
|
||||
+ IAudioSessionManager2 *iface, const WCHAR *session_id,
|
||||
+ IAudioVolumeDuckNotification *notification)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, notification);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification(
|
||||
+ IAudioSessionManager2 *iface,
|
||||
+ IAudioVolumeDuckNotification *notification)
|
||||
+{
|
||||
+ SessionMgr *This = impl_from_IAudioSessionManager2(iface);
|
||||
+ FIXME("(%p)->(%p) - stub\n", This, notification);
|
||||
+ return E_NOTIMPL;
|
||||
+}
|
||||
+
|
||||
+static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl =
|
||||
+{
|
||||
+ AudioSessionManager_QueryInterface,
|
||||
+ AudioSessionManager_AddRef,
|
||||
+ AudioSessionManager_Release,
|
||||
+ AudioSessionManager_GetAudioSessionControl,
|
||||
+ AudioSessionManager_GetSimpleAudioVolume,
|
||||
+ AudioSessionManager_GetSessionEnumerator,
|
||||
+ AudioSessionManager_RegisterSessionNotification,
|
||||
+ AudioSessionManager_UnregisterSessionNotification,
|
||||
+ AudioSessionManager_RegisterDuckNotification,
|
||||
+ AudioSessionManager_UnregisterDuckNotification
|
||||
+};
|
||||
+
|
||||
+static HRESULT WINAPI SimpleAudioVolume_QueryInterface(
|
||||
+ ISimpleAudioVolume *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_ISimpleAudioVolume))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
|
||||
+ ISimpleAudioVolume *iface, float level, const GUID *context)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context));
|
||||
+
|
||||
+ if (level < 0.f || level > 1.f)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ if (context)
|
||||
+ FIXME("Notifications not supported yet\n");
|
||||
+
|
||||
+ TRACE("Pulseaudio does not support session volume control\n");
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ session->master_vol = level;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume(
|
||||
+ ISimpleAudioVolume *iface, float *level)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", session, level);
|
||||
+
|
||||
+ if (!level)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ *level = session->master_vol;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
|
||||
+ BOOL mute, const GUID *context)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%u, %p)\n", session, mute, context);
|
||||
+
|
||||
+ if (context)
|
||||
+ FIXME("Notifications not supported yet\n");
|
||||
+
|
||||
+ session->mute = mute;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface,
|
||||
+ BOOL *mute)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", session, mute);
|
||||
+
|
||||
+ if (!mute)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ *mute = session->mute;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl =
|
||||
+{
|
||||
+ SimpleAudioVolume_QueryInterface,
|
||||
+ SimpleAudioVolume_AddRef,
|
||||
+ SimpleAudioVolume_Release,
|
||||
+ SimpleAudioVolume_SetMasterVolume,
|
||||
+ SimpleAudioVolume_GetMasterVolume,
|
||||
+ SimpleAudioVolume_SetMute,
|
||||
+ SimpleAudioVolume_GetMute
|
||||
+};
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_QueryInterface(
|
||||
+ IChannelAudioVolume *iface, REFIID riid, void **ppv)
|
||||
+{
|
||||
+ TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
+
|
||||
+ if (!ppv)
|
||||
+ return E_POINTER;
|
||||
+ *ppv = NULL;
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IUnknown) ||
|
||||
+ IsEqualIID(riid, &IID_IChannelAudioVolume))
|
||||
+ *ppv = iface;
|
||||
+ if (*ppv) {
|
||||
+ IUnknown_AddRef((IUnknown*)*ppv);
|
||||
+ return S_OK;
|
||||
+ }
|
||||
+
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
+ return E_NOINTERFACE;
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface);
|
||||
+}
|
||||
+
|
||||
+static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ return AudioSessionControl_Release(&This->IAudioSessionControl2_iface);
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_GetChannelCount(
|
||||
+ IChannelAudioVolume *iface, UINT32 *out)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%p)\n", session, out);
|
||||
+
|
||||
+ if (!out)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ *out = session->channel_count;
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
|
||||
+ IChannelAudioVolume *iface, UINT32 index, float level,
|
||||
+ const GUID *context)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %f, %s)\n", session, index, level,
|
||||
+ wine_dbgstr_guid(context));
|
||||
+
|
||||
+ if (level < 0.f || level > 1.f)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ if (index >= session->channel_count)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ if (context)
|
||||
+ FIXME("Notifications not supported yet\n");
|
||||
+
|
||||
+ TRACE("Pulseaudio does not support session volume control\n");
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ session->channel_vols[index] = level;
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume(
|
||||
+ IChannelAudioVolume *iface, UINT32 index, float *level)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p)\n", session, index, level);
|
||||
+
|
||||
+ if (!level)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ if (index >= session->channel_count)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ *level = session->channel_vols[index];
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
|
||||
+ IChannelAudioVolume *iface, UINT32 count, const float *levels,
|
||||
+ const GUID *context)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+ int i;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p, %s)\n", session, count, levels,
|
||||
+ wine_dbgstr_guid(context));
|
||||
+
|
||||
+ if (!levels)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ if (count != session->channel_count)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ if (context)
|
||||
+ FIXME("Notifications not supported yet\n");
|
||||
+
|
||||
+ TRACE("Pulseaudio does not support session volume control\n");
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ for(i = 0; i < count; ++i)
|
||||
+ session->channel_vols[i] = levels[i];
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes(
|
||||
+ IChannelAudioVolume *iface, UINT32 count, float *levels)
|
||||
+{
|
||||
+ AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface);
|
||||
+ AudioSession *session = This->session;
|
||||
+ int i;
|
||||
+
|
||||
+ TRACE("(%p)->(%d, %p)\n", session, count, levels);
|
||||
+
|
||||
+ if (!levels)
|
||||
+ return NULL_PTR_ERR;
|
||||
+
|
||||
+ if (count != session->channel_count)
|
||||
+ return E_INVALIDARG;
|
||||
+
|
||||
+ for(i = 0; i < count; ++i)
|
||||
+ levels[i] = session->channel_vols[i];
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl =
|
||||
+{
|
||||
+ ChannelAudioVolume_QueryInterface,
|
||||
+ ChannelAudioVolume_AddRef,
|
||||
+ ChannelAudioVolume_Release,
|
||||
+ ChannelAudioVolume_GetChannelCount,
|
||||
+ ChannelAudioVolume_SetChannelVolume,
|
||||
+ ChannelAudioVolume_GetChannelVolume,
|
||||
+ ChannelAudioVolume_SetAllVolumes,
|
||||
+ ChannelAudioVolume_GetAllVolumes
|
||||
+};
|
||||
+
|
||||
HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
IAudioSessionManager2 **out)
|
||||
{
|
||||
+ SessionMgr *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr));
|
||||
*out = NULL;
|
||||
- return E_NOTIMPL;
|
||||
+ if (!This)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl;
|
||||
+ This->device = device;
|
||||
+ This->ref = 1;
|
||||
+ *out = &This->IAudioSessionManager2_iface;
|
||||
+ return S_OK;
|
||||
}
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,23 @@
|
||||
From f0fe2f14297ba745299f3dd11871dad288666c63 Mon Sep 17 00:00:00 2001
|
||||
From: Sebastian Lackner <sebastian@fds-team.de>
|
||||
Date: Wed, 4 Nov 2015 02:20:43 +0100
|
||||
Subject: winepulse.drv: Use delay import for winealsa.drv.
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/Makefile.in | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/Makefile.in b/dlls/winepulse.drv/Makefile.in
|
||||
index d660063..5671c0d 100644
|
||||
--- a/dlls/winepulse.drv/Makefile.in
|
||||
+++ b/dlls/winepulse.drv/Makefile.in
|
||||
@@ -1,5 +1,6 @@
|
||||
MODULE = winepulse.drv
|
||||
IMPORTS = dxguid uuid winmm user32 advapi32 ole32
|
||||
+DELAYIMPORTS = winealsa.drv
|
||||
EXTRALIBS = $(PULSE_LIBS) $(PTHREAD_LIBS)
|
||||
EXTRAINCL = $(PULSE_CFLAGS)
|
||||
|
||||
--
|
||||
2.6.2
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 48782b64e7a62612d8166e74271dbeb1cd83bb3c Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 16/42] fix fdels trailing whitespaces
|
||||
|
||||
Happy? :P
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 64ee62e..5a71a3d 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1898,7 +1898,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
|
||||
TRACE("(%p)->(%p)\n", This, frames);
|
||||
if (!frames)
|
||||
return E_POINTER;
|
||||
-
|
||||
+
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
ACImpl_GetCapturePad(This, NULL);
|
||||
p = This->locked_ptr;
|
||||
@@ -1998,7 +1998,7 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
else
|
||||
*pos += This->pad;
|
||||
}
|
||||
-
|
||||
+
|
||||
/* Make time never go backwards */
|
||||
if (*pos < This->clock_lastpos)
|
||||
*pos = This->clock_lastpos;
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,146 @@
|
||||
From cacb40ffeaf3d0c09d5d78479a1b93b3f7434240 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 | 57 ++++++++++++++++++++-----------------------
|
||||
1 file changed, 26 insertions(+), 31 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index b2f83c8..36822a4 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -363,7 +363,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;
|
||||
@@ -382,7 +382,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)
|
||||
@@ -393,7 +393,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) {
|
||||
@@ -404,7 +404,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)
|
||||
{}
|
||||
}
|
||||
@@ -522,10 +522,12 @@ static HRESULT pulse_test_connect(void)
|
||||
WCHAR path[PATH_MAX], *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, '\\');
|
||||
@@ -537,24 +539,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;
|
||||
@@ -564,34 +565,28 @@ static HRESULT pulse_test_connect(void)
|
||||
}
|
||||
|
||||
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.6.2
|
||||
|
@ -1,4 +1,4 @@
|
||||
From c70a0c4b7242ae062876ee1a6b74f03f7e60c0d6 Mon Sep 17 00:00:00 2001
|
||||
From 08980bf07929d455b5891941388f4291319924bb 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
|
||||
@ -14,15 +14,30 @@ 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 | 233 ++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 226 insertions(+), 7 deletions(-)
|
||||
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 063b1db..8a75f0e 100644
|
||||
index 36822a4..9342762 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -84,6 +84,11 @@ static struct list g_sessions = LIST_INIT(g_sessions);
|
||||
@@ -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];
|
||||
|
||||
@ -34,7 +49,21 @@ index 063b1db..8a75f0e 100644
|
||||
static GUID pulse_render_guid =
|
||||
{ 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
|
||||
static GUID pulse_capture_guid =
|
||||
@@ -161,6 +166,7 @@ struct ACImpl {
|
||||
@@ -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];
|
||||
@ -42,47 +71,21 @@ index 063b1db..8a75f0e 100644
|
||||
|
||||
LONG ref;
|
||||
EDataFlow dataflow;
|
||||
@@ -679,6 +685,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)
|
||||
@@ -703,12 +712,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;
|
||||
@@ -727,11 +745,131 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
|
||||
return S_OK;
|
||||
@@ -186,8 +207,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;
|
||||
@@ -504,12 +523,92 @@ fail:
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys,
|
||||
-/* 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;
|
||||
@ -132,114 +135,193 @@ index 063b1db..8a75f0e 100644
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+struct pulse_all_info_cb_data {
|
||||
+ EDataFlow flow;
|
||||
+ WCHAR **ids;
|
||||
+ GUID *keys;
|
||||
+ UINT num;
|
||||
+};
|
||||
+
|
||||
+static void pulse_all_sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) {
|
||||
+ struct pulse_all_info_cb_data *st = userdata;
|
||||
+ void *tmp;
|
||||
+ DWORD len;
|
||||
+
|
||||
+ if (!i) goto out;
|
||||
+
|
||||
+ tmp = HeapReAlloc(GetProcessHeap(), 0, st->ids, sizeof(WCHAR*) * (st->num + 1));
|
||||
+ if (!tmp) goto out;
|
||||
+ st->ids = tmp;
|
||||
+
|
||||
+ tmp = HeapReAlloc(GetProcessHeap(), 0, st->keys, sizeof(GUID) * (st->num + 1));
|
||||
+ if (!tmp) goto out;
|
||||
+ st->keys = tmp;
|
||||
+
|
||||
+ len = MultiByteToWideChar(CP_UTF8, 0, i->description, -1, NULL, 0);
|
||||
+ if (!len) goto out;
|
||||
+
|
||||
+ st->ids[st->num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||
+ if (!st->ids[st->num]) goto out;
|
||||
+
|
||||
+ MultiByteToWideChar(CP_UTF8, 0, i->description, -1, st->ids[st->num], len);
|
||||
+ if (!get_device_guid(st->flow, i->name, &(st->keys[st->num])))
|
||||
+ CoCreateGuid(&(st->keys[st->num]));
|
||||
+
|
||||
+ st->num++;
|
||||
+
|
||||
+out:
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+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_all_source_info_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata) {
|
||||
+ struct pulse_all_info_cb_data *st = userdata;
|
||||
+ void *tmp;
|
||||
+ DWORD len;
|
||||
+
|
||||
+ if (!i) goto out;
|
||||
+
|
||||
+ tmp = HeapReAlloc(GetProcessHeap(), 0, st->ids, sizeof(WCHAR*) * (st->num + 1));
|
||||
+ if (!tmp) goto out;
|
||||
+ st->ids = tmp;
|
||||
+
|
||||
+ tmp = HeapReAlloc(GetProcessHeap(), 0, st->keys, sizeof(GUID) * (st->num + 1));
|
||||
+ if (!tmp) goto out;
|
||||
+ st->keys = tmp;
|
||||
+
|
||||
+ len = MultiByteToWideChar(CP_UTF8, 0, i->description, -1, NULL, 0);
|
||||
+ if (!len) goto out;
|
||||
+
|
||||
+ st->ids[st->num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||
+ if (!st->ids[st->num]) goto out;
|
||||
+
|
||||
+ MultiByteToWideChar(CP_UTF8, 0, i->description, -1, st->ids[st->num], len);
|
||||
+ if (!get_device_guid(st->flow, i->name, &(st->keys[st->num])))
|
||||
+ CoCreateGuid(&(st->keys[st->num]));
|
||||
+
|
||||
+ st->num++;
|
||||
+
|
||||
+out:
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **keys,
|
||||
UINT *num, UINT *def_index)
|
||||
static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
WCHAR *id;
|
||||
+ pa_operation* o;
|
||||
+ struct pulse_all_info_cb_data st;
|
||||
|
||||
TRACE("%d %p %p %p\n", flow, ids, num, def_index);
|
||||
|
||||
@@ -765,6 +903,27 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **
|
||||
else
|
||||
(*keys)[0] = pulse_capture_guid;
|
||||
|
||||
+ st.flow = flow;
|
||||
+ st.ids = *ids;
|
||||
+ st.keys = *keys;
|
||||
+ st.num = *num;
|
||||
- if (i)
|
||||
+ GUID guid;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ if (flow == eRender)
|
||||
+ o = pa_context_get_sink_info_list(pulse_ctx, &pulse_all_sink_info_cb, &st);
|
||||
+ else
|
||||
+ o = pa_context_get_source_info_list(pulse_ctx, &pulse_all_source_info_cb, &st);
|
||||
+ 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
|
||||
@@ -525,6 +624,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);
|
||||
@@ -572,6 +675,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 &&
|
||||
@@ -580,6 +686,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_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ while (pa_mainloop_iterate(ml, 1, &ret) >= 0 &&
|
||||
+ pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ {}
|
||||
+ pa_operation_unref(o);
|
||||
+ }
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+
|
||||
+ *ids = st.ids;
|
||||
+ *keys = st.keys;
|
||||
+ *num = st.num;
|
||||
pa_context_unref(ctx);
|
||||
pa_mainloop_free(ml);
|
||||
return S_OK;
|
||||
@@ -775,6 +889,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)
|
||||
@@ -799,12 +916,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;
|
||||
@@ -823,39 +949,53 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -777,20 +936,79 @@ int WINAPI AUDDRV_GetPriority(void)
|
||||
-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)
|
||||
@@ -867,20 +1007,79 @@ int WINAPI AUDDRV_GetPriority(void)
|
||||
return SUCCEEDED(hr) ? Priority_Preferred : Priority_Unavailable;
|
||||
}
|
||||
|
||||
@ -303,10 +385,10 @@ index 063b1db..8a75f0e 100644
|
||||
HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
|
||||
{
|
||||
+ char pulse_name[256] = {0};
|
||||
HRESULT hr;
|
||||
ACImpl *This;
|
||||
int i;
|
||||
EDataFlow dataflow;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
|
||||
+
|
||||
@ -320,8 +402,8 @@ index 063b1db..8a75f0e 100644
|
||||
+ return AUDCLNT_E_DEVICE_INVALIDATED;
|
||||
|
||||
*out = NULL;
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
@@ -813,6 +1031,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
|
||||
|
||||
@@ -898,6 +1097,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;
|
||||
@ -330,5 +412,5 @@ index 063b1db..8a75f0e 100644
|
||||
hr = CoCreateFreeThreadedMarshaler((IUnknown*)This, &This->marshal);
|
||||
if (hr) {
|
||||
--
|
||||
2.2.1
|
||||
2.6.2
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 1f92761fc130d432299df976841b77b60b64efa5 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 17/42] winepulse v12
|
||||
|
||||
Changes since v11:
|
||||
- Fix incorrect assertions which may fail on moving a capture device
|
||||
- Whitespace apply fixes
|
||||
|
||||
Changes since v10:
|
||||
- Make some members static
|
||||
- Fix small memory leak in GetService
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 5a71a3d..960af3c 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -596,10 +596,11 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
|
||||
dst = p->data;
|
||||
while (rem) {
|
||||
pa_stream_peek(This->stream, (const void**)&src, &src_len);
|
||||
- assert(src_len && src_len <= bytes);
|
||||
+ assert(src_len);
|
||||
assert(This->peek_ofs < src_len);
|
||||
src += This->peek_ofs;
|
||||
src_len -= This->peek_ofs;
|
||||
+ assert(src_len <= bytes);
|
||||
|
||||
copy = rem;
|
||||
if (copy > src_len)
|
||||
@@ -627,9 +628,10 @@ static void pulse_rd_drop(ACImpl *This, size_t bytes)
|
||||
while (rem) {
|
||||
const void *src;
|
||||
pa_stream_peek(This->stream, &src, &src_len);
|
||||
- assert(src_len && src_len <= bytes);
|
||||
+ assert(src_len);
|
||||
assert(This->peek_ofs < src_len);
|
||||
src_len -= This->peek_ofs;
|
||||
+ assert(src_len <= bytes);
|
||||
|
||||
copy = rem;
|
||||
if (copy > src_len)
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 81fda4861fddbb9683afe0761ae54b454765901f Mon Sep 17 00:00:00 2001
|
||||
From 13859577c7611936165d6b48ca9abcfa272844b2 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
|
||||
@ -8,10 +8,10 @@ Subject: winepulse: implement exclusive mode
|
||||
1 file changed, 19 insertions(+), 27 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index d29fa06..40eaaf2 100644
|
||||
index 9342762..5c00a88 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1416,6 +1416,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
@@ -1446,6 +1446,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
const GUID *sessionguid)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioClient(iface);
|
||||
@ -19,7 +19,7 @@ index d29fa06..40eaaf2 100644
|
||||
HRESULT hr = S_OK;
|
||||
UINT period_bytes;
|
||||
|
||||
@@ -1427,8 +1428,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
@@ -1457,8 +1458,6 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
|
||||
if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||
return AUDCLNT_E_NOT_INITIALIZED;
|
||||
@ -28,7 +28,7 @@ index d29fa06..40eaaf2 100644
|
||||
|
||||
if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS |
|
||||
AUDCLNT_STREAMFLAGS_LOOPBACK |
|
||||
@@ -1452,27 +1451,26 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
@@ -1492,27 +1491,26 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
if (FAILED(hr))
|
||||
goto exit;
|
||||
|
||||
@ -74,7 +74,7 @@ index d29fa06..40eaaf2 100644
|
||||
period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000);
|
||||
|
||||
if (duration < 20000000)
|
||||
@@ -1777,12 +1775,6 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
|
||||
@@ -1817,12 +1815,6 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
|
||||
else
|
||||
*out = closest;
|
||||
|
||||
@ -88,5 +88,5 @@ index d29fa06..40eaaf2 100644
|
||||
return hr;
|
||||
}
|
||||
--
|
||||
2.1.3
|
||||
2.6.2
|
||||
|
@ -1,41 +0,0 @@
|
||||
From 5761af9a26e1d84f53b698669efb9f33ee886635 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 18/42] winepulse v15: Add support for missing formats, and
|
||||
silence an error for missing format tags
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 17 ++++++++++++++++-
|
||||
1 file changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 960af3c..f52f119 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1109,7 +1109,22 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
}
|
||||
break;
|
||||
}
|
||||
- default: FIXME("Unhandled tag %x\n", fmt->wFormatTag);
|
||||
+ case WAVE_FORMAT_ALAW:
|
||||
+ case WAVE_FORMAT_MULAW:
|
||||
+ if (fmt->wBitsPerSample != 8) {
|
||||
+ FIXME("Unsupported bpp %u for LAW\n", fmt->wBitsPerSample);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ }
|
||||
+ if (fmt->nChannels != 1 && fmt->nChannels != 2) {
|
||||
+ FIXME("Unsupported channels %u for LAW\n", fmt->nChannels);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ }
|
||||
+ This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
|
||||
+ pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN("Unhandled tag %x\n", fmt->wFormatTag);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
This->ss.channels = This->map.channels;
|
||||
if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
From a879d7aa33f4d182d0b60c6991b0eb9e3e0f34fa Mon Sep 17 00:00:00 2001
|
||||
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
|
||||
@ -8,10 +8,10 @@ Subject: winepulse: fix segfault in pulse_rd_loop
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 6134850..37ff7ee 100644
|
||||
index 5c00a88..c6f4830 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -592,6 +592,7 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
|
||||
@@ -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);
|
||||
@ -20,5 +20,5 @@ index 6134850..37ff7ee 100644
|
||||
next = (ACPacket*)p->entry.next;
|
||||
next->discont = 1;
|
||||
--
|
||||
2.0.4
|
||||
2.6.2
|
||||
|
@ -1,79 +0,0 @@
|
||||
From f54d61ca3af7f60aa6e99046ea42542ac89305aa Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 19/42] winepulse v16: Add official warning wine doesn't want
|
||||
to support winepulse
|
||||
|
||||
And give an alternative place to ask for support.
|
||||
I wish it didn't have to come to this.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 25 +++++++++++++++++++++++--
|
||||
1 file changed, 23 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index f52f119..76a2e0e 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -59,6 +59,7 @@
|
||||
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(pulse);
|
||||
+WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
|
||||
static const REFERENCE_TIME MinimumPeriod = 30000;
|
||||
static const REFERENCE_TIME DefaultPeriod = 100000;
|
||||
@@ -81,6 +82,8 @@ const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
'W','i','n','e','\\','P','u','l','s','e',0};
|
||||
const WCHAR pulse_streamW[] = { 'S','t','r','e','a','m','V','o','l',0 };
|
||||
|
||||
+static HANDLE warn_once;
|
||||
+
|
||||
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
@@ -99,7 +102,10 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
}
|
||||
if (pulse_ml)
|
||||
pa_mainloop_quit(pulse_ml, 0);
|
||||
- CloseHandle(pulse_thread);
|
||||
+ if (pulse_thread)
|
||||
+ CloseHandle(pulse_thread);
|
||||
+ if (warn_once)
|
||||
+ CloseHandle(warn_once);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -758,6 +764,10 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
|
||||
int WINAPI AUDDRV_GetPriority(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
+ if (getenv("WINENOPULSE")) {
|
||||
+ FIXME_(winediag)("winepulse has been temporarily disabled through the environment\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
hr = pulse_connect();
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
@@ -771,7 +781,18 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
ACImpl *This;
|
||||
int i;
|
||||
|
||||
- TRACE("%p %p %d %p\n", key, dev, dataflow, out);
|
||||
+ /* Give one visible warning per session
|
||||
+ * Sadly wine has chosen not to accept the winepulse patch, so support ourselves
|
||||
+ */
|
||||
+ if (!warn_once && (warn_once = CreateEventA(0, 0, 0, "__winepulse_warn_event")) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
+ FIXME_(winediag)("Winepulse is not officially supported by the wine project\n");
|
||||
+ FIXME_(winediag)("For sound related feedback and support, please visit http://ubuntuforums.org/showthread.php?t=1960599\n");
|
||||
+ } else {
|
||||
+ WARN_(winediag)("Winepulse is not officially supported by the wine project\n");
|
||||
+ WARN_(winediag)("For sound related feedback and support, please visit http://ubuntuforums.org/showthread.php?t=1960599\n");
|
||||
+ }
|
||||
+
|
||||
+ TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
|
||||
if (dataflow != eRender && dataflow != eCapture)
|
||||
return E_UNEXPECTED;
|
||||
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,197 @@
|
||||
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
|
||||
|
@ -1,125 +0,0 @@
|
||||
From 534909554951611437c1c137d650dee651c4a7d9 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:03 +0200
|
||||
Subject: [PATCH 20/42] winepulse v17: Fix winmm tests
|
||||
|
||||
Handle dwChannelMask = SPEAKER_ALL better so WAVE_FORMAT_EXTENSIBLE tests pass too
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 72 +++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 56 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 76a2e0e..6e75674 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1066,6 +1066,8 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
This->ss.format = PA_SAMPLE_U8;
|
||||
else if (fmt->wBitsPerSample == 16)
|
||||
This->ss.format = PA_SAMPLE_S16LE;
|
||||
+ else
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
|
||||
break;
|
||||
case WAVE_FORMAT_EXTENSIBLE: {
|
||||
@@ -1102,13 +1104,16 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
This->ss.format = PA_SAMPLE_S24_32LE;
|
||||
else if (valid == 32)
|
||||
This->ss.format = PA_SAMPLE_S32LE;
|
||||
- default:
|
||||
break;
|
||||
+ default:
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
}
|
||||
This->map.channels = fmt->nChannels;
|
||||
- if (!mask)
|
||||
+ if (!mask || mask == SPEAKER_ALL)
|
||||
mask = get_channel_mask(fmt->nChannels);
|
||||
+ else if (mask == ~0U && fmt->nChannels == 1)
|
||||
+ mask = SPEAKER_FRONT_CENTER;
|
||||
for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
|
||||
if (mask & (1 << j))
|
||||
This->map.map[i++] = pulse_pos_from_wfx[j];
|
||||
@@ -1118,14 +1123,9 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
if (mask == SPEAKER_FRONT_CENTER)
|
||||
This->map.map[0] = PA_CHANNEL_POSITION_MONO;
|
||||
|
||||
- if ((mask & SPEAKER_ALL) && i < fmt->nChannels) {
|
||||
- This->map.map[i++] = PA_CHANNEL_POSITION_MONO;
|
||||
- FIXME("Is the 'all' channel mapped correctly?\n");
|
||||
- }
|
||||
-
|
||||
if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) {
|
||||
This->map.channels = 0;
|
||||
- ERR("Invalid channel mask: %i/%i and %x\n", i, fmt->nChannels, mask);
|
||||
+ ERR("Invalid channel mask: %i/%i and %x(%x)\n", i, fmt->nChannels, mask, wfe->dwChannelMask);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1383,15 +1383,55 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
|
||||
return E_INVALIDARG;
|
||||
if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||
return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
|
||||
- if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
- fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
|
||||
- return E_INVALIDARG;
|
||||
-
|
||||
- dump_fmt(fmt);
|
||||
-
|
||||
+ switch (fmt->wFormatTag) {
|
||||
+ case WAVE_FORMAT_EXTENSIBLE:
|
||||
+ if (fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
|
||||
+ return E_INVALIDARG;
|
||||
+ dump_fmt(fmt);
|
||||
+ break;
|
||||
+ case WAVE_FORMAT_ALAW:
|
||||
+ case WAVE_FORMAT_MULAW:
|
||||
+ case WAVE_FORMAT_IEEE_FLOAT:
|
||||
+ case WAVE_FORMAT_PCM:
|
||||
+ dump_fmt(fmt);
|
||||
+ break;
|
||||
+ default:
|
||||
+ dump_fmt(fmt);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ }
|
||||
+ if (fmt->nChannels == 0)
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
closest = clone_format(fmt);
|
||||
- if (!closest)
|
||||
- hr = E_OUTOFMEMORY;
|
||||
+ if (!closest) {
|
||||
+ if (out)
|
||||
+ *out = NULL;
|
||||
+ return E_OUTOFMEMORY;
|
||||
+ }
|
||||
+
|
||||
+ if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
+ UINT32 mask = 0, i, channels = 0;
|
||||
+ WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest;
|
||||
+
|
||||
+ if ((fmt->nChannels > 1 && ext->dwChannelMask == SPEAKER_ALL) ||
|
||||
+ (fmt->nChannels == 1 && ext->dwChannelMask == ~0U)) {
|
||||
+ mask = ext->dwChannelMask;
|
||||
+ channels = fmt->nChannels;
|
||||
+ } else if (ext->dwChannelMask) {
|
||||
+ for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
|
||||
+ if (i & ext->dwChannelMask) {
|
||||
+ mask |= i;
|
||||
+ channels++;
|
||||
+ }
|
||||
+ }
|
||||
+ if (channels < fmt->nChannels)
|
||||
+ mask = get_channel_mask(fmt->nChannels);
|
||||
+ } else
|
||||
+ mask = ext->dwChannelMask;
|
||||
+ if (ext->dwChannelMask != mask) {
|
||||
+ ext->dwChannelMask = mask;
|
||||
+ hr = S_FALSE;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if (hr == S_OK || !out) {
|
||||
CoTaskMemFree(closest);
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
From 4882a21ae315e9372d4d21a653a4ec7ce2d64896 Mon Sep 17 00:00:00 2001
|
||||
From 8062444d53d6bc1c669e4480abda2ada06477c18 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
|
||||
@ -14,7 +14,7 @@ Changes by Sebastian Lackner <sebastian@fds-team.de>:
|
||||
2 files changed, 116 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/Makefile.in b/dlls/winepulse.drv/Makefile.in
|
||||
index 3428329..1112575 100644
|
||||
index 5671c0d..ae49221 100644
|
||||
--- a/dlls/winepulse.drv/Makefile.in
|
||||
+++ b/dlls/winepulse.drv/Makefile.in
|
||||
@@ -1,5 +1,5 @@
|
||||
@ -25,7 +25,7 @@ index 3428329..1112575 100644
|
||||
EXTRALIBS = $(PULSE_LIBS) $(PTHREAD_LIBS)
|
||||
EXTRAINCL = $(PULSE_CFLAGS)
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 63b9786..356677c 100644
|
||||
index f9f421a..ca60dcb 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -43,6 +43,7 @@
|
||||
@ -36,8 +36,8 @@ index 63b9786..356677c 100644
|
||||
#include "dshow.h"
|
||||
#include "dsound.h"
|
||||
#include "propsys.h"
|
||||
@@ -402,6 +403,109 @@ static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) {
|
||||
}
|
||||
@@ -458,6 +459,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
|
||||
@ -146,7 +146,7 @@ index 63b9786..356677c 100644
|
||||
static HRESULT pulse_connect(void)
|
||||
{
|
||||
int len;
|
||||
@@ -425,14 +529,17 @@ static HRESULT pulse_connect(void)
|
||||
@@ -481,14 +585,17 @@ static HRESULT pulse_connect(void)
|
||||
pa_context_unref(pulse_ctx);
|
||||
|
||||
GetModuleFileNameW(NULL, path, sizeof(path)/sizeof(*path));
|
||||
@ -173,5 +173,5 @@ index 63b9786..356677c 100644
|
||||
pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str);
|
||||
pa_xfree(str);
|
||||
--
|
||||
2.2.1
|
||||
2.6.2
|
||||
|
@ -1,207 +0,0 @@
|
||||
From 4a9c7326546604233be84528ba56e10731296ca8 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 21/42] winepulse v18: Latency and compilation improvements
|
||||
|
||||
Changes since v17:
|
||||
- Remove clock_pulse interpolation
|
||||
* Couldn't work, sadly
|
||||
- Allow 2 * MinimumPeriod for shared buffers
|
||||
- Fix all compiler warnings when compiling with 64-bits
|
||||
- Dynamically select low latency mode if less than 2 default periods are request
|
||||
* This requires the rtkit patch to be useful
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 55 +++++++++++++++++--------------------------
|
||||
1 file changed, 22 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 6e75674..8e76826 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -169,7 +169,6 @@ struct ACImpl {
|
||||
pa_channel_map map;
|
||||
|
||||
INT64 clock_lastpos, clock_written;
|
||||
- pa_usec_t clock_pulse;
|
||||
|
||||
AudioSession *session;
|
||||
AudioSessionWrapper *session_wrapper;
|
||||
@@ -518,7 +517,6 @@ static void pulse_attr_update(pa_stream *s, void *user) {
|
||||
static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
|
||||
{
|
||||
ACImpl *This = userdata;
|
||||
- pa_usec_t time;
|
||||
UINT32 oldpad = This->pad;
|
||||
|
||||
if (bytes < This->bufsize_bytes)
|
||||
@@ -528,13 +526,8 @@ static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
|
||||
|
||||
assert(oldpad >= This->pad);
|
||||
|
||||
- if (0 && This->pad && pa_stream_get_time(This->stream, &time) >= 0)
|
||||
- This->clock_pulse = time;
|
||||
- else
|
||||
- This->clock_pulse = PA_USEC_INVALID;
|
||||
-
|
||||
This->clock_written += oldpad - This->pad;
|
||||
- TRACE("New pad: %u (-%u)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
|
||||
+ TRACE("New pad: %zu (-%zu)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
|
||||
|
||||
if (This->event)
|
||||
SetEvent(This->event);
|
||||
@@ -542,8 +535,6 @@ static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
|
||||
|
||||
static void pulse_underflow_callback(pa_stream *s, void *userdata)
|
||||
{
|
||||
- ACImpl *This = userdata;
|
||||
- This->clock_pulse = PA_USEC_INVALID;
|
||||
WARN("Underflow\n");
|
||||
}
|
||||
|
||||
@@ -562,12 +553,8 @@ static void pulse_latency_callback(pa_stream *s, void *userdata)
|
||||
static void pulse_started_callback(pa_stream *s, void *userdata)
|
||||
{
|
||||
ACImpl *This = userdata;
|
||||
- pa_usec_t time;
|
||||
|
||||
TRACE("(Re)started playing\n");
|
||||
- assert(This->clock_pulse == PA_USEC_INVALID);
|
||||
- if (0 && pa_stream_get_time(This->stream, &time) >= 0)
|
||||
- This->clock_pulse = time;
|
||||
if (This->event)
|
||||
SetEvent(This->event);
|
||||
}
|
||||
@@ -578,7 +565,7 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
|
||||
ACPacket *p, *next;
|
||||
LARGE_INTEGER stamp, freq;
|
||||
BYTE *dst, *src;
|
||||
- UINT32 src_len, copy, rem = This->capture_period;
|
||||
+ 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->discont) {
|
||||
@@ -630,7 +617,7 @@ static void pulse_rd_loop(ACImpl *This, size_t bytes)
|
||||
static void pulse_rd_drop(ACImpl *This, size_t bytes)
|
||||
{
|
||||
while (bytes >= This->capture_period) {
|
||||
- UINT32 src_len, copy, rem = This->capture_period;
|
||||
+ size_t src_len, copy, rem = This->capture_period;
|
||||
while (rem) {
|
||||
const void *src;
|
||||
pa_stream_peek(This->stream, &src, &src_len);
|
||||
@@ -660,7 +647,7 @@ static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata)
|
||||
{
|
||||
ACImpl *This = userdata;
|
||||
|
||||
- TRACE("Readable total: %u, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
|
||||
+ TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize);
|
||||
assert(bytes >= This->peek_ofs);
|
||||
bytes -= This->peek_ofs;
|
||||
if (bytes < This->capture_period)
|
||||
@@ -815,7 +802,6 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl;
|
||||
This->dataflow = dataflow;
|
||||
This->parent = dev;
|
||||
- This->clock_pulse = PA_USEC_INVALID;
|
||||
for (i = 0; i < PA_CHANNELS_MAX; ++i)
|
||||
This->vol[i] = 1.f;
|
||||
IMMDevice_AddRef(This->parent);
|
||||
@@ -1199,7 +1185,19 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
goto exit;
|
||||
|
||||
if (mode == AUDCLNT_SHAREMODE_SHARED) {
|
||||
- period = pulse_def_period[This->dataflow == eCapture];
|
||||
+ REFERENCE_TIME def = pulse_def_period[This->dataflow == eCapture];
|
||||
+ REFERENCE_TIME 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;
|
||||
}
|
||||
@@ -1510,7 +1508,6 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient *iface)
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return AUDCLNT_E_NOT_STOPPED;
|
||||
}
|
||||
- This->clock_pulse = PA_USEC_INVALID;
|
||||
|
||||
if (pa_stream_is_corked(This->stream)) {
|
||||
o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success);
|
||||
@@ -1566,7 +1563,6 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface)
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
This->started = FALSE;
|
||||
- This->clock_pulse = PA_USEC_INVALID;
|
||||
}
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return hr;
|
||||
@@ -1764,7 +1760,8 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
|
||||
UINT32 frames, BYTE **data)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
- UINT32 avail, pad, req, bytes = frames * pa_frame_size(&This->ss);
|
||||
+ size_t avail, req, bytes = frames * pa_frame_size(&This->ss);
|
||||
+ UINT32 pad;
|
||||
HRESULT hr = S_OK;
|
||||
int ret = -1;
|
||||
|
||||
@@ -1789,7 +1786,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
|
||||
avail = This->bufsize_frames - pad;
|
||||
if (avail < frames || bytes > This->bufsize_bytes) {
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
- WARN("Wanted to write %u, but only %u available\n", frames, avail);
|
||||
+ WARN("Wanted to write %u, but only %zu available\n", frames, avail);
|
||||
return AUDCLNT_E_BUFFER_TOO_LARGE;
|
||||
}
|
||||
|
||||
@@ -1797,7 +1794,7 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
|
||||
req = bytes;
|
||||
ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req);
|
||||
if (ret < 0 || req < bytes) {
|
||||
- FIXME("%p Not using pulse locked data: %i %u/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
|
||||
+ FIXME("%p Not using pulse locked data: %i %zu/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames);
|
||||
if (ret >= 0)
|
||||
pa_stream_cancel_write(This->stream);
|
||||
*data = This->tmp_buffer;
|
||||
@@ -1845,7 +1842,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
pa_stream_write(This->stream, This->tmp_buffer, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
This->pad += written_bytes;
|
||||
This->locked_ptr = NULL;
|
||||
- TRACE("Released %u, pad %u\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
+ TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
assert(This->pad <= This->bufsize_bytes);
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return S_OK;
|
||||
@@ -2053,7 +2050,6 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
UINT64 *qpctime)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioClock(iface);
|
||||
- pa_usec_t time;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)->(%p, %p)\n", This, pos, qpctime);
|
||||
@@ -2069,13 +2065,6 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
|
||||
}
|
||||
|
||||
*pos = This->clock_written;
|
||||
- if (This->clock_pulse != PA_USEC_INVALID && pa_stream_get_time(This->stream, &time) >= 0) {
|
||||
- UINT32 delta = pa_usec_to_bytes(time - This->clock_pulse, &This->ss);
|
||||
- if (delta < This->pad)
|
||||
- *pos += delta;
|
||||
- else
|
||||
- *pos += This->pad;
|
||||
- }
|
||||
|
||||
/* Make time never go backwards */
|
||||
if (*pos < This->clock_lastpos)
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,114 +0,0 @@
|
||||
From 87c12ec0ab5179a9460ee10096ace6e3fe8fa7d3 Mon Sep 17 00:00:00 2001
|
||||
From: Juergen Tretthahn <orson@orson.at>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 22/42] winepulse: API Compatibility with 1.5.2 onward, v2
|
||||
|
||||
V2: Add winepulse.drv.spec to commit too
|
||||
V1: Original version
|
||||
|
||||
Commit e87cb774d131963d2642d075977571585ec5da8d changed the driver api
|
||||
leave this commit out to build for builds prior to this
|
||||
|
||||
Not needed for: 1.5.1, 1.5 and 1.4 builds
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 34 ++++++++++++++++++++++------------
|
||||
dlls/winepulse.drv/winepulse.drv.spec | 2 +-
|
||||
2 files changed, 23 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 8e76826..b374b53 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -82,6 +82,11 @@ const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
'W','i','n','e','\\','P','u','l','s','e',0};
|
||||
const WCHAR pulse_streamW[] = { 'S','t','r','e','a','m','V','o','l',0 };
|
||||
|
||||
+static GUID pulse_render_guid =
|
||||
+{ 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
|
||||
+static GUID pulse_capture_guid =
|
||||
+{ 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } };
|
||||
+
|
||||
static HANDLE warn_once;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
@@ -716,7 +721,7 @@ static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
|
||||
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys,
|
||||
UINT *num, UINT *def_index)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
@@ -730,20 +735,21 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, void ***keys,
|
||||
*num = 1;
|
||||
*def_index = 0;
|
||||
|
||||
- *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *));
|
||||
+ *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids));
|
||||
if (!*ids)
|
||||
return E_OUTOFMEMORY;
|
||||
+ (*ids)[0] = defaultW;
|
||||
|
||||
- (*ids)[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
|
||||
- if (!(*ids)[0]) {
|
||||
+ *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys));
|
||||
+ if (!*keys) {
|
||||
HeapFree(GetProcessHeap(), 0, *ids);
|
||||
+ *ids = NULL;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
-
|
||||
- lstrcpyW((*ids)[0], defaultW);
|
||||
-
|
||||
- *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(void *));
|
||||
- (*keys)[0] = NULL;
|
||||
+ if (flow == eRender)
|
||||
+ (*keys)[0] = pulse_render_guid;
|
||||
+ else
|
||||
+ (*keys)[0] = pulse_capture_guid;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
@@ -761,12 +767,12 @@ int WINAPI AUDDRV_GetPriority(void)
|
||||
return SUCCEEDED(hr) ? 3 : 0;
|
||||
}
|
||||
|
||||
-HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
- EDataFlow dataflow, IAudioClient **out)
|
||||
+HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
|
||||
{
|
||||
HRESULT hr;
|
||||
ACImpl *This;
|
||||
int i;
|
||||
+ EDataFlow dataflow;
|
||||
|
||||
/* Give one visible warning per session
|
||||
* Sadly wine has chosen not to accept the winepulse patch, so support ourselves
|
||||
@@ -780,7 +786,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(void *key, IMMDevice *dev,
|
||||
}
|
||||
|
||||
TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
|
||||
- if (dataflow != eRender && dataflow != eCapture)
|
||||
+ if (IsEqualGUID(guid, &pulse_render_guid))
|
||||
+ dataflow = eRender;
|
||||
+ else if (IsEqualGUID(guid, &pulse_capture_guid))
|
||||
+ dataflow = eCapture;
|
||||
+ else
|
||||
return E_UNEXPECTED;
|
||||
|
||||
*out = NULL;
|
||||
diff --git a/dlls/winepulse.drv/winepulse.drv.spec b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
index a089166..612bf46 100644
|
||||
--- a/dlls/winepulse.drv/winepulse.drv.spec
|
||||
+++ b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
@@ -1,5 +1,5 @@
|
||||
# MMDevAPI driver functions
|
||||
@ stdcall -private GetPriority() AUDDRV_GetPriority
|
||||
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
|
||||
-@ stdcall -private GetAudioEndpoint(ptr ptr long ptr) AUDDRV_GetAudioEndpoint
|
||||
+@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint
|
||||
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
|
||||
--
|
||||
2.0.0
|
||||
|
@ -0,0 +1,123 @@
|
||||
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
|
||||
|
@ -1,58 +0,0 @@
|
||||
From c85625f7f671ee68050d9f83f2958fbb6d583c70 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 23/42] winepulse: Fix low latency support
|
||||
|
||||
Some games request a 20 ms buffer and will only fill 20 ms.
|
||||
Since 10 ms periods are too long in this case for winepulse,
|
||||
fill change period size to 5 ms and force a trigger if
|
||||
there's still data left to fill.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index b374b53..7c07f54 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1205,11 +1205,15 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
* default
|
||||
*/
|
||||
if (duration < 2 * def)
|
||||
- period = min;
|
||||
+ period = min;
|
||||
else
|
||||
- period = def;
|
||||
+ period = def;
|
||||
if (duration < 2 * period)
|
||||
duration = 2 * period;
|
||||
+
|
||||
+ /* 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);
|
||||
|
||||
@@ -1820,6 +1824,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
|
||||
+ UINT32 period;
|
||||
|
||||
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
|
||||
|
||||
@@ -1854,6 +1859,11 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
This->locked_ptr = NULL;
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
assert(This->pad <= This->bufsize_bytes);
|
||||
+
|
||||
+ period = pa_stream_get_buffer_attr(This->stream)->minreq;
|
||||
+ /* Require a minimum of 3 periods filled, if possible */
|
||||
+ if (This->event && This->pad + period <= This->bufsize_bytes && This->pad < period * 3)
|
||||
+ SetEvent(This->event);
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return S_OK;
|
||||
}
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,27 +0,0 @@
|
||||
From 4c58956caeaf8721ccbfd612175caf742797fffb Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 24/42] winepulse: drop realtime priority before thread
|
||||
destruction
|
||||
|
||||
prevents having to handle a kernel RT Watchdog Timeout.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 7c07f54..ba68102 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -101,6 +101,8 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
}
|
||||
DisableThreadLibraryCalls(dll);
|
||||
} 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);
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,29 +0,0 @@
|
||||
From c35b2f43436e6237542fe210d65c6e4e3b0819bd Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 25/42] winepulse: remove bogus SetEvent from
|
||||
pulse_started_callback
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 4 ----
|
||||
1 file changed, 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index ba68102..68de00c 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -559,11 +559,7 @@ static void pulse_latency_callback(pa_stream *s, void *userdata)
|
||||
|
||||
static void pulse_started_callback(pa_stream *s, void *userdata)
|
||||
{
|
||||
- ACImpl *This = userdata;
|
||||
-
|
||||
TRACE("(Re)started playing\n");
|
||||
- if (This->event)
|
||||
- SetEvent(This->event);
|
||||
}
|
||||
|
||||
static void pulse_rd_loop(ACImpl *This, size_t bytes)
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,42 +0,0 @@
|
||||
From 647aa74bd4a7a11065e8ee2c513d3fdd0584d1e7 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 26/42] winepulse: disable the setevent part of the latency
|
||||
hack
|
||||
|
||||
If you get playback glitches in skyrim or other games as a result of
|
||||
this patch, PLEASE REPORT TO ME!
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 68de00c..643d55e 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1822,7 +1822,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
|
||||
- UINT32 period;
|
||||
+// UINT32 period;
|
||||
|
||||
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
|
||||
|
||||
@@ -1858,10 +1858,10 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
assert(This->pad <= This->bufsize_bytes);
|
||||
|
||||
- period = pa_stream_get_buffer_attr(This->stream)->minreq;
|
||||
+// period = pa_stream_get_buffer_attr(This->stream)->minreq;
|
||||
/* Require a minimum of 3 periods filled, if possible */
|
||||
- if (This->event && This->pad + period <= This->bufsize_bytes && This->pad < period * 3)
|
||||
- SetEvent(This->event);
|
||||
+// if (This->event && This->pad + period <= This->bufsize_bytes && This->pad < period * 3)
|
||||
+// SetEvent(This->event);
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return S_OK;
|
||||
}
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,28 +0,0 @@
|
||||
From 824fc6ecfad213000ca8e93c147687530c34ea87 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 27/42] winepulse v20: fix the checks in IsFormatSupported
|
||||
|
||||
Thanks to DGhost001 for reporting and isolating the issue.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 643d55e..86dd10a 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1443,6 +1443,10 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
|
||||
}
|
||||
}
|
||||
|
||||
+ if (fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
|
||||
+ fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec)
|
||||
+ hr = S_FALSE;
|
||||
+
|
||||
if (hr == S_OK || !out) {
|
||||
CoTaskMemFree(closest);
|
||||
if (out)
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,413 +0,0 @@
|
||||
From e94c6ccaef68dbda1906e94c9f69dab20dacae4e Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 28/42] winepulse: fixup IsFormatSupported calls
|
||||
|
||||
---
|
||||
dlls/mmdevapi/tests/render.c | 164 +++++++++++++++++++++++++++++++++++++++
|
||||
dlls/winepulse.drv/mmdevdrv.c | 176 ++++++++++++++++++++++++++++--------------
|
||||
2 files changed, 283 insertions(+), 57 deletions(-)
|
||||
|
||||
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c
|
||||
index 4c8221b..c9e4636 100644
|
||||
--- a/dlls/mmdevapi/tests/render.c
|
||||
+++ b/dlls/mmdevapi/tests/render.c
|
||||
@@ -467,6 +467,169 @@ static void test_formats(AUDCLNT_SHAREMODE mode)
|
||||
}
|
||||
}
|
||||
|
||||
+static void test_formats2(void)
|
||||
+{
|
||||
+ IAudioClient *ac;
|
||||
+ HRESULT hr;
|
||||
+ WAVEFORMATEX *pwfx, *pwfx2;
|
||||
+ WAVEFORMATEXTENSIBLE *pwfe, wfe, *pwfe2;
|
||||
+
|
||||
+ hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
|
||||
+ NULL, (void**)&ac);
|
||||
+
|
||||
+ ok(hr == S_OK, "Activation failed with %08x\n", hr);
|
||||
+ if (hr != S_OK)
|
||||
+ return;
|
||||
+
|
||||
+ hr = IAudioClient_GetMixFormat(ac, &pwfx);
|
||||
+ ok(hr == S_OK, "GetMixFormat failed: %08x\n", hr);
|
||||
+ if (hr != S_OK)
|
||||
+ return;
|
||||
+
|
||||
+ ok(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE, "Invalid wFormatTag\n");
|
||||
+ if (pwfx->wFormatTag != WAVE_FORMAT_EXTENSIBLE) {
|
||||
+ CoTaskMemFree(pwfx);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ pwfe = (WAVEFORMATEXTENSIBLE*)pwfx;
|
||||
+ ok(pwfe->Samples.wValidBitsPerSample, "wValidBitsPerSample should be non-zero\n");
|
||||
+
|
||||
+ if (pwfx->nChannels > 2) {
|
||||
+ trace("Limiting channels to 2\n");
|
||||
+ pwfx->nChannels = 2;
|
||||
+ pwfx->nBlockAlign = pwfx->wBitsPerSample / 8 * pwfx->nChannels;
|
||||
+ pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
|
||||
+ pwfe->dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
+ }
|
||||
+
|
||||
+ wfe = *pwfe;
|
||||
+ pwfx->nAvgBytesPerSec = pwfx->nBlockAlign = 0;
|
||||
+
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with nAvgBytesPerSec=0 and nBlockAlign=0 returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok((hr == E_INVALIDARG || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && !pwfx2,
|
||||
+ "Shared IsFormatSupported with nAvgBytesPerSec=0 and nBlockAlign=0 returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ pwfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok((hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && !pwfx2,
|
||||
+ "Shared IsFormatSupported with nAvgBytesPerSec=0 and nBlockAlign=0 returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ *pwfe = wfe;
|
||||
+ pwfe->dwChannelMask = 0;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with dwChannelMask=0 returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == S_OK,
|
||||
+ "Shared IsFormatSupported with dwChannelMask=0 returned %08x\n", hr);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+
|
||||
+ pwfe->dwChannelMask = 0x3ffff;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with dwChannelMask=0x3ffff returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == S_OK && !pwfx2,
|
||||
+ "Shared IsFormatSupported with dwChannelMask=0x3ffff returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+
|
||||
+ pwfe->dwChannelMask = 0x40000000;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with dwChannelMask=0x40000000 returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == S_OK && !pwfx2,
|
||||
+ "Shared IsFormatSupported with dwChannelMask=0x40000000 returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ pwfe->dwChannelMask = SPEAKER_ALL | SPEAKER_RESERVED;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with dwChannelMask=SPEAKER_ALL | SPEAKER_RESERVED returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == S_OK && !pwfx2,
|
||||
+ "Shared IsFormatSupported with dwChannelMask=SPEAKER_ALL | SPEAKER_RESERVED returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ *pwfe = wfe;
|
||||
+ pwfe->Samples.wValidBitsPerSample = 0;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,
|
||||
+ "Exclusive IsFormatSupported with wValidBitsPerSample=0 returned %08x\n", hr);
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok((hr == S_FALSE || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && pwfx2,
|
||||
+ "Shared IsFormatSupported with wValidBitsPerSample=0 returned %08x %p\n", hr, pwfx2);
|
||||
+ if (pwfx2) {
|
||||
+ pwfe2 = (WAVEFORMATEXTENSIBLE*)pwfx2;
|
||||
+ ok(pwfe2->Samples.wValidBitsPerSample == pwfx->wBitsPerSample,
|
||||
+ "Shared IsFormatSupported had wValidBitsPerSample set to %u, not %u\n",
|
||||
+ pwfe2->Samples.wValidBitsPerSample, pwfx->wBitsPerSample);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+ }
|
||||
+
|
||||
+ pwfx2 = NULL;
|
||||
+ pwfe->Samples.wValidBitsPerSample = pwfx->wBitsPerSample + 1;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok((hr == E_INVALIDARG || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && !pwfx2,
|
||||
+ "Shared IsFormatSupported with wValidBitsPerSample += 1 returned %08x %p\n", hr, pwfx2);
|
||||
+
|
||||
+ *pwfe = wfe;
|
||||
+ memset(&pwfe->SubFormat, 0xff, 16);
|
||||
+ pwfx2 = NULL;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && !pwfx2,
|
||||
+ "Shared IsFormatSupported with SubFormat=-1 returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ *pwfe = wfe;
|
||||
+ pwfx2 = NULL;
|
||||
+ pwfe->Samples.wValidBitsPerSample = pwfx->wBitsPerSample = 256;
|
||||
+ pwfx->nBlockAlign = pwfx->wBitsPerSample / 8 * pwfx->nChannels;
|
||||
+ pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok((hr == E_INVALIDARG || hr == AUDCLNT_E_UNSUPPORTED_FORMAT) && !pwfx2,
|
||||
+ "Shared IsFormatSupported with wBitsPerSample=256 returned %08x %p\n", hr, pwfx2);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+
|
||||
+ *pwfe = wfe;
|
||||
+ pwfx2 = NULL;
|
||||
+ pwfe->Samples.wValidBitsPerSample = pwfx->wBitsPerSample - 1;
|
||||
+ hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2);
|
||||
+ ok(hr == S_FALSE && pwfx2,
|
||||
+ "Shared IsFormatSupported with wValidBitsPerSample-=1 returned %08x %p\n", hr, pwfx2);
|
||||
+ if (pwfx2) {
|
||||
+ pwfe2 = (WAVEFORMATEXTENSIBLE*)pwfx2;
|
||||
+ ok(pwfe2->Samples.wValidBitsPerSample == pwfx->wBitsPerSample,
|
||||
+ "Shared IsFormatSupported had wValidBitsPerSample set to %u, not %u\n",
|
||||
+ pwfe2->Samples.wValidBitsPerSample, pwfx->wBitsPerSample);
|
||||
+ CoTaskMemFree(pwfx2);
|
||||
+ }
|
||||
+
|
||||
+ CoTaskMemFree(pwfx);
|
||||
+ IAudioClient_Release(ac);
|
||||
+}
|
||||
+
|
||||
static void test_references(void)
|
||||
{
|
||||
IAudioClient *ac;
|
||||
@@ -2245,6 +2408,7 @@ START_TEST(render)
|
||||
test_audioclient();
|
||||
test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE);
|
||||
test_formats(AUDCLNT_SHAREMODE_SHARED);
|
||||
+ test_formats2();
|
||||
test_references();
|
||||
test_marshal();
|
||||
trace("Output to a MS-DOS console is particularly slow and disturbs timing.\n");
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 86dd10a..554a9fc 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1104,10 +1104,8 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
}
|
||||
}
|
||||
This->map.channels = fmt->nChannels;
|
||||
- if (!mask || mask == SPEAKER_ALL)
|
||||
+ if (!mask || (mask & (SPEAKER_ALL|SPEAKER_RESERVED)))
|
||||
mask = get_channel_mask(fmt->nChannels);
|
||||
- else if (mask == ~0U && fmt->nChannels == 1)
|
||||
- mask = SPEAKER_FRONT_CENTER;
|
||||
for (j = 0; j < sizeof(pulse_pos_from_wfx)/sizeof(*pulse_pos_from_wfx) && i < fmt->nChannels; ++j) {
|
||||
if (mask & (1 << j))
|
||||
This->map.map[i++] = pulse_pos_from_wfx[j];
|
||||
@@ -1381,83 +1379,147 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface,
|
||||
ACImpl *This = impl_from_IAudioClient(iface);
|
||||
HRESULT hr = S_OK;
|
||||
WAVEFORMATEX *closest = NULL;
|
||||
+ BOOL exclusive;
|
||||
|
||||
TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out);
|
||||
|
||||
- if (!fmt || (mode == AUDCLNT_SHAREMODE_SHARED && !out))
|
||||
+ if (!fmt)
|
||||
return E_POINTER;
|
||||
|
||||
if (out)
|
||||
*out = NULL;
|
||||
- if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||
+
|
||||
+ if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) {
|
||||
+ exclusive = 1;
|
||||
+ out = NULL;
|
||||
+ } else if (mode == AUDCLNT_SHAREMODE_SHARED) {
|
||||
+ exclusive = 0;
|
||||
+ if (!out)
|
||||
+ return E_POINTER;
|
||||
+ } else
|
||||
return E_INVALIDARG;
|
||||
- if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||
- return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED;
|
||||
- switch (fmt->wFormatTag) {
|
||||
- case WAVE_FORMAT_EXTENSIBLE:
|
||||
- if (fmt->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX))
|
||||
- return E_INVALIDARG;
|
||||
- dump_fmt(fmt);
|
||||
- break;
|
||||
- case WAVE_FORMAT_ALAW:
|
||||
- case WAVE_FORMAT_MULAW:
|
||||
- case WAVE_FORMAT_IEEE_FLOAT:
|
||||
- case WAVE_FORMAT_PCM:
|
||||
- dump_fmt(fmt);
|
||||
- break;
|
||||
- default:
|
||||
- dump_fmt(fmt);
|
||||
- return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
- }
|
||||
+
|
||||
if (fmt->nChannels == 0)
|
||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+
|
||||
closest = clone_format(fmt);
|
||||
- if (!closest) {
|
||||
- if (out)
|
||||
- *out = NULL;
|
||||
+ if (!closest)
|
||||
return E_OUTOFMEMORY;
|
||||
- }
|
||||
|
||||
- if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
- UINT32 mask = 0, i, channels = 0;
|
||||
+ dump_fmt(fmt);
|
||||
+
|
||||
+ switch (fmt->wFormatTag) {
|
||||
+ case WAVE_FORMAT_EXTENSIBLE: {
|
||||
WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest;
|
||||
|
||||
- if ((fmt->nChannels > 1 && ext->dwChannelMask == SPEAKER_ALL) ||
|
||||
- (fmt->nChannels == 1 && ext->dwChannelMask == ~0U)) {
|
||||
- mask = ext->dwChannelMask;
|
||||
- channels = fmt->nChannels;
|
||||
- } else if (ext->dwChannelMask) {
|
||||
- for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
|
||||
- if (i & ext->dwChannelMask) {
|
||||
- mask |= i;
|
||||
- channels++;
|
||||
+ if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) &&
|
||||
+ fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) ||
|
||||
+ fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels ||
|
||||
+ ext->Samples.wValidBitsPerSample > fmt->wBitsPerSample ||
|
||||
+ fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (exclusive) {
|
||||
+ UINT32 mask = 0, i, channels = 0;
|
||||
+
|
||||
+ if (!(ext->dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) {
|
||||
+ for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) {
|
||||
+ if (i & ext->dwChannelMask) {
|
||||
+ mask |= i;
|
||||
+ channels++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (channels != fmt->nChannels || (ext->dwChannelMask & ~mask)) {
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ break;
|
||||
}
|
||||
+ } else {
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ break;
|
||||
}
|
||||
- if (channels < fmt->nChannels)
|
||||
- mask = get_channel_mask(fmt->nChannels);
|
||||
- } else
|
||||
- mask = ext->dwChannelMask;
|
||||
- if (ext->dwChannelMask != mask) {
|
||||
- ext->dwChannelMask = mask;
|
||||
- hr = S_FALSE;
|
||||
}
|
||||
+
|
||||
+ if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) {
|
||||
+ if (fmt->wBitsPerSample != 32) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample) {
|
||||
+ hr = S_FALSE;
|
||||
+ ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
|
||||
+ }
|
||||
+ } else if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
|
||||
+ if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample &&
|
||||
+ !(fmt->wBitsPerSample == 32 &&
|
||||
+ ext->Samples.wValidBitsPerSample == 24)) {
|
||||
+ hr = S_FALSE;
|
||||
+ ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample;
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
}
|
||||
|
||||
- if (fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 ||
|
||||
- fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec)
|
||||
- hr = S_FALSE;
|
||||
+ case WAVE_FORMAT_ALAW:
|
||||
+ case WAVE_FORMAT_MULAW:
|
||||
+ if (fmt->wBitsPerSample != 8) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* Fall-through */
|
||||
+ case WAVE_FORMAT_IEEE_FLOAT:
|
||||
+ if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* Fall-through */
|
||||
+ case WAVE_FORMAT_PCM:
|
||||
+ if (fmt->wFormatTag == WAVE_FORMAT_PCM &&
|
||||
+ (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) {
|
||||
+ hr = E_INVALIDARG;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (fmt->nChannels > 2) {
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ break;
|
||||
+ }
|
||||
+ /*
|
||||
+ * fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be
|
||||
+ * ignored, invalid values are happily accepted.
|
||||
+ */
|
||||
+ break;
|
||||
+ default:
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
- if (hr == S_OK || !out) {
|
||||
+ if (exclusive && hr != S_OK) {
|
||||
+ hr = AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
CoTaskMemFree(closest);
|
||||
- if (out)
|
||||
- *out = NULL;
|
||||
- } else if (closest) {
|
||||
- closest->nBlockAlign =
|
||||
- closest->nChannels * closest->wBitsPerSample / 8;
|
||||
- closest->nAvgBytesPerSec =
|
||||
- closest->nBlockAlign * closest->nSamplesPerSec;
|
||||
+ } else if (hr != S_FALSE)
|
||||
+ CoTaskMemFree(closest);
|
||||
+ 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.0.0
|
||||
|
@ -1,28 +0,0 @@
|
||||
From c334a7107c408e86154e4968003a28b8a5322e62 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:04 +0200
|
||||
Subject: [PATCH 29/42] winepulse v21: return early if padding didn't update
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 554a9fc..a4575d5 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -531,7 +531,10 @@ static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata)
|
||||
else
|
||||
This->pad = 0;
|
||||
|
||||
- assert(oldpad >= This->pad);
|
||||
+ if (oldpad == This->pad)
|
||||
+ return;
|
||||
+
|
||||
+ assert(oldpad > This->pad);
|
||||
|
||||
This->clock_written += oldpad - This->pad;
|
||||
TRACE("New pad: %zu (-%zu)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss));
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,36 +0,0 @@
|
||||
From 653e4912a248101e5451eec21a9e7a07dce8a49a Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:05 +0200
|
||||
Subject: [PATCH 30/42] winepulse: fix unneeded free in write..
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index a4575d5..3ca68fd 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1886,6 +1886,10 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
|
||||
return hr;
|
||||
}
|
||||
|
||||
+static void pulse_free_noop(void *buf)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
IAudioRenderClient *iface, UINT32 written_frames, DWORD flags)
|
||||
{
|
||||
@@ -1921,7 +1925,7 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
if (This->locked_ptr)
|
||||
pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
else
|
||||
- pa_stream_write(This->stream, This->tmp_buffer, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
+ pa_stream_write(This->stream, This->tmp_buffer, written_bytes, pulse_free_noop, 0, PA_SEEK_RELATIVE);
|
||||
This->pad += written_bytes;
|
||||
This->locked_ptr = NULL;
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,51 +0,0 @@
|
||||
From 6a3d42407535ce71761d41f47e6b0a49938d77d1 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:05 +0200
|
||||
Subject: [PATCH 31/42] winepulse v23: fixup a invalid free in mmdevapi
|
||||
|
||||
array members of ids should be dynamically allocated, judging from valgrind output.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 12 ++++++++++--
|
||||
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 3ca68fd..5b041a2 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -726,6 +726,8 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **
|
||||
UINT *num, UINT *def_index)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
+ WCHAR *id;
|
||||
+
|
||||
TRACE("%d %p %p %p\n", flow, ids, num, def_index);
|
||||
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
@@ -737,16 +739,22 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **
|
||||
*def_index = 0;
|
||||
|
||||
*ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids));
|
||||
+ *keys = NULL;
|
||||
if (!*ids)
|
||||
return E_OUTOFMEMORY;
|
||||
- (*ids)[0] = defaultW;
|
||||
|
||||
+ (*ids)[0] = id = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW));
|
||||
*keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys));
|
||||
- if (!*keys) {
|
||||
+ if (!*keys || !id) {
|
||||
+ HeapFree(GetProcessHeap(), 0, id);
|
||||
+ HeapFree(GetProcessHeap(), 0, *keys);
|
||||
HeapFree(GetProcessHeap(), 0, *ids);
|
||||
*ids = NULL;
|
||||
+ *keys = NULL;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
+ memcpy(id, defaultW, sizeof(defaultW));
|
||||
+
|
||||
if (flow == eRender)
|
||||
(*keys)[0] = pulse_render_guid;
|
||||
else
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,67 +0,0 @@
|
||||
From d6baba9b8c742b672121ad283fdee54135f46e7a Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:05 +0200
|
||||
Subject: [PATCH 38/42] winepulse: use a pi-mutex for serialization.
|
||||
|
||||
The winepulse thread is realtime, to prevent blocking it indefinitely
|
||||
use priority inheritance. Only initialize and release are potentially
|
||||
unsafe, the rest should be ok with -rt.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 5b041a2..a09ce7f 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define COBJMACROS
|
||||
+#define _GNU_SOURCE
|
||||
+
|
||||
#include "config.h"
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
@@ -30,6 +32,7 @@
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
+#include <errno.h>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
@@ -68,7 +71,7 @@ static pa_context *pulse_ctx;
|
||||
static pa_mainloop *pulse_ml;
|
||||
|
||||
static HANDLE pulse_thread;
|
||||
-static pthread_mutex_t pulse_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
+static pthread_mutex_t pulse_lock;
|
||||
static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER;
|
||||
static struct list g_sessions = LIST_INIT(g_sessions);
|
||||
|
||||
@@ -93,6 +96,8 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
HKEY key;
|
||||
+ pthread_mutexattr_t attr;
|
||||
+
|
||||
if (RegOpenKeyW(HKEY_CURRENT_USER, pulse_keyW, &key) == ERROR_SUCCESS) {
|
||||
DWORD size = sizeof(pulse_stream_volume);
|
||||
RegQueryValueExW(key, pulse_streamW, 0, NULL,
|
||||
@@ -100,6 +105,12 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
RegCloseKey(key);
|
||||
}
|
||||
DisableThreadLibraryCalls(dll);
|
||||
+
|
||||
+ pthread_mutexattr_init(&attr);
|
||||
+ pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
|
||||
+
|
||||
+ if (pthread_mutex_init(&pulse_lock, &attr) != 0)
|
||||
+ pthread_mutex_init(&pulse_lock, NULL);
|
||||
} else if (reason == DLL_PROCESS_DETACH) {
|
||||
if (pulse_thread)
|
||||
SetThreadPriority(pulse_thread, 0);
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,137 +0,0 @@
|
||||
From 2e64f15c657e318118c582361bee81ad37dca872 Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <maarten.lankhorst@canonical.com>
|
||||
Date: Mon, 14 Jul 2014 09:50:05 +0200
|
||||
Subject: [PATCH 39/42] winepulse: add support for IMarshal
|
||||
|
||||
Fixes bug 32161 for winepulse. Based On Jeff Klein's patches for the
|
||||
other drivers.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 31 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 31 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index a09ce7f..f052a08 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -169,6 +169,7 @@ struct ACImpl {
|
||||
IAudioClock IAudioClock_iface;
|
||||
IAudioClock2 IAudioClock2_iface;
|
||||
IAudioStreamVolume IAudioStreamVolume_iface;
|
||||
+ IUnknown *marshal;
|
||||
IMMDevice *parent;
|
||||
struct list entry;
|
||||
float vol[PA_CHANNELS_MAX];
|
||||
@@ -834,6 +835,12 @@ 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;
|
||||
+
|
||||
+ hr = CoCreateFreeThreadedMarshaler((IUnknown*)This, &This->marshal);
|
||||
+ if (hr) {
|
||||
+ HeapFree(GetProcessHeap(), 0, This);
|
||||
+ return hr;
|
||||
+ }
|
||||
IMMDevice_AddRef(This->parent);
|
||||
|
||||
*out = &This->IAudioClient_iface;
|
||||
@@ -845,10 +852,13 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
|
||||
static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
|
||||
REFIID riid, void **ppv)
|
||||
{
|
||||
+ ACImpl *This = impl_from_IAudioClient(iface);
|
||||
+
|
||||
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
|
||||
if (!ppv)
|
||||
return E_POINTER;
|
||||
+
|
||||
*ppv = NULL;
|
||||
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient))
|
||||
*ppv = iface;
|
||||
@@ -856,6 +866,10 @@ static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface,
|
||||
IUnknown_AddRef((IUnknown*)*ppv);
|
||||
return S_OK;
|
||||
}
|
||||
+
|
||||
+ if (IsEqualIID(riid, &IID_IMarshal))
|
||||
+ return IUnknown_QueryInterface(This->marshal, riid, ppv);
|
||||
+
|
||||
WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
@@ -888,6 +902,7 @@ static ULONG WINAPI AudioClient_Release(IAudioClient *iface)
|
||||
list_remove(&This->entry);
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
}
|
||||
+ IUnknown_Release(This->marshal);
|
||||
IMMDevice_Release(This->parent);
|
||||
HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
@@ -1826,6 +1841,7 @@ static const IAudioClientVtbl AudioClient_Vtbl =
|
||||
static HRESULT WINAPI AudioRenderClient_QueryInterface(
|
||||
IAudioRenderClient *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
+ ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
|
||||
if (!ppv)
|
||||
@@ -1840,6 +1856,9 @@ static HRESULT WINAPI AudioRenderClient_QueryInterface(
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+ if (IsEqualIID(riid, &IID_IMarshal))
|
||||
+ return IUnknown_QueryInterface(This->marshal, riid, ppv);
|
||||
+
|
||||
WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
@@ -1969,6 +1988,7 @@ static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = {
|
||||
static HRESULT WINAPI AudioCaptureClient_QueryInterface(
|
||||
IAudioCaptureClient *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
+ ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
|
||||
if (!ppv)
|
||||
@@ -1983,6 +2003,9 @@ static HRESULT WINAPI AudioCaptureClient_QueryInterface(
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+ if (IsEqualIID(riid, &IID_IMarshal))
|
||||
+ return IUnknown_QueryInterface(This->marshal, riid, ppv);
|
||||
+
|
||||
WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
@@ -2125,6 +2148,9 @@ static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+ if (IsEqualIID(riid, &IID_IMarshal))
|
||||
+ return IUnknown_QueryInterface(This->marshal, riid, ppv);
|
||||
+
|
||||
WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
@@ -2260,6 +2286,8 @@ static const IAudioClock2Vtbl AudioClock2_Vtbl =
|
||||
static HRESULT WINAPI AudioStreamVolume_QueryInterface(
|
||||
IAudioStreamVolume *iface, REFIID riid, void **ppv)
|
||||
{
|
||||
+ ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
+
|
||||
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
||||
|
||||
if (!ppv)
|
||||
@@ -2274,6 +2302,9 @@ static HRESULT WINAPI AudioStreamVolume_QueryInterface(
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+ if (IsEqualIID(riid, &IID_IMarshal))
|
||||
+ return IUnknown_QueryInterface(This->marshal, riid, ppv);
|
||||
+
|
||||
WARN("Unknown interface %s\n", debugstr_guid(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
--
|
||||
2.0.0
|
||||
|
@ -1,206 +0,0 @@
|
||||
From b7e889389b27ee3074e74a72ff3be9c3e4b6d77a Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Mon, 5 Jan 2015 11:31:56 +0100
|
||||
Subject: winepulse: Trivial cleanups and changes for consistency with other
|
||||
drivers
|
||||
|
||||
Removes some C++ comments, the FIXME's and fixes indent some.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 86 +++++++++++++++++--------------------------
|
||||
1 file changed, 33 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index e755e8a..62d040a 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -16,8 +16,6 @@
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
- *
|
||||
- * Pulseaudio driver support.. hell froze over
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
@@ -62,7 +60,14 @@
|
||||
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(pulse);
|
||||
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
+
|
||||
+/* From <dlls/mmdevapi/mmdevapi.h> */
|
||||
+enum DriverPriority {
|
||||
+ Priority_Unavailable = 0,
|
||||
+ Priority_Low,
|
||||
+ Priority_Neutral,
|
||||
+ Priority_Preferred
|
||||
+};
|
||||
|
||||
static const REFERENCE_TIME MinimumPeriod = 30000;
|
||||
static const REFERENCE_TIME DefaultPeriod = 100000;
|
||||
@@ -90,8 +95,6 @@ static GUID pulse_render_guid =
|
||||
static GUID pulse_capture_guid =
|
||||
{ 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } };
|
||||
|
||||
-static HANDLE warn_once;
|
||||
-
|
||||
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
@@ -122,8 +125,6 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
pa_mainloop_quit(pulse_ml, 0);
|
||||
if (pulse_thread)
|
||||
CloseHandle(pulse_thread);
|
||||
- if (warn_once)
|
||||
- CloseHandle(warn_once);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -507,6 +508,11 @@ static HRESULT pulse_stream_valid(ACImpl *This) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
+static void silence_buffer(pa_sample_format_t format, BYTE *buffer, UINT32 bytes)
|
||||
+{
|
||||
+ memset(buffer, format == PA_SAMPLE_U8 ? 0x80 : 0, bytes);
|
||||
+}
|
||||
+
|
||||
static void dump_attr(const pa_buffer_attr *attr) {
|
||||
TRACE("maxlength: %u\n", attr->maxlength);
|
||||
TRACE("minreq: %u\n", attr->minreq);
|
||||
@@ -784,14 +790,10 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **
|
||||
int WINAPI AUDDRV_GetPriority(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
- if (getenv("WINENOPULSE")) {
|
||||
- FIXME_(winediag)("winepulse has been temporarily disabled through the environment\n");
|
||||
- return 0;
|
||||
- }
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
hr = pulse_connect();
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
- return SUCCEEDED(hr) ? 3 : 0;
|
||||
+ return SUCCEEDED(hr) ? Priority_Preferred : Priority_Unavailable;
|
||||
}
|
||||
|
||||
HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out)
|
||||
@@ -801,17 +803,6 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
|
||||
int i;
|
||||
EDataFlow dataflow;
|
||||
|
||||
- /* Give one visible warning per session
|
||||
- * Sadly wine has chosen not to accept the winepulse patch, so support ourselves
|
||||
- */
|
||||
- if (!warn_once && (warn_once = CreateEventA(0, 0, 0, "__winepulse_warn_event")) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
- FIXME_(winediag)("Winepulse is not officially supported by the wine project\n");
|
||||
- FIXME_(winediag)("For sound related feedback and support, please visit http://ubuntuforums.org/showthread.php?t=1960599\n");
|
||||
- } else {
|
||||
- WARN_(winediag)("Winepulse is not officially supported by the wine project\n");
|
||||
- WARN_(winediag)("For sound related feedback and support, please visit http://ubuntuforums.org/showthread.php?t=1960599\n");
|
||||
- }
|
||||
-
|
||||
TRACE("%s %p %p\n", debugstr_guid(guid), dev, out);
|
||||
if (IsEqualGUID(guid, &pulse_render_guid))
|
||||
dataflow = eRender;
|
||||
@@ -1165,22 +1156,22 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt)
|
||||
}
|
||||
break;
|
||||
}
|
||||
- case WAVE_FORMAT_ALAW:
|
||||
- case WAVE_FORMAT_MULAW:
|
||||
- if (fmt->wBitsPerSample != 8) {
|
||||
- FIXME("Unsupported bpp %u for LAW\n", fmt->wBitsPerSample);
|
||||
- return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
- }
|
||||
- if (fmt->nChannels != 1 && fmt->nChannels != 2) {
|
||||
- FIXME("Unsupported channels %u for LAW\n", fmt->nChannels);
|
||||
- return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
- }
|
||||
- This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
|
||||
- pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
|
||||
- break;
|
||||
- default:
|
||||
- WARN("Unhandled tag %x\n", fmt->wFormatTag);
|
||||
+ case WAVE_FORMAT_ALAW:
|
||||
+ case WAVE_FORMAT_MULAW:
|
||||
+ if (fmt->wBitsPerSample != 8) {
|
||||
+ FIXME("Unsupported bpp %u for LAW\n", fmt->wBitsPerSample);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ }
|
||||
+ if (fmt->nChannels != 1 && fmt->nChannels != 2) {
|
||||
+ FIXME("Unsupported channels %u for LAW\n", fmt->nChannels);
|
||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
+ }
|
||||
+ This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW;
|
||||
+ pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA);
|
||||
+ break;
|
||||
+ default:
|
||||
+ WARN("Unhandled tag %x\n", fmt->wFormatTag);
|
||||
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
This->ss.channels = This->map.channels;
|
||||
if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) {
|
||||
@@ -1287,7 +1278,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface,
|
||||
else {
|
||||
ACPacket *cur_packet = (ACPacket*)((char*)This->tmp_buffer + This->bufsize_bytes);
|
||||
BYTE *data = This->tmp_buffer;
|
||||
- memset(This->tmp_buffer, This->ss.format == PA_SAMPLE_U8 ? 0x80 : 0, This->bufsize_bytes);
|
||||
+ silence_buffer(This->ss.format, This->tmp_buffer, This->bufsize_bytes);
|
||||
list_init(&This->packet_free_head);
|
||||
list_init(&This->packet_filled_head);
|
||||
for (i = 0; i < capture_packets; ++i, ++cur_packet) {
|
||||
@@ -1939,7 +1930,6 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioRenderClient(iface);
|
||||
UINT32 written_bytes = written_frames * pa_frame_size(&This->ss);
|
||||
-// UINT32 period;
|
||||
|
||||
TRACE("(%p)->(%u, %x)\n", This, written_frames, flags);
|
||||
|
||||
@@ -1958,12 +1948,8 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
return AUDCLNT_E_INVALID_SIZE;
|
||||
}
|
||||
|
||||
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
- if (This->ss.format == PA_SAMPLE_U8)
|
||||
- memset(This->tmp_buffer, 128, written_bytes);
|
||||
- else
|
||||
- memset(This->tmp_buffer, 0, written_bytes);
|
||||
- }
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
+ silence_buffer(This->ss.format, This->tmp_buffer, written_bytes);
|
||||
|
||||
This->locked = 0;
|
||||
if (This->locked_ptr)
|
||||
@@ -1975,10 +1961,6 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
assert(This->pad <= This->bufsize_bytes);
|
||||
|
||||
-// period = pa_stream_get_buffer_attr(This->stream)->minreq;
|
||||
- /* Require a minimum of 3 periods filled, if possible */
|
||||
-// if (This->event && This->pad + period <= This->bufsize_bytes && This->pad < period * 3)
|
||||
-// SetEvent(This->event);
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
return S_OK;
|
||||
}
|
||||
@@ -2107,7 +2089,6 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
|
||||
IAudioCaptureClient *iface, UINT32 *frames)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioCaptureClient(iface);
|
||||
- ACPacket *p;
|
||||
|
||||
TRACE("(%p)->(%p)\n", This, frames);
|
||||
if (!frames)
|
||||
@@ -2115,8 +2096,7 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
|
||||
|
||||
pthread_mutex_lock(&pulse_lock);
|
||||
ACImpl_GetCapturePad(This, NULL);
|
||||
- p = This->locked_ptr;
|
||||
- if (p)
|
||||
+ if (This->locked_ptr)
|
||||
*frames = This->capture_period / pa_frame_size(&This->ss);
|
||||
else
|
||||
*frames = 0;
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,59 +0,0 @@
|
||||
From 8e167d31b37ed7b6bcd89422dc810f8046d99fbd Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Mon, 5 Jan 2015 11:31:56 +0100
|
||||
Subject: winepulse: Sync default channel masks with other drivers
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 26 +++++++++-----------------
|
||||
1 file changed, 9 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 62d040a..1ef2ea2 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -964,33 +964,25 @@ static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt)
|
||||
|
||||
static DWORD get_channel_mask(unsigned int channels)
|
||||
{
|
||||
- switch(channels) {
|
||||
+ switch(channels){
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
- return SPEAKER_FRONT_CENTER;
|
||||
+ return KSAUDIO_SPEAKER_MONO;
|
||||
case 2:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
|
||||
+ return KSAUDIO_SPEAKER_STEREO;
|
||||
case 3:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
|
||||
- SPEAKER_LOW_FREQUENCY;
|
||||
+ return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY;
|
||||
case 4:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
|
||||
- SPEAKER_BACK_RIGHT;
|
||||
+ return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */
|
||||
case 5:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
|
||||
- SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY;
|
||||
+ return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY;
|
||||
case 6:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
|
||||
- SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER;
|
||||
+ return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */
|
||||
case 7:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
|
||||
- SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
|
||||
- SPEAKER_BACK_CENTER;
|
||||
+ return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER;
|
||||
case 8:
|
||||
- return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT |
|
||||
- SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_FRONT_CENTER |
|
||||
- SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
|
||||
+ return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */
|
||||
}
|
||||
FIXME("Unknown speaker configuration: %u\n", channels);
|
||||
return 0;
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,39 +0,0 @@
|
||||
From 833ed01b5a7619f983590ce4140fd621ded8674a Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Mon, 5 Jan 2015 11:31:56 +0100
|
||||
Subject: winepulse: Always mute buffer
|
||||
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 13 ++++++++-----
|
||||
1 file changed, 8 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 3463cd8..ba38ab9 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -1940,14 +1940,17 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
|
||||
return AUDCLNT_E_INVALID_SIZE;
|
||||
}
|
||||
|
||||
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
- silence_buffer(This->ss.format, This->tmp_buffer, written_bytes);
|
||||
-
|
||||
This->locked = 0;
|
||||
- if (This->locked_ptr)
|
||||
+ if (This->locked_ptr) {
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
+ silence_buffer(This->ss.format, This->locked_ptr, written_bytes);
|
||||
pa_stream_write(This->stream, This->locked_ptr, written_bytes, NULL, 0, PA_SEEK_RELATIVE);
|
||||
- else
|
||||
+ } else {
|
||||
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
|
||||
+ silence_buffer(This->ss.format, This->tmp_buffer, written_bytes);
|
||||
pa_stream_write(This->stream, This->tmp_buffer, written_bytes, pulse_free_noop, 0, PA_SEEK_RELATIVE);
|
||||
+ }
|
||||
+
|
||||
This->pad += written_bytes;
|
||||
This->locked_ptr = NULL;
|
||||
TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss));
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,166 +0,0 @@
|
||||
From daa8631528ad331f094c148a6267b135d101d066 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Eikum <aeikum@codeweavers.com>
|
||||
Date: Mon, 5 Jan 2015 11:31:56 +0100
|
||||
Subject: winepulse: Remove volume support
|
||||
|
||||
This was disabled by default, and a quick Google turned up no references
|
||||
to anyone being told to set it. If no one's using it, let's just remove
|
||||
it.
|
||||
---
|
||||
dlls/winepulse.drv/mmdevdrv.c | 90 +++----------------------------------------
|
||||
1 file changed, 6 insertions(+), 84 deletions(-)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index ba38ab9..063b1db 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -84,12 +84,6 @@ static struct list g_sessions = LIST_INIT(g_sessions);
|
||||
static WAVEFORMATEXTENSIBLE pulse_fmt[2];
|
||||
static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2];
|
||||
|
||||
-static DWORD pulse_stream_volume;
|
||||
-
|
||||
-const WCHAR pulse_keyW[] = {'S','o','f','t','w','a','r','e','\\',
|
||||
- 'W','i','n','e','\\','P','u','l','s','e',0};
|
||||
-const WCHAR pulse_streamW[] = { 'S','t','r','e','a','m','V','o','l',0 };
|
||||
-
|
||||
static GUID pulse_render_guid =
|
||||
{ 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } };
|
||||
static GUID pulse_capture_guid =
|
||||
@@ -98,15 +92,8 @@ static GUID pulse_capture_guid =
|
||||
BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
- HKEY key;
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
- if (RegOpenKeyW(HKEY_CURRENT_USER, pulse_keyW, &key) == ERROR_SUCCESS) {
|
||||
- DWORD size = sizeof(pulse_stream_volume);
|
||||
- RegQueryValueExW(key, pulse_streamW, 0, NULL,
|
||||
- (BYTE*)&pulse_stream_volume, &size);
|
||||
- RegCloseKey(key);
|
||||
- }
|
||||
DisableThreadLibraryCalls(dll);
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
@@ -527,12 +514,6 @@ static void pulse_op_cb(pa_stream *s, int success, void *user) {
|
||||
pthread_cond_signal(&pulse_cond);
|
||||
}
|
||||
|
||||
-static void pulse_ctx_op_cb(pa_context *c, int success, void *user) {
|
||||
- TRACE("Success: %i\n", success);
|
||||
- *(int*)user = success;
|
||||
- pthread_cond_signal(&pulse_cond);
|
||||
-}
|
||||
-
|
||||
static void pulse_attr_update(pa_stream *s, void *user) {
|
||||
const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s);
|
||||
TRACE("New attributes or device moved:\n");
|
||||
@@ -2329,36 +2310,12 @@ struct pulse_info_cb_data {
|
||||
float *levels;
|
||||
};
|
||||
|
||||
-static void pulse_sink_input_info_cb(pa_context *c, const pa_sink_input_info *info, int eol, void *data)
|
||||
-{
|
||||
- struct pulse_info_cb_data *d = data;
|
||||
- int i;
|
||||
- if (eol)
|
||||
- return;
|
||||
- for (i = 0; i < d->n; ++i)
|
||||
- d->levels[i] = (float)info->volume.values[i] / (float)PA_VOLUME_NORM;
|
||||
- pthread_cond_signal(&pulse_cond);
|
||||
-}
|
||||
-
|
||||
-static void pulse_source_info_cb(pa_context *c, const pa_source_info *info, int eol, void *data)
|
||||
-{
|
||||
- struct pulse_info_cb_data *d = data;
|
||||
- int i;
|
||||
- if (eol)
|
||||
- return;
|
||||
- for (i = 0; i < d->n; ++i)
|
||||
- d->levels[i] = (float)info->volume.values[i] / (float)PA_VOLUME_NORM;
|
||||
- pthread_cond_signal(&pulse_cond);
|
||||
-}
|
||||
-
|
||||
static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
|
||||
IAudioStreamVolume *iface, UINT32 count, const float *levels)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
- pa_operation *o;
|
||||
HRESULT hr;
|
||||
- int success = 0, i;
|
||||
- pa_cvolume cv;
|
||||
+ int i;
|
||||
|
||||
TRACE("(%p)->(%d, %p)\n", This, count, levels);
|
||||
|
||||
@@ -2373,26 +2330,8 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
|
||||
if (FAILED(hr))
|
||||
goto out;
|
||||
|
||||
- if (pulse_stream_volume) {
|
||||
- cv.channels = count;
|
||||
- for (i = 0; i < cv.channels; ++i)
|
||||
- cv.values[i] = levels[i] * (float)PA_VOLUME_NORM;
|
||||
- if (This->dataflow == eRender)
|
||||
- o = pa_context_set_sink_input_volume(pulse_ctx, pa_stream_get_index(This->stream), &cv, pulse_ctx_op_cb, &success);
|
||||
- else
|
||||
- o = pa_context_set_source_volume_by_index(pulse_ctx, pa_stream_get_device_index(This->stream), &cv, pulse_ctx_op_cb, &success);
|
||||
- if (o) {
|
||||
- while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
- pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
- pa_operation_unref(o);
|
||||
- }
|
||||
- if (!success)
|
||||
- hr = AUDCLNT_E_BUFFER_ERROR;
|
||||
- } else {
|
||||
- int i;
|
||||
- for (i = 0; i < count; ++i)
|
||||
- This->vol[i] = levels[i];
|
||||
- }
|
||||
+ for (i = 0; i < count; ++i)
|
||||
+ This->vol[i] = levels[i];
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
@@ -2403,9 +2342,8 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
|
||||
IAudioStreamVolume *iface, UINT32 count, float *levels)
|
||||
{
|
||||
ACImpl *This = impl_from_IAudioStreamVolume(iface);
|
||||
- pa_operation *o;
|
||||
HRESULT hr;
|
||||
- struct pulse_info_cb_data info;
|
||||
+ int i;
|
||||
|
||||
TRACE("(%p)->(%d, %p)\n", This, count, levels);
|
||||
|
||||
@@ -2420,24 +2358,8 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
|
||||
if (FAILED(hr))
|
||||
goto out;
|
||||
|
||||
- if (pulse_stream_volume) {
|
||||
- info.n = count;
|
||||
- info.levels = levels;
|
||||
- if (This->dataflow == eRender)
|
||||
- o = pa_context_get_sink_input_info(pulse_ctx, pa_stream_get_index(This->stream), pulse_sink_input_info_cb, &info);
|
||||
- else
|
||||
- o = pa_context_get_source_info_by_index(pulse_ctx, pa_stream_get_device_index(This->stream), pulse_source_info_cb, &info);
|
||||
- if (o) {
|
||||
- while(pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
- pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
- pa_operation_unref(o);
|
||||
- } else
|
||||
- hr = AUDCLNT_E_BUFFER_ERROR;
|
||||
- } else {
|
||||
- int i;
|
||||
- for (i = 0; i < count; ++i)
|
||||
- levels[i] = This->vol[i];
|
||||
- }
|
||||
+ for (i = 0; i < count; ++i)
|
||||
+ levels[i] = This->vol[i];
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&pulse_lock);
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,47 +0,0 @@
|
||||
From 4b3ea90efafd93ad275b641520a566e519a7861c Mon Sep 17 00:00:00 2001
|
||||
From: Maarten Lankhorst <wine@mblankhorst.nl>
|
||||
Date: Mon, 5 Jan 2015 11:34:54 +0100
|
||||
Subject: winepulse: Forward winmm functions to winealsa
|
||||
|
||||
---
|
||||
configure.ac | 2 +-
|
||||
dlls/winepulse.drv/Makefile.in | 1 +
|
||||
dlls/winepulse.drv/winepulse.drv.spec | 5 +++++
|
||||
3 files changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 31b9bef..6bda11c 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -3335,3 +3335,3 @@ WINE_CONFIG_DLL(windowscodecsext,,[implib])
|
||||
WINE_CONFIG_TEST(dlls/windowscodecsext/tests)
|
||||
-WINE_CONFIG_DLL(winealsa.drv)
|
||||
+WINE_CONFIG_DLL(winealsa.drv,,[implib])
|
||||
WINE_CONFIG_DLL(winecoreaudio.drv)
|
||||
diff --git a/dlls/winepulse.drv/Makefile.in b/dlls/winepulse.drv/Makefile.in
|
||||
index 158bbc0..3428329 100644
|
||||
--- a/dlls/winepulse.drv/Makefile.in
|
||||
+++ b/dlls/winepulse.drv/Makefile.in
|
||||
@@ -1,5 +1,6 @@
|
||||
MODULE = winepulse.drv
|
||||
IMPORTS = dxguid uuid winmm user32 advapi32 ole32
|
||||
+DELAYIMPORTS = winealsa.drv
|
||||
EXTRALIBS = $(PULSE_LIBS) $(PTHREAD_LIBS)
|
||||
EXTRAINCL = $(PULSE_CFLAGS)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/winepulse.drv.spec b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
index 612bf46..288de87 100644
|
||||
--- a/dlls/winepulse.drv/winepulse.drv.spec
|
||||
+++ b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
@@ -3,3 +3,8 @@
|
||||
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
|
||||
@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint
|
||||
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
|
||||
+
|
||||
+# WinMM driver functions
|
||||
+@ stdcall -private DriverProc(long long long long long) winealsa.drv.DriverProc
|
||||
+@ stdcall -private midMessage(long long long long long) winealsa.drv.midMessage
|
||||
+@ stdcall -private modMessage(long long long long long) winealsa.drv.modMessage
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,195 +0,0 @@
|
||||
From 3510a611556452d32624578cd9d5d658f53844fa 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 | 155 ++++++++++++++++++++++++++++++++++
|
||||
dlls/winepulse.drv/winepulse.drv.spec | 1 +
|
||||
2 files changed, 156 insertions(+)
|
||||
|
||||
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c
|
||||
index 3be56fa..63b9786 100644
|
||||
--- a/dlls/winepulse.drv/mmdevdrv.c
|
||||
+++ b/dlls/winepulse.drv/mmdevdrv.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "initguid.h"
|
||||
#include "ks.h"
|
||||
#include "ksmedia.h"
|
||||
+#include "propkey.h"
|
||||
#include "mmdeviceapi.h"
|
||||
#include "audioclient.h"
|
||||
#include "endpointvolume.h"
|
||||
@@ -3341,3 +3342,157 @@ HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device,
|
||||
*out = &This->IAudioSessionManager2_iface;
|
||||
return S_OK;
|
||||
}
|
||||
+
|
||||
+enum AudioDeviceConnectionType {
|
||||
+ AudioDeviceConnectionType_Unknown = 0,
|
||||
+ AudioDeviceConnectionType_PCI,
|
||||
+ AudioDeviceConnectionType_USB
|
||||
+};
|
||||
+
|
||||
+static HRESULT pulse_set_device_path(pa_proplist *p, int index, GUID *guid, PROPVARIANT *pv)
|
||||
+{
|
||||
+ const char *buffer;
|
||||
+ enum AudioDeviceConnectionType connection;
|
||||
+ USHORT vendor_id, product_id;
|
||||
+ UINT serial_number;
|
||||
+
|
||||
+ 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" */
|
||||
+
|
||||
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
|
||||
+
|
||||
+ connection = AudioDeviceConnectionType_Unknown;
|
||||
+ if (buffer) {
|
||||
+ if (!strcmp(buffer,"pci"))
|
||||
+ connection = AudioDeviceConnectionType_PCI;
|
||||
+ else if (!strcmp(buffer,"usb"))
|
||||
+ connection = AudioDeviceConnectionType_USB;
|
||||
+ }
|
||||
+
|
||||
+ if (connection == AudioDeviceConnectionType_Unknown)
|
||||
+ return E_FAIL;
|
||||
+
|
||||
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_VENDOR_ID);
|
||||
+ if (buffer)
|
||||
+ vendor_id = strtol(buffer, NULL, 16);
|
||||
+ else
|
||||
+ return E_FAIL;
|
||||
+
|
||||
+ buffer = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_ID);
|
||||
+ if (buffer)
|
||||
+ product_id = strtol(buffer, NULL, 16);
|
||||
+ else
|
||||
+ 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];
|
||||
+
|
||||
+ pv->vt = VT_LPWSTR;
|
||||
+ pv->u.pwszVal = CoTaskMemAlloc(128 * sizeof(WCHAR));
|
||||
+
|
||||
+ if (!pv->u.pwszVal)
|
||||
+ return E_OUTOFMEMORY;
|
||||
+
|
||||
+ if (connection == AudioDeviceConnectionType_USB)
|
||||
+ sprintfW( pv->u.pwszVal, usbformatW, vendor_id, product_id, index, serial_number);
|
||||
+ else if (connection == AudioDeviceConnectionType_PCI)
|
||||
+ sprintfW( pv->u.pwszVal, pciformatW, vendor_id, product_id, index, serial_number);
|
||||
+
|
||||
+ return S_OK;
|
||||
+}
|
||||
+
|
||||
+struct pulse_prop_values_info_cb_data {
|
||||
+ const PROPERTYKEY *prop;
|
||||
+ PROPVARIANT *pv;
|
||||
+ GUID *guid;
|
||||
+ HRESULT hr;
|
||||
+};
|
||||
+
|
||||
+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 void pulse_prop_values_sink_info_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
|
||||
+{
|
||||
+ struct pulse_prop_values_info_cb_data *st = userdata;
|
||||
+
|
||||
+ if (i) {
|
||||
+ if (IsEqualPropertyKey(*st->prop, devicepath_key))
|
||||
+ st->hr = pulse_set_device_path(i->proplist, i->index, st->guid, st->pv);
|
||||
+ else if (IsEqualPropertyKey(*st->prop, PKEY_AudioEndpoint_FormFactor)) {
|
||||
+ st->pv->vt = VT_UI4;
|
||||
+ st->pv->u.ulVal = Speakers;
|
||||
+ st->hr = S_OK;
|
||||
+ } else
|
||||
+ st->hr = E_NOTIMPL;
|
||||
+ }
|
||||
+
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+static void pulse_prop_values_source_info_cb(pa_context *c, const pa_source_info *i, int eol, void *userdata)
|
||||
+{
|
||||
+ struct pulse_prop_values_info_cb_data *st = userdata;
|
||||
+
|
||||
+ if (i)
|
||||
+ {
|
||||
+ if (IsEqualPropertyKey(*st->prop, devicepath_key))
|
||||
+ st->hr = pulse_set_device_path(i->proplist, i->index, st->guid, st->pv);
|
||||
+ else if (IsEqualPropertyKey(*st->prop, PKEY_AudioEndpoint_FormFactor)) {
|
||||
+ st->pv->vt = VT_UI4;
|
||||
+ st->pv->u.ulVal = (i->monitor_of_sink == PA_INVALID_INDEX) ? Microphone : LineLevel;
|
||||
+ st->hr = S_OK;
|
||||
+ } else
|
||||
+ st->hr = E_NOTIMPL;
|
||||
+ }
|
||||
+
|
||||
+ pthread_cond_signal(&pulse_cond);
|
||||
+}
|
||||
+
|
||||
+HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out)
|
||||
+{
|
||||
+ struct pulse_prop_values_info_cb_data userdata;
|
||||
+ char name[256];
|
||||
+ EDataFlow flow;
|
||||
+ pa_operation *o;
|
||||
+
|
||||
+ TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out);
|
||||
+
|
||||
+ if (IsEqualGUID(guid, &pulse_render_guid) || IsEqualGUID(guid, &pulse_capture_guid))
|
||||
+ return E_NOTIMPL;
|
||||
+
|
||||
+ if (!get_pulse_name_by_guid(guid, name, sizeof(name), &flow)) {
|
||||
+ WARN("Unknown interface %s\n", debugstr_guid(guid));
|
||||
+ return E_NOINTERFACE;
|
||||
+ }
|
||||
+
|
||||
+ if (!IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_FormFactor) &&
|
||||
+ !IsEqualPropertyKey(*prop, devicepath_key)) {
|
||||
+ return E_NOTIMPL;
|
||||
+ }
|
||||
+
|
||||
+ userdata.prop = prop;
|
||||
+ userdata.pv = out;
|
||||
+ userdata.guid = guid;
|
||||
+ userdata.hr = E_FAIL;
|
||||
+
|
||||
+ pthread_mutex_lock(&pulse_lock);
|
||||
+ if (flow == eRender)
|
||||
+ o = pa_context_get_sink_info_by_name(pulse_ctx, name, &pulse_prop_values_sink_info_cb, &userdata);
|
||||
+ else
|
||||
+ o = pa_context_get_source_info_by_name(pulse_ctx, name, &pulse_prop_values_source_info_cb, &userdata);
|
||||
+ if (o) {
|
||||
+ while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
|
||||
+ pthread_cond_wait(&pulse_cond, &pulse_lock);
|
||||
+ pa_operation_unref(o);
|
||||
+ }
|
||||
+ pthread_mutex_unlock(&pulse_lock);
|
||||
+
|
||||
+ return userdata.hr;
|
||||
+}
|
||||
diff --git a/dlls/winepulse.drv/winepulse.drv.spec b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
index 288de87..7aeb175 100644
|
||||
--- a/dlls/winepulse.drv/winepulse.drv.spec
|
||||
+++ b/dlls/winepulse.drv/winepulse.drv.spec
|
||||
@@ -3,6 +3,7 @@
|
||||
@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs
|
||||
@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint
|
||||
@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager
|
||||
+@ stdcall -private GetPropValue(ptr ptr ptr) AUDDRV_GetPropValue
|
||||
|
||||
# WinMM driver functions
|
||||
@ stdcall -private DriverProc(long long long long long) winealsa.drv.DriverProc
|
||||
--
|
||||
2.2.1
|
||||
|
@ -1,4 +1,3 @@
|
||||
Fixes: [10495] Support for PulseAudio backend for audio
|
||||
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
|
||||
@ -6,4 +5,3 @@ 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
|
||||
Category: stable
|
||||
Disabled: true
|
||||
|
Loading…
Reference in New Issue
Block a user