[PATCH 5/5] dsound: Add support for IDirectSoundBufferNotify in capture
Maarten Lankhorst
m.b.lankhorst at gmail.com
Mon Nov 30 15:56:21 CST 2009
---
dlls/dsound/capture.c | 230 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 227 insertions(+), 3 deletions(-)
diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c
index c95d5c1..aee10d0 100644
--- a/dlls/dsound/capture.c
+++ b/dlls/dsound/capture.c
@@ -56,18 +56,23 @@ typedef struct DSCImpl
ALCchar *device;
DSCBuffer *buf;
+ UINT timer_id;
+ DWORD timer_res;
CRITICAL_SECTION crst;
} DSCImpl;
struct DSCBuffer
{
const IDirectSoundCaptureBuffer8Vtbl *lpVtbl;
- LONG ref;
+ const IDirectSoundNotifyVtbl *lpNotVtbl;
+ LONG ref, not_ref;
DSCImpl *parent;
ALCdevice *dev;
DWORD buf_size;
BYTE *buf;
WAVEFORMATEX *format;
+ DSBPOSITIONNOTIFY *notify;
+ DWORD nnotify;
DWORD pos;
BOOL playing, looping;
@@ -75,6 +80,7 @@ struct DSCBuffer
static const IDirectSoundCaptureVtbl DSC_Vtbl;
static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl;
+static const IDirectSoundNotifyVtbl DSCNot_Vtbl;
static void DSCImpl_Destroy(DSCImpl *This);
@@ -84,11 +90,118 @@ static HRESULT DSCBuffer_Create(DSCBuffer **buf)
if (!This)
return E_OUTOFMEMORY;
This->lpVtbl = &DSCBuffer_Vtbl;
+ This->lpNotVtbl = &DSCNot_Vtbl;
This->ref = 1;
*buf = This;
return S_OK;
}
+static void trigger_notifies(DSCBuffer *buf, DWORD lastpos, DWORD curpos)
+{
+ DWORD i;
+ if (lastpos == curpos)
+ return;
+ for (i = 0; i < buf->nnotify; ++i)
+ {
+ DSBPOSITIONNOTIFY *not = &buf->notify[i];
+ HANDLE event = not->hEventNotify;
+ DWORD ofs = not->dwOffset;
+
+ if (ofs == DSCBPN_OFFSET_STOP)
+ continue;
+
+ /* Wraparound case */
+ if (curpos < lastpos)
+ {
+ if (ofs < curpos
+ || ofs >= lastpos)
+ SetEvent(event);
+ continue;
+ }
+
+ /* Normal case */
+ if (ofs >= lastpos
+ && ofs < curpos)
+ SetEvent(event);
+ }
+}
+
+static void CALLBACK DSCBuffer_timer(UINT timerID, UINT msg, DWORD_PTR dwUser,
+ DWORD_PTR dw1, DWORD_PTR dw2)
+{
+ DSCImpl *This = (DSCImpl*)dwUser;
+ DSCBuffer *buf;
+ ALint avail = 0;
+
+ EnterCriticalSection(&This->crst);
+ buf = This->buf;
+ if (!buf || !buf->dev || !buf->playing)
+ goto out;
+
+ alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
+ if (avail)
+ {
+ avail *= buf->format->nBlockAlign;
+ if (avail + buf->pos > buf->buf_size)
+ avail = buf->buf_size - buf->pos;
+
+ alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
+ trigger_notifies(buf, buf->pos, buf->pos + avail);
+ buf->pos += avail;
+
+ if (buf->pos == buf->buf_size)
+ {
+ buf->pos = 0;
+ if (!buf->looping)
+ IDirectSoundCaptureBuffer_Stop((IDirectSoundCaptureBuffer*)buf);
+ else
+ {
+ avail = 0;
+ alcGetIntegerv(buf->dev, ALC_CAPTURE_SAMPLES, 1, &avail);
+ avail *= buf->format->nBlockAlign;
+ if (avail >= buf->buf_size)
+ {
+ ERR("TOO MUCH AVAIL: %u/%u\n", avail, buf->buf_size);
+ avail = buf->buf_size;
+ }
+
+ if (avail)
+ {
+ alcCaptureSamples(buf->dev, buf->buf + buf->pos, avail/buf->format->nBlockAlign);
+ trigger_notifies(buf, buf->pos, buf->pos + avail);
+ buf->pos += avail;
+ }
+ }
+ }
+ }
+
+out:
+ LeaveCriticalSection(&This->crst);
+ return;
+}
+
+static void DSCBuffer_starttimer(DSCImpl *prim)
+{
+ TIMECAPS time;
+ ALint refresh = FAKE_REFRESH_COUNT;
+ DWORD triggertime, res = DS_TIME_RES;
+
+ if (prim->timer_id)
+ return;
+
+ timeGetDevCaps(&time, sizeof(TIMECAPS));
+ triggertime = 1000 / refresh;
+ if (triggertime < time.wPeriodMin)
+ triggertime = time.wPeriodMin;
+ TRACE("Calling timer every %u ms for %i refreshes per second\n", triggertime, refresh);
+ if (res < time.wPeriodMin)
+ res = time.wPeriodMin;
+ if (timeBeginPeriod(res) == TIMERR_NOCANDO)
+ WARN("Could not set minimum resolution, don't expect sound\n");
+ prim->timer_res = res;
+ prim->timer_id = timeSetEvent(triggertime, res, DSCBuffer_timer, (DWORD_PTR)prim, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
+}
+
static void DSCBuffer_Destroy(DSCBuffer *This)
{
if (This->dev)
@@ -99,6 +212,7 @@ static void DSCBuffer_Destroy(DSCBuffer *This)
}
if (This->parent)
This->parent->buf = NULL;
+ HeapFree(GetProcessHeap(), 0, This->notify);
HeapFree(GetProcessHeap(), 0, This->format);
HeapFree(GetProcessHeap(), 0, This->buf);
HeapFree(GetProcessHeap(), 0, This);
@@ -112,7 +226,7 @@ static HRESULT WINAPI DSCBuffer_QueryInterface(IDirectSoundCaptureBuffer8 *iface
TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv);
*ppv = NULL;
if (IsEqualIID(riid, &IID_IDirectSoundNotify))
- FIXME("IDirectSoundNotify implemented\n");
+ *ppv = &This->lpNotVtbl;
else if (IsEqualIID(riid, &IID_IUnknown)
|| IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer)
|| IsEqualIID(riid, &IID_IDirectSoundCaptureBuffer8))
@@ -140,7 +254,7 @@ static ULONG WINAPI DSCBuffer_Release(IDirectSoundCaptureBuffer8 *iface)
EnterCriticalSection(crst);
ref = InterlockedDecrement(&This->ref);
TRACE("Reference count decremented to %i\n", ref);
- if (!ref)
+ if (!ref && !This->not_ref)
DSCBuffer_Destroy(This);
LeaveCriticalSection(crst);
return ref;
@@ -389,6 +503,7 @@ static HRESULT WINAPI DSCBuffer_Start(IDirectSoundCaptureBuffer8 *iface, DWORD f
EnterCriticalSection(&This->parent->crst);
if (!This->playing)
{
+ DSCBuffer_starttimer(This->parent);
This->playing = 1;
alcCaptureStart(This->dev);
}
@@ -405,6 +520,14 @@ static HRESULT WINAPI DSCBuffer_Stop(IDirectSoundCaptureBuffer8 *iface)
EnterCriticalSection(&This->parent->crst);
if (This->playing)
{
+ DWORD i;
+
+ for (i = 0; i < This->nnotify; ++i)
+ if (This->notify[i].dwOffset == DSCBPN_OFFSET_STOP)
+ {
+ SetEvent(This->notify[i].hEventNotify);
+ break;
+ }
This->playing = This->looping = 0;
alcCaptureStop(This->dev);
}
@@ -454,6 +577,102 @@ static const IDirectSoundCaptureBuffer8Vtbl DSCBuffer_Vtbl =
DSCBuffer_GetFXStatus
};
+static DSCBuffer *get_this_from_not(IDirectSoundNotify *iface)
+{
+ return (DSCBuffer*)((char*)iface - offsetof(DSCBuffer,lpNotVtbl));
+}
+
+static HRESULT WINAPI DSCBufferNot_QueryInterface(IDirectSoundNotify *iface, REFIID riid, void **ppv)
+{
+ DSCBuffer *This = get_this_from_not(iface);
+ return IDirectSoundCaptureBuffer_QueryInterface((IDirectSoundCaptureBuffer*)This, riid, ppv);
+}
+
+static ULONG WINAPI DSCBufferNot_AddRef(IDirectSoundNotify *iface)
+{
+ DSCBuffer *This = get_this_from_not(iface);
+ LONG ret;
+
+ ret = InterlockedIncrement(&This->not_ref);
+ TRACE("new refcount %d\n", ret);
+ return ret;
+}
+
+static ULONG WINAPI DSCBufferNot_Release(IDirectSoundNotify *iface)
+{
+ DSCBuffer *This = get_this_from_not(iface);
+ CRITICAL_SECTION *crst = &This->parent->crst;
+ LONG ret;
+
+ EnterCriticalSection(crst);
+ ret = InterlockedDecrement(&This->not_ref);
+ TRACE("new refcount %d\n", ret);
+ if (!ret && !This->ref)
+ DSCBuffer_Destroy(This);
+ LeaveCriticalSection(crst);
+ return ret;
+}
+
+static HRESULT WINAPI DSCBufferNot_SetNotificationPositions(IDirectSoundNotify *iface, DWORD count, const DSBPOSITIONNOTIFY *notifications)
+{
+ DSCBuffer *This = get_this_from_not(iface);
+ DSBPOSITIONNOTIFY *nots;
+ HRESULT hr;
+ DWORD state;
+
+ EnterCriticalSection(&This->parent->crst);
+ hr = DSERR_INVALIDPARAM;
+ if (count && !notifications)
+ goto out;
+
+ hr = DSCBuffer_GetStatus((IDirectSoundCaptureBuffer8*)This, &state);
+ if (FAILED(hr))
+ goto out;
+
+ hr = DSERR_INVALIDCALL;
+ if (state & DSCBSTATUS_CAPTURING)
+ goto out;
+
+ if (!count)
+ {
+ HeapFree(GetProcessHeap(), 0, This->notify);
+ This->notify = 0;
+ This->nnotify = 0;
+ }
+ else
+ {
+ DWORD i;
+ hr = DSERR_INVALIDPARAM;
+ for (i = 0; i < count; ++i)
+ {
+ if (notifications[i].dwOffset >= This->buf_size
+ && notifications[i].dwOffset != DSCBPN_OFFSET_STOP)
+ goto out;
+ }
+ hr = E_OUTOFMEMORY;
+ nots = HeapAlloc(GetProcessHeap(), 0, count*sizeof(*nots));
+ if (!nots)
+ goto out;
+ memcpy(nots, notifications, count*sizeof(*nots));
+ HeapFree(GetProcessHeap(), 0, This->notify);
+ This->notify = nots;
+ This->nnotify = count;
+ hr = S_OK;
+ }
+
+out:
+ LeaveCriticalSection(&This->parent->crst);
+ return hr;
+}
+
+static const IDirectSoundNotifyVtbl DSCNot_Vtbl =
+{
+ DSCBufferNot_QueryInterface,
+ DSCBufferNot_AddRef,
+ DSCBufferNot_Release,
+ DSCBufferNot_SetNotificationPositions
+};
+
HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
{
DSCImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
@@ -474,6 +693,11 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, IDirectSoundCapture8 **cap)
static void DSCImpl_Destroy(DSCImpl *This)
{
+ if (This->timer_id)
+ {
+ timeKillEvent(This->timer_id);
+ timeEndPeriod(This->timer_res);
+ }
EnterCriticalSection(&This->crst);
if (This->buf)
DSCBuffer_Destroy(This->buf);
--
1.6.5.3
More information about the wine-patches
mailing list