Maarten Lankhorst : mmdevapi: Add audio capture code.

Alexandre Julliard julliard at winehq.org
Tue Apr 20 11:32:23 CDT 2010


Module: wine
Branch: master
Commit: f062e1b127aac4d5a075c40e8d9d90cc687d5d6c
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f062e1b127aac4d5a075c40e8d9d90cc687d5d6c

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Mon Apr 19 11:52:52 2010 +0200

mmdevapi: Add audio capture code.

---

 dlls/mmdevapi/audio.c         |  149 +++++++++++++++++++++++++++++++++++++++++
 dlls/mmdevapi/tests/capture.c |    4 +-
 2 files changed, 152 insertions(+), 1 deletions(-)

diff --git a/dlls/mmdevapi/audio.c b/dlls/mmdevapi/audio.c
index b2ee3f0..997e037 100644
--- a/dlls/mmdevapi/audio.c
+++ b/dlls/mmdevapi/audio.c
@@ -76,6 +76,7 @@ typedef struct ACImpl {
     ALint format;
 
     ACRender *render;
+    ACCapture *capture;
 } ACImpl;
 
 struct ACRender {
@@ -84,11 +85,20 @@ struct ACRender {
     ACImpl *parent;
 };
 
+struct ACCapture {
+    const IAudioCaptureClientVtbl *lpVtbl;
+    LONG ref;
+    ACImpl *parent;
+};
+
 static const IAudioClientVtbl ACImpl_Vtbl;
 static const IAudioRenderClientVtbl ACRender_Vtbl;
+static const IAudioCaptureClientVtbl ACCapture_Vtbl;
 
 static HRESULT AudioRenderClient_Create(ACImpl *parent, ACRender **ppv);
 static void AudioRenderClient_Destroy(ACRender *This);
+static HRESULT AudioCaptureClient_Create(ACImpl *parent, ACCapture **ppv);
+static void AudioCaptureClient_Destroy(ACCapture *This);
 
 static int get_format_PCM(WAVEFORMATEX *format)
 {
@@ -265,6 +275,8 @@ static void AudioClient_Destroy(ACImpl *This)
         DeleteTimerQueueTimer(NULL, This->timer_id, INVALID_HANDLE_VALUE);
     if (This->render)
         AudioRenderClient_Destroy(This->render);
+    if (This->capture)
+        AudioCaptureClient_Destroy(This->capture);
     if (This->parent->flow == eRender && This->init) {
         setALContext(This->parent->ctx);
         IAudioClient_Stop((IAudioClient*)This);
@@ -828,6 +840,12 @@ static HRESULT WINAPI AC_GetService(IAudioClient *iface, REFIID riid, void **ppv
         if (!This->render)
             hr = AudioRenderClient_Create(This, &This->render);
         *ppv = This->render;
+    } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) {
+        if (This->parent->flow != eCapture)
+            return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+        if (!This->capture)
+            hr = AudioCaptureClient_Create(This, &This->capture);
+        *ppv = This->capture;
     }
 
     if (FAILED(hr))
@@ -1063,4 +1081,135 @@ static const IAudioRenderClientVtbl ACRender_Vtbl = {
     ACR_ReleaseBuffer
 };
 
+static HRESULT AudioCaptureClient_Create(ACImpl *parent, ACCapture **ppv)
+{
+    ACCapture *This;
+    This = *ppv = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+    if (!This)
+        return E_OUTOFMEMORY;
+    This->lpVtbl = &ACCapture_Vtbl;
+    This->ref = 0;
+    This->parent = parent;
+    return S_OK;
+}
+
+static void AudioCaptureClient_Destroy(ACCapture *This)
+{
+    This->parent->capture = NULL;
+    HeapFree(GetProcessHeap(), 0, This);
+}
+
+static HRESULT WINAPI ACC_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 ACC_AddRef(IAudioCaptureClient *iface)
+{
+    ACCapture *This = (ACCapture*)iface;
+    ULONG ref;
+    ref = InterlockedIncrement(&This->ref);
+    TRACE("Refcount now %i\n", ref);
+    return ref;
+}
+
+static ULONG WINAPI ACC_Release(IAudioCaptureClient *iface)
+{
+    ACCapture *This = (ACCapture*)iface;
+    ULONG ref;
+    ref = InterlockedDecrement(&This->ref);
+    TRACE("Refcount now %i\n", ref);
+    if (!ref)
+        AudioCaptureClient_Destroy(This);
+    return ref;
+}
+
+static HRESULT WINAPI ACC_GetBuffer(IAudioCaptureClient *iface, BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, UINT64 *qpcpos)
+{
+    ACCapture *This = (ACCapture*)iface;
+    HRESULT hr;
+    DWORD block = This->parent->pwfx->nBlockAlign;
+    DWORD ofs, bufsize;
+    TRACE("(%p)->(%p,%p,%p,%p,%p)\n", This, data, frames, flags, devpos, qpcpos);
+
+    if (!data)
+        return E_POINTER;
+    if (!frames)
+        return E_POINTER;
+    if (!flags) {
+        FIXME("Flags can be null?\n");
+        return E_POINTER;
+    }
+    EnterCriticalSection(This->parent->crst);
+    hr = AUDCLNT_E_OUT_OF_ORDER;
+    if (This->parent->locked)
+        goto out;
+    IAudioCaptureClient_GetNextPacketSize(iface, frames);
+    ofs = This->parent->ofs;
+    bufsize = This->parent->bufsize;
+    if ( (ofs*block) % This->parent->psize)
+        ERR("Unaligned offset %u with %u\n", ofs*block, This->parent->psize);
+    *data = This->parent->buffer + ofs * block;
+    This->parent->locked = *frames;
+    if (devpos)
+        *devpos = This->parent->frameswritten - This->parent->pad;
+    if (qpcpos)
+        *qpcpos = This->parent->laststamp;
+    if (*frames)
+        hr = S_OK;
+    else
+        hr = AUDCLNT_S_BUFFER_EMPTY;
+out:
+    LeaveCriticalSection(This->parent->crst);
+    return hr;
+}
+
+static HRESULT WINAPI ACC_ReleaseBuffer(IAudioCaptureClient *iface, UINT32 written)
+{
+    ACCapture *This = (ACCapture*)iface;
+    HRESULT hr = S_OK;
+    EnterCriticalSection(This->parent->crst);
+    if (!written || written == This->parent->locked)
+        This->parent->locked = 0;
+    else if (!This->parent->locked)
+        hr = AUDCLNT_E_OUT_OF_ORDER;
+    else
+        hr = AUDCLNT_E_INVALID_SIZE;
+    This->parent->ofs += written;
+    This->parent->ofs %= This->parent->bufsize;
+    This->parent->pad -= written;
+    LeaveCriticalSection(This->parent->crst);
+    return hr;
+}
+
+static HRESULT WINAPI ACC_GetNextPacketSize(IAudioCaptureClient *iface, UINT32 *frames)
+{
+    ACCapture *This = (ACCapture*)iface;
+
+    return AC_GetCurrentPadding((IAudioClient*)This->parent, frames);
+}
+
+static const IAudioCaptureClientVtbl ACCapture_Vtbl =
+{
+    ACC_QueryInterface,
+    ACC_AddRef,
+    ACC_Release,
+    ACC_GetBuffer,
+    ACC_ReleaseBuffer,
+    ACC_GetNextPacketSize
+};
+
 #endif
diff --git a/dlls/mmdevapi/tests/capture.c b/dlls/mmdevapi/tests/capture.c
index d88a19d..b5c4883 100644
--- a/dlls/mmdevapi/tests/capture.c
+++ b/dlls/mmdevapi/tests/capture.c
@@ -81,7 +81,7 @@ static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx)
     UINT64 devpos, qpcpos;
 
     hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&acc);
-    todo_wine ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08x\n", hr);
+    ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08x\n", hr);
     if (hr != S_OK)
         return;
 
@@ -118,6 +118,8 @@ static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx)
         ok(frames, "Amount of frames locked is 0!\n");
     else if (hr == AUDCLNT_S_BUFFER_EMPTY)
         ok(!frames, "Amount of frames locked with empty buffer is %u!\n", frames);
+    else
+        ok(0, "GetBuffer returned %08x\n", hr);
     trace("Device position is at %u, amount of frames locked: %u\n", (DWORD)devpos, frames);
 
     if (frames) {




More information about the wine-cvs mailing list