wine-staging/patches/06-winepulse/0005-winepulse-Add-IAudioRenderClient-and-IAudioCaptureCl.patch
2014-01-06 01:26:32 +01:00

353 lines
11 KiB
Diff

From d8b1b43529fa98eb0a04d1616f1b98d264d2018b Mon Sep 17 00:00:00 2001
From: Maarten Lankhorst <m.b.lankhorst@gmail.com>
Date: Sat, 4 Jan 2014 07:08:54 +0100
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)
{
--
1.8.5.2