From 19d41e613915b4277dd6791077f5268b23f34e75 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Thu, 8 Jan 2015 18:41:18 +0100
Subject: [PATCH] winepulse-Pulseaudio_Support: Added missing files.

---
 ...l-cleanups-and-changes-for-consisten.patch | 206 ++++++++++++++++++
 ...efault-channel-masks-with-other-driv.patch |  59 +++++
 ...red-mode-track-device-position-in-by.patch |  50 +++++
 .../0030-winepulse-Always-mute-buffer.patch   |  39 ++++
 ...0031-winepulse-Remove-volume-support.patch | 166 ++++++++++++++
 ...-Forward-winmm-functions-to-winealsa.patch |  47 ++++
 6 files changed, 567 insertions(+)
 create mode 100644 patches/winepulse-PulseAudio_Support/0027-winepulse-Trivial-cleanups-and-changes-for-consisten.patch
 create mode 100644 patches/winepulse-PulseAudio_Support/0028-winepulse-Sync-default-channel-masks-with-other-driv.patch
 create mode 100644 patches/winepulse-PulseAudio_Support/0029-winepulse-In-Shared-mode-track-device-position-in-by.patch
 create mode 100644 patches/winepulse-PulseAudio_Support/0030-winepulse-Always-mute-buffer.patch
 create mode 100644 patches/winepulse-PulseAudio_Support/0031-winepulse-Remove-volume-support.patch
 create mode 100644 patches/winepulse-PulseAudio_Support/0032-winepulse-Forward-winmm-functions-to-winealsa.patch

diff --git a/patches/winepulse-PulseAudio_Support/0027-winepulse-Trivial-cleanups-and-changes-for-consisten.patch b/patches/winepulse-PulseAudio_Support/0027-winepulse-Trivial-cleanups-and-changes-for-consisten.patch
new file mode 100644
index 00000000..ced6f114
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0027-winepulse-Trivial-cleanups-and-changes-for-consisten.patch
@@ -0,0 +1,206 @@
+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
+
diff --git a/patches/winepulse-PulseAudio_Support/0028-winepulse-Sync-default-channel-masks-with-other-driv.patch b/patches/winepulse-PulseAudio_Support/0028-winepulse-Sync-default-channel-masks-with-other-driv.patch
new file mode 100644
index 00000000..a695b9f0
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0028-winepulse-Sync-default-channel-masks-with-other-driv.patch
@@ -0,0 +1,59 @@
+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
+
diff --git a/patches/winepulse-PulseAudio_Support/0029-winepulse-In-Shared-mode-track-device-position-in-by.patch b/patches/winepulse-PulseAudio_Support/0029-winepulse-In-Shared-mode-track-device-position-in-by.patch
new file mode 100644
index 00000000..c01a1489
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0029-winepulse-In-Shared-mode-track-device-position-in-by.patch
@@ -0,0 +1,50 @@
+From ca6122875e93dbcde90fcdb361c84a67ad1a5d44 Mon Sep 17 00:00:00 2001
+From: Andrew Eikum <aeikum@codeweavers.com>
+Date: Mon, 5 Jan 2015 11:31:56 +0100
+Subject: winepulse: In Shared mode, track device position in bytes
+
+---
+ 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
+--- 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)
+ 
+     pthread_mutex_lock(&pulse_lock);
+     hr = pulse_stream_valid(This);
+-    if (SUCCEEDED(hr))
+-        *freq = This->ss.rate * pa_frame_size(&This->ss);
++    if (SUCCEEDED(hr)) {
++        if (This->share == AUDCLNT_SHAREMODE_SHARED)
++            *freq = This->ss.rate * pa_frame_size(&This->ss);
++        else
++            *freq = This->ss.rate;
++    }
+     pthread_mutex_unlock(&pulse_lock);
+     return hr;
+ }
+@@ -2180,6 +2184,9 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
+ 
+     *pos = This->clock_written;
+ 
++    if (This->share == AUDCLNT_SHAREMODE_EXCLUSIVE)
++        *pos /= pa_frame_size(&This->ss);
++
+     /* 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,
+ {
+     ACImpl *This = impl_from_IAudioClock2(iface);
+     HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime);
+-    if (SUCCEEDED(hr))
++    if (SUCCEEDED(hr) && This->share == AUDCLNT_SHAREMODE_SHARED)
+         *pos /= pa_frame_size(&This->ss);
+     return hr;
+ }
+-- 
+2.2.1
+
diff --git a/patches/winepulse-PulseAudio_Support/0030-winepulse-Always-mute-buffer.patch b/patches/winepulse-PulseAudio_Support/0030-winepulse-Always-mute-buffer.patch
new file mode 100644
index 00000000..8c0d9ea5
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0030-winepulse-Always-mute-buffer.patch
@@ -0,0 +1,39 @@
+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
+
diff --git a/patches/winepulse-PulseAudio_Support/0031-winepulse-Remove-volume-support.patch b/patches/winepulse-PulseAudio_Support/0031-winepulse-Remove-volume-support.patch
new file mode 100644
index 00000000..34e7c76c
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0031-winepulse-Remove-volume-support.patch
@@ -0,0 +1,166 @@
+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
+
diff --git a/patches/winepulse-PulseAudio_Support/0032-winepulse-Forward-winmm-functions-to-winealsa.patch b/patches/winepulse-PulseAudio_Support/0032-winepulse-Forward-winmm-functions-to-winealsa.patch
new file mode 100644
index 00000000..eec3e69f
--- /dev/null
+++ b/patches/winepulse-PulseAudio_Support/0032-winepulse-Forward-winmm-functions-to-winealsa.patch
@@ -0,0 +1,47 @@
+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 = @PULSELIBS@ $(PTHREAD_LIBS)
+ EXTRAINCL = @PULSEINCL@
+ 
+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
+