[PATCH 4/5] dsound: Add support for OpenAL IDirectSoundCaptureBuffer, try 3

Maarten Lankhorst m.b.lankhorst at gmail.com
Tue Dec 1 05:03:00 CST 2009


Ticking timer is missing, so this doesn't do much till next commit
---
 dlls/dsound/capture.c |  413 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 411 insertions(+), 2 deletions(-)

diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c
index d9f0491..8c20ce8 100644
--- a/dlls/dsound/capture.c
+++ b/dlls/dsound/capture.c
@@ -47,19 +47,408 @@ HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **cap)
 
 #ifdef SONAME_LIBOPENAL
 
+typedef struct DSCBuffer DSCBuffer;
+
 typedef struct DSCImpl
 {
     const IDirectSoundCaptureVtbl *lpVtbl;
     LONG ref;
 
     ALCchar *device;
+    DSCBuffer *buf;
     CRITICAL_SECTION crst;
 } DSCImpl;
 
+struct DSCBuffer
+{
+    const IDirectSoundCaptureBuffer8Vtbl *lpVtbl;
+    LONG ref;
+    DSCImpl *parent;
+    ALCdevice *dev;
+    DWORD buf_size;
+    BYTE *buf;
+    WAVEFORMATEX *format;
+
+    DWORD pos;
+    BOOL playing, looping;
+};
+
 static const IDirectSoundCaptureVtbl DSC_Vtbl;
+static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl;
 
 static void DSCImpl_Destroy(DSCImpl *This);
 
