mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
353 lines
11 KiB
Diff
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
|
|
|