[PATCH 4/5] dsound: Add support for OpenAL IDirectSoundCaptureBuffer
Maarten Lankhorst
m.b.lankhorst at gmail.com
Mon Nov 30 15:56:20 CST 2009
Ticking timer is missing, so this doesn't do much till next commit
---
dlls/dsound/capture.c | 418 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 416 insertions(+), 2 deletions(-)
diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c
index f9d8975..c95d5c1 100644
--- a/dlls/dsound/capture.c
+++ b/dlls/dsound/capture.c
@@ -47,19 +47,413 @@ HRESULT DSOUND_CaptureCreate(REFIID riid, IDirectSoundCapture **cap)
#ifdef HAVE_OPENAL
+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)
+ alcCaptureStop(This->dev);
+ alcCaptureCloseDevice(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;
+ const ALCchar *fmt_str = NULL;
+ ALenum buf_format;
+
+ 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 (!IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
+ return DSERR_BADFORMAT;
+ else 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;
+ }
+
+ if (format->nChannels == 1)
+ {
+ switch (format->wBitsPerSample)
+ {
+ case 8: fmt_str = "AL_FORMAT_MONO8"; break;
+ case 16: fmt_str = "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: fmt_str = "AL_FORMAT_STEREO8"; break;
+ case 16: fmt_str = "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);
+
+ if (!fmt_str)
+ return DSERR_INVALIDPARAM;
+
+ This->buf_size = desc->dwBufferBytes;
+ buf_format = alGetEnumValue(fmt_str);
+ if(buf_format <= 0)
+ {
+ WARN("Could not get OpenAL format from %s\n", fmt_str);
+ return DSERR_INVALIDPARAM;
+ }
+ This->dev = alcCaptureOpenDevice(This->parent->device, This->format->nSamplesPerSec, buf_format, This->buf_size);
+ if (!This->dev)
+ {
+ ERR("couldn't open device %s %s(%x)@%u, reason: %04x\n", This->parent->device, fmt_str, buf_format, This->format->nSamplesPerSec, alcGetError(NULL));
+ return DSERR_INVALIDPARAM;
+ }
+ This->buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->buf_size);
+ if (!This->buf)
+ {
+ alcCaptureCloseDevice(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;
+ alcCaptureStart(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;
+ alcCaptureStop(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 +474,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 +549,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