+static HRESULT DSCBuffer_Create(DSCBuffer **buf)
+{
+    DSCBuffer *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
+    if (!This)
+        return E_OUTOFMEMORY;
+    This->lpVtbl = &DSCBuffer_Vtbl;
+    This->ref = 1;
+    *buf = This;
+    return S_OK;
+}
+
+static void DSCBuffer_Destroy(DSCBuffer *This)
+{
+    if (This->dev)
+    {
+        if (This->playing)
+            palcCaptureStop(This->dev);
+        palcCaptureCloseDevice(This->dev);
+    }
+    if (This->parent)
+        This->parent->buf = NULL;
+    HeapFree(GetProcessHeap(), 0, This->format);
+    HeapFree(GetProcessHeap(), 0, This->buf);
+    HeapFree(GetProcessHeap(), 0, This);
+}
+
+static HRESULT WINAPI DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8 *iface, REFIID riid, void **ppv)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    if (!ppv)
+        return E_POINTER;
+    TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
+    *ppv = NULL;
+    if (IsEqualIID(riid, &IID_IDirectSoundNotify))
+        FIXME("IDirectSoundNotify implemented\n");
+    else if (IsEqualIID(riid, &IID_IUnknown)
+             || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer)
+             || IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
+        *ppv = This;
+    if (!*ppv)
+        return E_NOINTERFACE;
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI DSCBuffer_AddRef(IDirectSoundCaptureBuffer8 *iface)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    LONG ref;
+    ref = InterlockedIncrement(&This->ref);
+    TRACE("Reference count incremented to %i\n", ref);
+    return ref;
+}
+
+static ULONG WINAPI DSCBuffer_Release(IDirectSoundCaptureBuffer8 *iface)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    CRITICAL_SECTION *crst = &This->parent->crst;
+    LONG ref;
+    EnterCriticalSection(crst);
+    ref = InterlockedDecrement(&This->ref);
+    TRACE("Reference count decremented to %i\n", ref);
+    if (!ref)
+        DSCBuffer_Destroy(This);
+    LeaveCriticalSection(crst);
+    return ref;
+}
+
+static HRESULT WINAPI DSCBuffer_GetCaps(IDirectSoundCaptureBuffer8 *iface, DSCBCAPS *caps)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+
+    if (!caps || caps->dwSize < sizeof(*caps))
+        return DSERR_INVALIDPARAM;
+    caps->dwSize = sizeof(*caps);
+    caps->dwFlags = 0;
+    caps->dwBufferBytes = This->buf_size;
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface, DWORD *cappos, DWORD *readpos)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    DWORD pos1, pos2;
+    EnterCriticalSection(&This->parent->crst);
+    pos1 = This->pos;
+    if (This->playing)
+    {
+        pos2 = This->format->nSamplesPerSec / 100;
+        pos2 *= This->format->nBlockAlign;
+        pos2 += pos1;
+        if (!This->looping && pos2 > This->buf_size)
+            pos2 = 0;
+        else
+            pos2 %= This->buf_size;
+    }
+    else
+        pos2 = pos1;
+    pos2 %= This->buf_size;
+    LeaveCriticalSection(&This->parent->crst);
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_GetFormat(IDirectSoundCaptureBuffer8 *iface, WAVEFORMATEX *wfx, DWORD size, DWORD *written)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    TRACE("(%p,%p,%u,%p)\n", This, wfx, size, written);
+
+    if (size > sizeof(WAVEFORMATEX) + This->format->cbSize)
+        size = sizeof(WAVEFORMATEX) + This->format->cbSize;
+
+    if (wfx)
+    {
+        CopyMemory(wfx, This->format, size);
+        if (written)
+            *written = size;
+    } else if (written)
+        *written = sizeof(WAVEFORMATEX) + This->format->cbSize;
+    else
+        return DSERR_INVALIDPARAM;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_GetStatus(IDirectSoundCaptureBuffer8 *iface, DWORD *status)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    TRACE("(%p)->(%p)\n", This, status);
+
+    if (!status)
+        return DSERR_INVALIDPARAM;
+    EnterCriticalSection(&This->parent->crst);
+    *status = 0;
+    if (This->playing)
+    {
+        *status |= DSCBSTATUS_CAPTURING;
+        if (This->looping)
+            *status |= DSCBSTATUS_LOOPING;
+    }
+    LeaveCriticalSection(&This->parent->crst);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_Initialize(IDirectSoundCaptureBuffer8 *iface, IDirectSoundCapture *parent, const DSCBUFFERDESC *desc)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    WAVEFORMATEX *format;
+    ALenum buf_format = -1;
+
+    if (This->parent)
+        return DSERR_ALREADYINITIALIZED;
+    This->parent = (DSCImpl*)parent;
+    if (!desc->lpwfxFormat)
+        return DSERR_INVALIDPARAM;
+
+    format = desc->lpwfxFormat;
+    if (format->nChannels > 2)
+    {
+        WARN("nChannels > 2 not supported for recording\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (!This->format)
+        This->format = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEFORMATEXTENSIBLE));
+    if (!This->format)
+        return DSERR_OUTOFMEMORY;
+
+    if (format->wFormatTag == WAVE_FORMAT_PCM
+        || format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+    {
+        if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+        {
+            WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)format;
+            if (format->cbSize < sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX))
+                return DSERR_INVALIDPARAM;
+            else if (format->cbSize > sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
+                && format->cbSize != sizeof(WAVEFORMATEXTENSIBLE))
+                return DSERR_CONTROLUNAVAIL;
+            else if (!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
+                return DSERR_BADFORMAT;
+        }
+
+        if (format->nChannels == 1)
+        {
+            switch (format->wBitsPerSample)
+            {
+                case 8: buf_format = AL_FORMAT_MONO8; break;
+                case 16: buf_format = AL_FORMAT_MONO16; break;
+                default:
+                    WARN("Unsupported bpp %u\n", format->wBitsPerSample);
+                    return DSERR_BADFORMAT;
+            }
+        }
+        else if (format->nChannels == 2)
+        {
+            switch (format->wBitsPerSample)
+            {
+                case 8: buf_format = AL_FORMAT_STEREO8; break;
+                case 16: buf_format = AL_FORMAT_STEREO16; break;
+                default:
+                    WARN("Unsupported bpp %u\n", format->wBitsPerSample);
+                    return DSERR_BADFORMAT;
+            }
+        }
+        memcpy(This->format, format, sizeof(*format) + format->cbSize);
+        if (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+            This->format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+        else
+            This->format->cbSize = 0;
+        This->format->nBlockAlign = This->format->wBitsPerSample * This->format->nChannels / 8;
+        This->format->nAvgBytesPerSec = This->format->nSamplesPerSec * This->format->nBlockAlign;
+    }
+    else if (format->wFormatTag)
+        WARN("Unhandled formattag %x\n", format->wFormatTag);
+
+    This->buf_size = desc->dwBufferBytes;
+    if(buf_format <= 0)
+    {
+        WARN("Could not get OpenAL format\n");
+        return DSERR_INVALIDPARAM;
+    }
+    This->dev = palcCaptureOpenDevice(This->parent->device, This->format->nSamplesPerSec, buf_format, This->buf_size / This->format->nBlockAlign);
+    if (!This->dev)
+    {
+        ERR("couldn't open device %s %x@%u, reason: %04x\n", This->parent->device, buf_format, This->format->nSamplesPerSec, palcGetError(NULL));
+        return DSERR_INVALIDPARAM;
+    }
+    This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
+    if (!This->buf)
+    {
+        palcCaptureCloseDevice(This->dev);
+        WARN("Out of memory\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_Lock(IDirectSoundCaptureBuffer8 *iface, DWORD ofs, DWORD bytes, void **ptr1, DWORD *len1, void **ptr2, DWORD *len2, DWORD flags)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    HRESULT hr;
+    DWORD remain;
+    TRACE("(%p)->(%u, %u, %p, %p, %p, %p, %#x)\n", This, ofs, bytes, ptr1, len1, ptr2, len2, flags);
+
+    EnterCriticalSection(&This->parent->crst);
+    hr = DSERR_INVALIDPARAM;
+    if (ptr1)
+        *ptr1 = NULL;
+    if (len1)
+        *len1 = 0;
+    if (ptr2)
+        *ptr2 = NULL;
+    if (len2)
+        *len2 = 0;
+    if (ofs >= This->buf_size)
+    {
+        WARN("Invalid ofs %u\n", ofs);
+        goto out;
+    }
+    if (!ptr1 || !len1)
+    {
+        WARN("Invalid pointer/len %p %p\n", ptr1, len1);
+        goto out;
+    }
+    if (flags & DSCBLOCK_ENTIREBUFFER)
+        bytes = This->buf_size;
+    if (bytes > This->buf_size)
+    {
+        WARN("Invalid size %u\n", bytes);
+        goto out;
+    }
+
+    if (ofs + bytes >= This->buf_size)
+    {
+        *len1 = This->buf_size - ofs;
+        remain = bytes - *len1;
+    }
+    else
+    {
+        *len1 = bytes;
+        remain = 0;
+    }
+    *ptr1 = This->buf + ofs;
+
+    if (ptr2 && len2 && remain)
+    {
+        *ptr2 = This->buf;
+        *len2 = remain;
+    }
+    hr = S_OK;
+
+out:
+    LeaveCriticalSection(&This->parent->crst);
+    return hr;
+}
+
+static HRESULT WINAPI DSCBuffer_Start(IDirectSoundCaptureBuffer8 *iface, DWORD flags)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    TRACE("(%p)->(%08x)\n", This, flags);
+
+    EnterCriticalSection(&This->parent->crst);
+    if (!This->playing)
+    {
+        This->playing = 1;
+        palcCaptureStart(This->dev);
+    }
+    This->looping = !!(flags & DSCBSTART_LOOPING);
+    LeaveCriticalSection(&This->parent->crst);
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_Stop(IDirectSoundCaptureBuffer8 *iface)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    TRACE("(%p)\n", This);
+
+    EnterCriticalSection(&This->parent->crst);
+    if (This->playing)
+    {
+        This->playing = This->looping = 0;
+        palcCaptureStop(This->dev);
+    }
+    LeaveCriticalSection(&This->parent->crst);
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_Unlock(IDirectSoundCaptureBuffer8 *iface, void *ptr1, DWORD len1, void *ptr2, DWORD len2)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    TRACE("(%p)->(%p,%u,%p,%u)\n", This, ptr1, len2, ptr2, len2);
+
+    if (!ptr1)
+        return DSERR_INVALIDPARAM;
+    return S_OK;
+}
+
+static HRESULT WINAPI DSCBuffer_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface, REFGUID guid, DWORD num, REFGUID riid, void **ppv)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    FIXME("(%p)->(%s %u %s %p) stub\n", This, debugstr_guid(guid), num, debugstr_guid(riid), ppv);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DSCBuffer_GetFXStatus(IDirectSoundCaptureBuffer8 *iface, DWORD count, DWORD *status)
+{
+    DSCBuffer *This = (DSCBuffer*)iface;
+    FIXME("(%p)->(%u %p) stub\n", This, count, status);
+    return E_NOTIMPL;
+}
+
+static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl =
+{
+    DSCBuffer_QueryInterface,
+    DSCBuffer_AddRef,
+    DSCBuffer_Release,
+    DSCBuffer_GetCaps,
+    DSCBuffer_GetCurrentPosition,
+    DSCBuffer_GetFormat,
+    DSCBuffer_GetStatus,
+    DSCBuffer_Initialize,
+    DSCBuffer_Lock,
+    DSCBuffer_Start,
+    DSCBuffer_Stop,
+    DSCBuffer_Unlock,
+    DSCBuffer_GetObjectInPath,
+    DSCBuffer_GetFXStatus
+};
+
 HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
 {
     DSCImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
@@ -80,6 +469,10 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
 
 static void DSCImpl_Destroy(DSCImpl *This)
 {
+    EnterCriticalSection(&This->crst);
+    if (This->buf)
+        DSCBuffer_Destroy(This->buf);
+    LeaveCriticalSection(&This->crst);
     HeapFree(GetProcessHeap(), 0, This->device);
     This->crst.DebugInfo->Spare[0] = 0;
     DeleteCriticalSection(&This->crst);
@@ -151,8 +544,24 @@ static HRESULT WINAPI DSCImpl_CreateCaptureBuffer(IDirectSoundCapture8 *iface, c
         WARN("Not initialized\n");
         goto out;
     }
-    FIXME("stub\n");
-    hr = E_NOTIMPL;
+    if (This->buf)
+    {
+        hr = DSERR_ALLOCATED;
+        WARN("Capture buffer already allocated\n");
+        goto out;
+    }
+
+    hr = DSCBuffer_Create(&This->buf);
+    if (SUCCEEDED(hr))
+    {
+        hr = IDirectSoundCaptureBuffer_Initialize((IDirectSoundCaptureBuffer*)This->buf, iface, desc);
+        if (FAILED(hr))
+        {
+            DSCBuffer_Destroy(This->buf);
+            This->buf = NULL;
+        }
+    }
+    *ppv = (IDirectSoundCaptureBuffer*)This->buf;
 out:
     LeaveCriticalSection(&This->crst);
     return hr;
-- 
1.6.5.3




More information about the wine-patches mailing list