* Sync with trunk r64401.
[reactos.git] / dll / directx / wine / dsound / capture.c
index 756bbc0..b8df4f5 100644 (file)
 
 #include "dsound_private.h"
 
-typedef struct DirectSoundCaptureDevice      DirectSoundCaptureDevice;
-
-/* IDirectSoundCaptureBuffer implementation structure */
-typedef struct IDirectSoundCaptureBufferImpl
-{
-    IDirectSoundCaptureBuffer8          IDirectSoundCaptureBuffer8_iface;
-    IDirectSoundNotify                  IDirectSoundNotify_iface;
-    LONG                                numIfaces; /* "in use interfaces" refcount */
-    LONG                                ref, refn;
-    /* IDirectSoundCaptureBuffer fields */
-    DirectSoundCaptureDevice            *device;
-    DSCBUFFERDESC                       *pdscbd;
-    DWORD                               flags;
-    /* IDirectSoundNotify fields */
-    DSBPOSITIONNOTIFY                   *notifies;
-    int                                 nrofnotifies;
-} IDirectSoundCaptureBufferImpl;
-
-/* DirectSoundCaptureDevice implementation structure */
-struct DirectSoundCaptureDevice
+/*****************************************************************************
+ * IDirectSoundCaptureNotify implementation structure
+ */
+struct IDirectSoundCaptureNotifyImpl
 {
-    GUID                          guid;
-    LONG                          ref;
-    DSCCAPS                       drvcaps;
-    BYTE                          *buffer;
-    DWORD                         buflen, write_pos_bytes;
-    WAVEFORMATEX                  *pwfx;
-    IDirectSoundCaptureBufferImpl *capture_buffer;
-    DWORD                         state;
-    UINT                          timerID;
-    CRITICAL_SECTION              lock;
-    IMMDevice                     *mmdevice;
-    IAudioClient                  *client;
-    IAudioCaptureClient           *capture;
-    struct list                   entry;
+    /* IUnknown fields */
+    const IDirectSoundNotifyVtbl       *lpVtbl;
+    LONG                                ref;
+    IDirectSoundCaptureBufferImpl*      dscb;
 };
 
-
-static void capturebuffer_destroy(IDirectSoundCaptureBufferImpl *This)
-{
-    if (This->device->state == STATE_CAPTURING)
-        This->device->state = STATE_STOPPING;
-
-    HeapFree(GetProcessHeap(),0, This->pdscbd);
-
-    if (This->device->client) {
-        IAudioClient_Release(This->device->client);
-        This->device->client = NULL;
-    }
-
-    if (This->device->capture) {
-        IAudioCaptureClient_Release(This->device->capture);
-        This->device->capture = NULL;
-    }
-
-    /* remove from DirectSoundCaptureDevice */
-    This->device->capture_buffer = NULL;
-
-    HeapFree(GetProcessHeap(), 0, This->notifies);
-    HeapFree(GetProcessHeap(), 0, This);
-    TRACE("(%p) released\n", This);
-}
-
 /*******************************************************************************
- * IDirectSoundNotify
+ *             IDirectSoundCaptureNotify
  */
-static inline struct IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
-{
-    return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundNotify_iface);
-}
-
-static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
-        void **ppobj)
+static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
+    LPDIRECTSOUNDNOTIFY iface,
+    REFIID riid,
+    LPVOID *ppobj)
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
+    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
 
-    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
+    if (This->dscb == NULL) {
+       WARN("invalid parameter\n");
+       return E_INVALIDARG;
+    }
 
-    return IDirectSoundCaptureBuffer_QueryInterface(&This->IDirectSoundCaptureBuffer8_iface, riid, ppobj);
+    return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
 }
 
-static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
+static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
-    ULONG ref = InterlockedIncrement(&This->refn);
-
+    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref - 1);
-
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
-
     return ref;
 }
 
-static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
+static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
-    ULONG ref = InterlockedDecrement(&This->refn);
-
+    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref + 1);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        capturebuffer_destroy(This);
-
+    if (!ref) {
+        if (This->dscb->hwnotify)
+            IDsDriverNotify_Release(This->dscb->hwnotify);
+       This->dscb->notify=NULL;
+       IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb);
+       HeapFree(GetProcessHeap(),0,This);
+       TRACE("(%p) released\n", This);
+    }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
-        DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
+static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
+    LPDIRECTSOUNDNOTIFY iface,
+    DWORD howmuch,
+    LPCDSBPOSITIONNOTIFY notify)
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundNotify(iface);
+    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
     TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
 
     if (howmuch > 0 && notify == NULL) {
@@ -152,26 +102,32 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSou
            notify[i].dwOffset,notify[i].hEventNotify);
     }
 
-    if (howmuch > 0) {
+    if (This->dscb->hwnotify) {
+       HRESULT hres;
+       hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify);
+       if (hres != DS_OK)
+           WARN("IDsDriverNotify_SetNotificationPositions failed\n");
+       return hres;
+    } else if (howmuch > 0) {
        /* Make an internal copy of the caller-supplied array.
         * Replace the existing copy if one is already present. */
-        if (This->notifies)
-            This->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->notifies,
-                    howmuch * sizeof(DSBPOSITIONNOTIFY));
+       if (This->dscb->notifies)
+           This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+               This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
        else
-            This->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                    howmuch * sizeof(DSBPOSITIONNOTIFY));
+           This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+               howmuch * sizeof(DSBPOSITIONNOTIFY));
 
-        if (!This->notifies) {
+       if (This->dscb->notifies == NULL) {
            WARN("out of memory\n");
            return DSERR_OUTOFMEMORY;
        }
-        CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
-        This->nrofnotifies = howmuch;
+       CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
+       This->dscb->nrofnotifies = howmuch;
     } else {
-        HeapFree(GetProcessHeap(), 0, This->notifies);
-        This->notifies = NULL;
-        This->nrofnotifies = 0;
+        HeapFree(GetProcessHeap(), 0, This->dscb->notifies);
+        This->dscb->notifies = NULL;
+        This->dscb->nrofnotifies = 0;
     }
 
     return S_OK;
@@ -179,12 +135,36 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSou
 
 static const IDirectSoundNotifyVtbl dscnvt =
 {
-    IDirectSoundNotifyImpl_QueryInterface,
-    IDirectSoundNotifyImpl_AddRef,
-    IDirectSoundNotifyImpl_Release,
-    IDirectSoundNotifyImpl_SetNotificationPositions
+    IDirectSoundCaptureNotifyImpl_QueryInterface,
+    IDirectSoundCaptureNotifyImpl_AddRef,
+    IDirectSoundCaptureNotifyImpl_Release,
+    IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
 };
 
+static HRESULT IDirectSoundCaptureNotifyImpl_Create(
+    IDirectSoundCaptureBufferImpl *dscb,
+    IDirectSoundCaptureNotifyImpl **pdscn)
+{
+    IDirectSoundCaptureNotifyImpl * dscn;
+    TRACE("(%p,%p)\n",dscb,pdscn);
+
+    dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
+
+    if (dscn == NULL) {
+       WARN("out of memory\n");
+       return DSERR_OUTOFMEMORY;
+    }
+
+    dscn->ref = 0;
+    dscn->lpVtbl = &dscnvt;
+    dscn->dscb = dscb;
+    dscb->notify = dscn;
+    IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb);
+
+    *pdscn = dscn;
+    return DS_OK;
+}
+
 
 static const char * const captureStateString[] = {
     "STATE_STOPPED",
@@ -195,18 +175,16 @@ static const char * const captureStateString[] = {
 
 
 /*******************************************************************************
- * IDirectSoundCaptureBuffer
+ *             IDirectSoundCaptureBuffer
  */
-static inline IDirectSoundCaptureBufferImpl *impl_from_IDirectSoundCaptureBuffer8(IDirectSoundCaptureBuffer8 *iface)
-{
-    return CONTAINING_RECORD(iface, IDirectSoundCaptureBufferImpl, IDirectSoundCaptureBuffer8_iface);
-}
-
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundCaptureBuffer8 *iface,
-        REFIID riid, void **ppobj)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_QueryInterface(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    REFIID riid,
+    LPVOID* ppobj )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
+    HRESULT hres;
     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
 
     if (ppobj == NULL) {
@@ -216,53 +194,100 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_QueryInterface(IDirectSoundC
 
     *ppobj = NULL;
 
+    if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
+       if (!This->notify)
+           hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
+       if (This->notify) {
+           IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
+           if (This->device->hwbuf && !This->hwnotify) {
+               hres = IDsCaptureDriverBuffer_QueryInterface(This->device->hwbuf,
+                   &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify));
+               if (hres != DS_OK) {
+                   WARN("IDsCaptureDriverBuffer_QueryInterface failed\n");
+                   IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
+                   *ppobj = 0;
+                   return hres;
+               }
+           }
+
+            *ppobj = This->notify;
+           return DS_OK;
+       }
+
+       WARN("IID_IDirectSoundNotify\n");
+       return E_FAIL;
+    }
+
     if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) ||
          IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) {
        IDirectSoundCaptureBuffer8_AddRef(iface);
-        *ppobj = iface;
-        return S_OK;
-    }
-
-    if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
-        IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
-        *ppobj = &This->IDirectSoundNotify_iface;
-        return S_OK;
+       *ppobj = This;
+       return NO_ERROR;
     }
 
     FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj);
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI IDirectSoundCaptureBufferImpl_AddRef(IDirectSoundCaptureBuffer8 *iface)
+static ULONG WINAPI
+IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref - 1);
-
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
-
     return ref;
 }
 
-static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(IDirectSoundCaptureBuffer8 *iface)
+static ULONG WINAPI
+IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
     TRACE("(%p) ref was %d\n", This, ref + 1);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        capturebuffer_destroy(This);
+    if (!ref) {
+        TRACE("deleting object\n");
+       if (This->device->state == STATE_CAPTURING)
+           This->device->state = STATE_STOPPING;
+
+        HeapFree(GetProcessHeap(),0, This->pdscbd);
+
+       if (This->device->hwi) {
+           waveInReset(This->device->hwi);
+           waveInClose(This->device->hwi);
+            HeapFree(GetProcessHeap(),0, This->device->pwave);
+            This->device->pwave = 0;
+           This->device->hwi = 0;
+       }
 
+       if (This->device->hwbuf)
+           IDsCaptureDriverBuffer_Release(This->device->hwbuf);
+
+        /* remove from DirectSoundCaptureDevice */
+        This->device->capture_buffer = NULL;
+
+        if (This->notify)
+           IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify);
+
+        /* If driver manages its own buffer, IDsCaptureDriverBuffer_Release
+           should have freed the buffer. Prevent freeing it again in
+           IDirectSoundCaptureBufferImpl_Create */
+        if (!(This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY))
+           This->device->buffer = NULL;
+
+       HeapFree(GetProcessHeap(), 0, This->notifies);
+        HeapFree( GetProcessHeap(), 0, This );
+       TRACE("(%p) released\n", This);
+    }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureBuffer8 *iface,
-        DSCBCAPS *lpDSCBCaps)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetCaps(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDSCBCAPS lpDSCBCaps )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
 
     if (lpDSCBCaps == NULL) {
@@ -289,11 +314,14 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCaps(IDirectSoundCaptureB
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSoundCaptureBuffer8 *iface,
-        DWORD *lpdwCapturePosition, DWORD *lpdwReadPosition)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetCurrentPosition(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDWORD lpdwCapturePosition,
+    LPDWORD lpdwReadPosition )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
+    HRESULT hres = DS_OK;
     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
 
     if (This->device == NULL) {
@@ -301,35 +329,42 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetCurrentPosition(IDirectSo
         return DSERR_INVALIDPARAM;
     }
 
-    EnterCriticalSection(&This->device->lock);
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_GetPosition(This->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
+       if (hres != DS_OK)
+           WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
+    } else if (This->device->hwi) {
+        DWORD pos;
 
-    if (!This->device->client) {
+        EnterCriticalSection(&This->device->lock);
+        pos = (DWORD_PTR)This->device->pwave[This->device->index].lpData - (DWORD_PTR)This->device->buffer;
+        if (lpdwCapturePosition)
+            *lpdwCapturePosition = (This->device->pwave[This->device->index].dwBufferLength + pos) % This->device->buflen;
+        if (lpdwReadPosition)
+            *lpdwReadPosition = pos;
         LeaveCriticalSection(&This->device->lock);
+
+    } else {
         WARN("no driver\n");
-        return DSERR_NODRIVER;
+        hres = DSERR_NODRIVER;
     }
 
-    if(lpdwCapturePosition)
-        *lpdwCapturePosition = This->device->write_pos_bytes;
-
-    if(lpdwReadPosition)
-        *lpdwReadPosition = This->device->write_pos_bytes;
-
-    LeaveCriticalSection(&This->device->lock);
-
     TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
-    TRACE("returning DS_OK\n");
-
-    return DS_OK;
+    TRACE("returning %08x\n", hres);
+    return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptureBuffer8 *iface,
-        WAVEFORMATEX *lpwfxFormat, DWORD dwSizeAllocated, DWORD *lpdwSizeWritten)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetFormat(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPWAVEFORMATEX lpwfxFormat,
+    DWORD dwSizeAllocated,
+    LPDWORD lpdwSizeWritten )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     HRESULT hres = DS_OK;
-
-    TRACE("(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated, lpdwSizeWritten);
+    TRACE( "(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated,
+        lpdwSizeWritten );
 
     if (This->device == NULL) {
         WARN("invalid parameter: This->device == NULL\n");
@@ -356,11 +391,12 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFormat(IDirectSoundCaptur
     return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptureBuffer8 *iface,
-        DWORD *lpdwStatus)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetStatus(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDWORD lpdwStatus )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
 
     if (This->device == NULL) {
@@ -393,23 +429,32 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetStatus(IDirectSoundCaptur
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Initialize(IDirectSoundCaptureBuffer8 *iface,
-        IDirectSoundCapture *lpDSC, const DSCBUFFERDESC *lpcDSCBDesc)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_Initialize(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPDIRECTSOUNDCAPTURE lpDSC,
+    LPCDSCBUFFERDESC lpcDSCBDesc )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
 
     FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc );
 
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuffer8 *iface,
-        DWORD dwReadCusor, DWORD dwReadBytes, void **lplpvAudioPtr1, DWORD *lpdwAudioBytes1,
-        void **lplpvAudioPtr2, DWORD *lpdwAudioBytes2, DWORD dwFlags)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_Lock(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwReadCusor,
+    DWORD dwReadBytes,
+    LPVOID* lplpvAudioPtr1,
+    LPDWORD lpdwAudioBytes1,
+    LPVOID* lplpvAudioPtr2,
+    LPDWORD lpdwAudioBytes2,
+    DWORD dwFlags )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
     HRESULT hres = DS_OK;
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
         lpdwAudioBytes2, dwFlags, GetTickCount() );
@@ -431,7 +476,14 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuff
 
     EnterCriticalSection(&(This->device->lock));
 
-    if (This->device->client) {
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Lock(This->device->hwbuf, lplpvAudioPtr1,
+                                           lpdwAudioBytes1, lplpvAudioPtr2,
+                                           lpdwAudioBytes2, dwReadCusor,
+                                           dwReadBytes, dwFlags);
+       if (hres != DS_OK)
+           WARN("IDsCaptureDriverBuffer_Lock failed\n");
+    } else if (This->device->hwi) {
         *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
         if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
             *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
@@ -457,12 +509,13 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Lock(IDirectSoundCaptureBuff
     return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuffer8 *iface,
-        DWORD dwFlags)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_Start(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwFlags )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-    HRESULT hres;
-
+    HRESULT hres = DS_OK;
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p,0x%08x)\n", This, dwFlags );
 
     if (This->device == NULL) {
@@ -470,45 +523,101 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Start(IDirectSoundCaptureBuf
         return DSERR_INVALIDPARAM;
     }
 
-    if ( !This->device->client ) {
+    if ( (This->device->driver == 0) && (This->device->hwi == 0) ) {
         WARN("no driver\n");
         return DSERR_NODRIVER;
     }
 
     EnterCriticalSection(&(This->device->lock));
 
+    This->flags = dwFlags;
+    TRACE("old This->state=%s\n",captureStateString[This->device->state]);
     if (This->device->state == STATE_STOPPED)
         This->device->state = STATE_STARTING;
     else if (This->device->state == STATE_STOPPING)
         This->device->state = STATE_CAPTURING;
-    else
-        goto out;
     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
-    This->flags = dwFlags;
 
-    if (This->device->buffer)
-        FillMemory(This->device->buffer, This->device->buflen, (This->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
+    LeaveCriticalSection(&(This->device->lock));
 
-    hres = IAudioClient_Start(This->device->client);
-    if(FAILED(hres)){
-        WARN("Start failed: %08x\n", hres);
-        LeaveCriticalSection(&This->device->lock);
-        return hres;
-    }
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Start(This->device->hwbuf, dwFlags);
+       if (hres != DS_OK)
+           WARN("IDsCaptureDriverBuffer_Start failed\n");
+    } else if (This->device->hwi) {
+        DirectSoundCaptureDevice *device = This->device;
+
+        if (device->buffer) {
+            int c;
+            DWORD blocksize = DSOUND_fraglen(device->pwfx->nSamplesPerSec, device->pwfx->nBlockAlign);
+            device->nrofpwaves = device->buflen / blocksize + !!(device->buflen % blocksize);
+            TRACE("nrofpwaves=%d\n", device->nrofpwaves);
+
+            /* prepare headers */
+            if (device->pwave)
+                device->pwave = HeapReAlloc(GetProcessHeap(), 0,device->pwave, device->nrofpwaves*sizeof(WAVEHDR));
+            else
+                device->pwave = HeapAlloc(GetProcessHeap(), 0, device->nrofpwaves*sizeof(WAVEHDR));
+
+            for (c = 0; c < device->nrofpwaves; ++c) {
+                device->pwave[c].lpData = (char *)device->buffer + c * blocksize;
+                if (c + 1 == device->nrofpwaves)
+                    device->pwave[c].dwBufferLength = device->buflen - c * blocksize;
+                else
+                    device->pwave[c].dwBufferLength = blocksize;
+                device->pwave[c].dwBytesRecorded = 0;
+                device->pwave[c].dwUser = (DWORD_PTR)device;
+                device->pwave[c].dwFlags = 0;
+                device->pwave[c].dwLoops = 0;
+                hres = mmErr(waveInPrepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR)));
+                if (hres != DS_OK) {
+                    WARN("waveInPrepareHeader failed\n");
+                    while (c--)
+                        waveInUnprepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR));
+                    break;
+                }
+
+                hres = mmErr(waveInAddBuffer(device->hwi, &(device->pwave[c]), sizeof(WAVEHDR)));
+                if (hres != DS_OK) {
+                    WARN("waveInAddBuffer failed\n");
+                    while (c--)
+                        waveInUnprepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR));
+                    break;
+                }
+            }
 
-out:
-    LeaveCriticalSection(&This->device->lock);
+            FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
+        }
 
-    TRACE("returning DS_OK\n");
-    return DS_OK;
+        device->index = 0;
+
+       if (hres == DS_OK) {
+           /* start filling the first buffer */
+           hres = mmErr(waveInStart(device->hwi));
+            if (hres != DS_OK)
+                WARN("waveInStart failed\n");
+        }
+
+        if (hres != DS_OK) {
+            WARN("calling waveInClose because of error\n");
+            waveInClose(device->hwi);
+            device->hwi = 0;
+        }
+    } else {
+        WARN("no driver\n");
+        hres = DSERR_NODRIVER;
+    }
+
+    TRACE("returning %08x\n", hres);
+    return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuffer8 *iface)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
-    HRESULT hres;
-
-    TRACE("(%p)\n", This);
+    HRESULT hres = DS_OK;
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
+    TRACE( "(%p)\n", This );
 
     if (This->device == NULL) {
         WARN("invalid parameter: This->device == NULL\n");
@@ -524,26 +633,35 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Stop(IDirectSoundCaptureBuff
        This->device->state = STATE_STOPPED;
     TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
 
-    if(This->device->client){
-        hres = IAudioClient_Stop(This->device->client);
-        if(FAILED(hres)){
-            LeaveCriticalSection(&This->device->lock);
-            return hres;
-        }
-    }
-
     LeaveCriticalSection(&(This->device->lock));
 
-    TRACE("returning DS_OK\n");
-    return DS_OK;
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Stop(This->device->hwbuf);
+        if (hres != DS_OK)
+            WARN("IDsCaptureDriverBuffer_Stop() failed\n");
+    } else if (This->device->hwi) {
+        hres = mmErr(waveInReset(This->device->hwi));
+        if (hres != DS_OK)
+            WARN("waveInReset() failed\n");
+    } else {
+       WARN("no driver\n");
+        hres = DSERR_NODRIVER;
+    }
+
+    TRACE("returning %08x\n", hres);
+    return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBuffer8 *iface,
-        void *lpvAudioPtr1, DWORD dwAudioBytes1, void *lpvAudioPtr2, DWORD dwAudioBytes2)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_Unlock(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    LPVOID lpvAudioPtr1,
+    DWORD dwAudioBytes1,
+    LPVOID lpvAudioPtr2,
+    DWORD dwAudioBytes2 )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
     HRESULT hres = DS_OK;
-
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
         lpvAudioPtr2, dwAudioBytes2 );
 
@@ -552,7 +670,12 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBu
         return DSERR_INVALIDPARAM;
     }
 
-    if (!This->device->client) {
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Unlock(This->device->hwbuf, lpvAudioPtr1,
+                                             dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
+       if (hres != DS_OK)
+           WARN("IDsCaptureDriverBuffer_Unlock failed\n");
+    } else if (!This->device->hwi) {
         WARN("invalid call\n");
         hres = DSERR_INVALIDCALL;
     }
@@ -561,25 +684,29 @@ static HRESULT WINAPI IDirectSoundCaptureBufferImpl_Unlock(IDirectSoundCaptureBu
     return hres;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetObjectInPath(IDirectSoundCaptureBuffer8 *iface,
-        REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetObjectInPath(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    REFGUID rguidObject,
+    DWORD dwIndex,
+    REFGUID rguidInterface,
+    LPVOID* ppObject )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
 
     FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
         dwIndex, debugstr_guid(rguidInterface), ppObject );
 
-    if (!ppObject)
-        return DSERR_INVALIDPARAM;
-
-    *ppObject = NULL;
-    return DSERR_CONTROLUNAVAIL;
+    return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureBufferImpl_GetFXStatus(IDirectSoundCaptureBuffer8 *iface,
-        DWORD dwFXCount, DWORD *pdwFXStatus)
+static HRESULT WINAPI
+IDirectSoundCaptureBufferImpl_GetFXStatus(
+    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
+    DWORD dwFXCount,
+    LPDWORD pdwFXStatus )
 {
-    IDirectSoundCaptureBufferImpl *This = impl_from_IDirectSoundCaptureBuffer8(iface);
+    IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
 
     FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
 
@@ -634,13 +761,55 @@ static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from,
     }
 }
 
+static void CALLBACK
+DSOUND_capture_callback(HWAVEIN hwi, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1,
+                        DWORD_PTR dw2)
+{
+    DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
+    IDirectSoundCaptureBufferImpl * Moi = This->capture_buffer;
+    TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %d\n",hwi,msg,
+       msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" :
+       msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount());
+
+    if (msg == MM_WIM_DATA) {
+       EnterCriticalSection( &(This->lock) );
+       TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n",
+           captureStateString[This->state],This->index);
+       if (This->state != STATE_STOPPED) {
+           int index = This->index;
+           if (This->state == STATE_STARTING)
+               This->state = STATE_CAPTURING;
+           capture_CheckNotify(Moi, (DWORD_PTR)This->pwave[index].lpData - (DWORD_PTR)This->buffer, This->pwave[index].dwBufferLength);
+           This->index = (This->index + 1) % This->nrofpwaves;
+           if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) {
+               TRACE("end of buffer\n");
+               This->state = STATE_STOPPED;
+               capture_CheckNotify(Moi, 0, 0);
+           } else {
+               if (This->state == STATE_CAPTURING) {
+                   waveInUnprepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
+                   waveInPrepareHeader(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
+                   waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR));
+               } else if (This->state == STATE_STOPPING) {
+                   TRACE("stopping\n");
+                   This->state = STATE_STOPPED;
+               }
+           }
+       }
+       TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n",
+           captureStateString[This->state],This->index);
+       LeaveCriticalSection( &(This->lock) );
+    }
+
+    TRACE("completed\n");
+}
+
 static HRESULT IDirectSoundCaptureBufferImpl_Create(
     DirectSoundCaptureDevice *device,
     IDirectSoundCaptureBufferImpl ** ppobj,
     LPCDSCBUFFERDESC lpcDSCBufferDesc)
 {
     LPWAVEFORMATEX  wfex;
-    IDirectSoundCaptureBufferImpl *This;
     TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
 
     if (ppobj == NULL) {
@@ -648,15 +817,15 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
        return DSERR_INVALIDPARAM;
     }
 
-    *ppobj = NULL;
-
     if (!device) {
        WARN("not initialized\n");
+        *ppobj = NULL;
        return DSERR_UNINITIALIZED;
     }
 
     if (lpcDSCBufferDesc == NULL) {
        WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
+        *ppobj = NULL;
        return DSERR_INVALIDPARAM;
     }
 
@@ -665,6 +834,7 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
         (lpcDSCBufferDesc->dwBufferBytes == 0) ||
         (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { /* FIXME: DSERR_BADFORMAT ? */
        WARN("invalid lpcDSCBufferDesc\n");
+       *ppobj = NULL;
        return DSERR_INVALIDPARAM;
     }
 
@@ -677,26 +847,30 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
         wfex->wBitsPerSample, wfex->cbSize);
 
     device->pwfx = DSOUND_CopyFormat(wfex);
-    if ( device->pwfx == NULL )
+    if ( device->pwfx == NULL ) {
+       *ppobj = NULL;
        return DSERR_OUTOFMEMORY;
+    }
 
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+    *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
         sizeof(IDirectSoundCaptureBufferImpl));
 
-    if ( This == NULL ) {
+    if ( *ppobj == NULL ) {
        WARN("out of memory\n");
+       *ppobj = NULL;
        return DSERR_OUTOFMEMORY;
     } else {
-        HRESULT err = DS_OK;
+       HRESULT err = DS_OK;
         LPBYTE newbuf;
         DWORD buflen;
+        IDirectSoundCaptureBufferImpl *This = *ppobj;
 
-        This->numIfaces = 0;
-        This->ref = 0;
-        This->refn = 0;
+        This->ref = 1;
         This->device = device;
         This->device->capture_buffer = This;
-        This->nrofnotifies = 0;
+       This->notify = NULL;
+       This->nrofnotifies = 0;
+       This->hwnotify = NULL;
 
         This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
             lpcDSCBufferDesc->dwSize);
@@ -706,72 +880,80 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
             WARN("no memory\n");
             This->device->capture_buffer = 0;
             HeapFree( GetProcessHeap(), 0, This );
+            *ppobj = NULL;
             return DSERR_OUTOFMEMORY;
         }
 
-        This->IDirectSoundCaptureBuffer8_iface.lpVtbl = &dscbvt;
-        This->IDirectSoundNotify_iface.lpVtbl = &dscnvt;
-
-        err = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
-                CLSCTX_INPROC_SERVER, NULL, (void**)&device->client);
-        if(FAILED(err)){
-            WARN("Activate failed: %08x\n", err);
-            HeapFree(GetProcessHeap(), 0, This->pdscbd);
-            This->device->capture_buffer = 0;
-            HeapFree( GetProcessHeap(), 0, This );
-            return err;
-        }
-
-        err = IAudioClient_Initialize(device->client,
-                AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST,
-                200 * 100000, 50000, device->pwfx, NULL);
-        if(FAILED(err)){
-            WARN("Initialize failed: %08x\n", err);
-            IAudioClient_Release(device->client);
-            device->client = NULL;
-            HeapFree(GetProcessHeap(), 0, This->pdscbd);
-            This->device->capture_buffer = 0;
-            HeapFree( GetProcessHeap(), 0, This );
-            if(err == AUDCLNT_E_UNSUPPORTED_FORMAT)
-                return DSERR_BADFORMAT;
-            return err;
-        }
+        This->lpVtbl = &dscbvt;
+
+       if (device->driver) {
+            if (This->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
+                FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
+
+            if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
+                /* allocate buffer from system memory */
+                buflen = lpcDSCBufferDesc->dwBufferBytes;
+                TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
+                if (device->buffer)
+                    newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
+                else
+                    newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
+
+                if (newbuf == NULL) {
+                    WARN("failed to allocate capture buffer\n");
+                    err = DSERR_OUTOFMEMORY;
+                    /* but the old buffer might still exist and must be re-prepared */
+                } else {
+                    device->buffer = newbuf;
+                    device->buflen = buflen;
+                }
+            } else {
+                /* let driver allocate memory */
+                device->buflen = lpcDSCBufferDesc->dwBufferBytes;
+                /* FIXME: */
+                HeapFree( GetProcessHeap(), 0, device->buffer);
+                device->buffer = NULL;
+            }
 
-        err = IAudioClient_GetService(device->client, &IID_IAudioCaptureClient,
-                (void**)&device->capture);
-        if(FAILED(err)){
-            WARN("GetService failed: %08x\n", err);
-            IAudioClient_Release(device->client);
-            device->client = NULL;
-            HeapFree(GetProcessHeap(), 0, This->pdscbd);
-            This->device->capture_buffer = 0;
-            HeapFree( GetProcessHeap(), 0, This );
-            return err;
-        }
+           err = IDsCaptureDriver_CreateCaptureBuffer(device->driver,
+               device->pwfx,0,0,&(device->buflen),&(device->buffer),(LPVOID*)&(device->hwbuf));
+           if (err != DS_OK) {
+               WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
+               This->device->capture_buffer = 0;
+               HeapFree( GetProcessHeap(), 0, This );
+               *ppobj = NULL;
+               return err;
+           }
+       } else {
+           DWORD flags = CALLBACK_FUNCTION | WAVE_MAPPED;
+            err = mmErr(waveInOpen(&(device->hwi),
+                device->drvdesc.dnDevNode, device->pwfx,
+                (DWORD_PTR)DSOUND_capture_callback, (DWORD_PTR)device, flags));
+            if (err != DS_OK) {
+                WARN("waveInOpen failed\n");
+               This->device->capture_buffer = 0;
+               HeapFree( GetProcessHeap(), 0, This );
+               *ppobj = NULL;
+               return err;
+            }
 
-        buflen = lpcDSCBufferDesc->dwBufferBytes;
-        TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
-        if (device->buffer)
-            newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
-        else
-            newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
-        if (newbuf == NULL) {
-            IAudioClient_Release(device->client);
-            device->client = NULL;
-            IAudioCaptureClient_Release(device->capture);
-            device->capture = NULL;
-            HeapFree(GetProcessHeap(), 0, This->pdscbd);
-            This->device->capture_buffer = 0;
-            HeapFree( GetProcessHeap(), 0, This );
-            return DSERR_OUTOFMEMORY;
-        }
-        device->buffer = newbuf;
-        device->buflen = buflen;
+           buflen = lpcDSCBufferDesc->dwBufferBytes;
+            TRACE("desired buflen=%d, old buffer=%p\n", buflen, device->buffer);
+           if (device->buffer)
+                newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen);
+           else
+               newbuf = HeapAlloc(GetProcessHeap(),0,buflen);
+            if (newbuf == NULL) {
+                WARN("failed to allocate capture buffer\n");
+                err = DSERR_OUTOFMEMORY;
+                /* but the old buffer might still exist and must be re-prepared */
+            } else {
+                device->buffer = newbuf;
+                device->buflen = buflen;
+            }
+       }
     }
 
-    IDirectSoundCaptureBuffer_AddRef(&This->IDirectSoundCaptureBuffer8_iface);
-    *ppobj = This;
-
     TRACE("returning DS_OK\n");
     return DS_OK;
 }
@@ -780,6 +962,8 @@ static HRESULT IDirectSoundCaptureBufferImpl_Create(
 /*******************************************************************************
  * DirectSoundCaptureDevice
  */
+DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
+
 static HRESULT DirectSoundCaptureDevice_Create(
     DirectSoundCaptureDevice ** ppDevice)
 {
@@ -813,351 +997,224 @@ static ULONG DirectSoundCaptureDevice_Release(
 
     if (!ref) {
         TRACE("deleting object\n");
-
-        timeKillEvent(device->timerID);
-        timeEndPeriod(DS_TIME_RES);
-
-        EnterCriticalSection(&DSOUND_capturers_lock);
-        list_remove(&device->entry);
-        LeaveCriticalSection(&DSOUND_capturers_lock);
-
         if (device->capture_buffer)
-            IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface);
+            IDirectSoundCaptureBufferImpl_Release(
+               (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
+
+        if (device->driver) {
+            IDsCaptureDriver_Close(device->driver);
+            IDsCaptureDriver_Release(device->driver);
+        }
 
-        if(device->mmdevice)
-            IMMDevice_Release(device->mmdevice);
         HeapFree(GetProcessHeap(), 0, device->pwfx);
         device->lock.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection( &(device->lock) );
+        DSOUND_capture[device->drvdesc.dnDevNode] = NULL;
         HeapFree(GetProcessHeap(), 0, device);
        TRACE("(%p) released\n", device);
     }
     return ref;
 }
 
-static void CALLBACK DSOUND_capture_timer(UINT timerID, UINT msg, DWORD_PTR user,
-                                          DWORD_PTR dw1, DWORD_PTR dw2)
-{
-    DirectSoundCaptureDevice *device = (DirectSoundCaptureDevice*)user;
-    UINT32 packet_frames, packet_bytes, avail_bytes;
-    DWORD flags;
-    BYTE *buf;
-    HRESULT hr;
-
-    if(!device->ref)
-        return;
-
-    EnterCriticalSection(&device->lock);
-
-    if(!device->capture_buffer || device->state == STATE_STOPPED){
-        LeaveCriticalSection(&device->lock);
-        return;
-    }
-
-    if(device->state == STATE_STOPPING){
-        device->state = STATE_STOPPED;
-        LeaveCriticalSection(&device->lock);
-        return;
-    }
-
-    if(device->state == STATE_STARTING)
-        device->state = STATE_CAPTURING;
-
-    hr = IAudioCaptureClient_GetBuffer(device->capture, &buf, &packet_frames,
-            &flags, NULL, NULL);
-    if(FAILED(hr)){
-        LeaveCriticalSection(&device->lock);
-        WARN("GetBuffer failed: %08x\n", hr);
-        return;
-    }
-
-    packet_bytes = packet_frames * device->pwfx->nBlockAlign;
-
-    avail_bytes = device->buflen - device->write_pos_bytes;
-    if(avail_bytes > packet_bytes)
-        avail_bytes = packet_bytes;
-
-    memcpy(device->buffer + device->write_pos_bytes, buf, avail_bytes);
-    capture_CheckNotify(device->capture_buffer, device->write_pos_bytes, avail_bytes);
-
-    packet_bytes -= avail_bytes;
-    if(packet_bytes > 0){
-        if(device->capture_buffer->flags & DSCBSTART_LOOPING){
-            memcpy(device->buffer, buf + avail_bytes, packet_bytes);
-            capture_CheckNotify(device->capture_buffer, 0, packet_bytes);
-        }else{
-            device->state = STATE_STOPPED;
-            capture_CheckNotify(device->capture_buffer, 0, 0);
-        }
-    }
-
-    device->write_pos_bytes += avail_bytes + packet_bytes;
-    device->write_pos_bytes %= device->buflen;
-
-    hr = IAudioCaptureClient_ReleaseBuffer(device->capture, packet_frames);
-    if(FAILED(hr)){
-        LeaveCriticalSection(&device->lock);
-        WARN("ReleaseBuffer failed: %08x\n", hr);
-        return;
-    }
-
-    LeaveCriticalSection(&device->lock);
-}
-
-static struct _TestFormat {
-    DWORD flag;
-    DWORD rate;
-    DWORD depth;
-    WORD channels;
-} formats_to_test[] = {
-    { WAVE_FORMAT_1M08, 11025, 8, 1 },
-    { WAVE_FORMAT_1M16, 11025, 16, 1 },
-    { WAVE_FORMAT_1S08, 11025, 8, 2 },
-    { WAVE_FORMAT_1S16, 11025, 16, 2 },
-    { WAVE_FORMAT_2M08, 22050, 8, 1 },
-    { WAVE_FORMAT_2M16, 22050, 16, 1 },
-    { WAVE_FORMAT_2S08, 22050, 8, 2 },
-    { WAVE_FORMAT_2S16, 22050, 16, 2 },
-    { WAVE_FORMAT_4M08, 44100, 8, 1 },
-    { WAVE_FORMAT_4M16, 44100, 16, 1 },
-    { WAVE_FORMAT_4S08, 44100, 8, 2 },
-    { WAVE_FORMAT_4S16, 44100, 16, 2 },
-    { WAVE_FORMAT_48M08, 48000, 8, 1 },
-    { WAVE_FORMAT_48M16, 48000, 16, 1 },
-    { WAVE_FORMAT_48S08, 48000, 8, 2 },
-    { WAVE_FORMAT_48S16, 48000, 16, 2 },
-    { WAVE_FORMAT_96M08, 96000, 8, 1 },
-    { WAVE_FORMAT_96M16, 96000, 16, 1 },
-    { WAVE_FORMAT_96S08, 96000, 8, 2 },
-    { WAVE_FORMAT_96S16, 96000, 16, 2 },
-    {0}
-};
-
 static HRESULT DirectSoundCaptureDevice_Initialize(
     DirectSoundCaptureDevice ** ppDevice,
     LPCGUID lpcGUID)
 {
-    HRESULT hr;
+    HRESULT err = DSERR_INVALIDPARAM;
+    unsigned wid, widn;
+    BOOLEAN found = FALSE;
     GUID devGUID;
-    IMMDevice *mmdevice;
-    struct _TestFormat *fmt;
-    DirectSoundCaptureDevice *device;
-    IAudioClient *client;
-
+    DirectSoundCaptureDevice *device = *ppDevice;
     TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
 
     /* Default device? */
     if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
-        lpcGUID = &DSDEVID_DefaultCapture;
-
-    if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultPlayback) ||
-            IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoicePlayback))
-        return DSERR_NODRIVER;
+       lpcGUID = &DSDEVID_DefaultCapture;
 
     if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
         WARN("invalid parameter: lpcGUID\n");
         return DSERR_INVALIDPARAM;
     }
 
-    hr = get_mmdevice(eCapture, &devGUID, &mmdevice);
-    if(FAILED(hr))
-        return hr;
+    widn = waveInGetNumDevs();
+    if (!widn) {
+       WARN("no audio devices found\n");
+       return DSERR_NODRIVER;
+    }
 
-    EnterCriticalSection(&DSOUND_capturers_lock);
+    /* enumerate WINMM audio devices and find the one we want */
+    for (wid=0; wid<widn; wid++) {
+       if (IsEqualGUID( &devGUID, &DSOUND_capture_guids[wid]) ) {
+           found = TRUE;
+           break;
+       }
+    }
 
-    LIST_FOR_EACH_ENTRY(device, &DSOUND_capturers, DirectSoundCaptureDevice, entry){
-        if(IsEqualGUID(&device->guid, &devGUID)){
-            IMMDevice_Release(mmdevice);
-            LeaveCriticalSection(&DSOUND_capturers_lock);
-            return DSERR_ALLOCATED;
-        }
+    if (found == FALSE) {
+       WARN("No device found matching given ID!\n");
+       return DSERR_NODRIVER;
+    }
+
+    if (DSOUND_capture[wid]) {
+        WARN("already in use\n");
+        return DSERR_ALLOCATED;
     }
 
-    hr = DirectSoundCaptureDevice_Create(&device);
-    if (hr != DS_OK) {
+    err = DirectSoundCaptureDevice_Create(&(device));
+    if (err != DS_OK) {
         WARN("DirectSoundCaptureDevice_Create failed\n");
-        LeaveCriticalSection(&DSOUND_capturers_lock);
-        return hr;
+        return err;
     }
 
+    *ppDevice = device;
     device->guid = devGUID;
 
-    device->mmdevice = mmdevice;
-
-    device->drvcaps.dwFlags = 0;
-
-    device->drvcaps.dwFormats = 0;
-    device->drvcaps.dwChannels = 0;
-    hr = IMMDevice_Activate(mmdevice, &IID_IAudioClient,
-            CLSCTX_INPROC_SERVER, NULL, (void**)&client);
-    if(FAILED(hr)){
-        device->lock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection(&device->lock);
-        HeapFree(GetProcessHeap(), 0, device);
-        LeaveCriticalSection(&DSOUND_capturers_lock);
-        return DSERR_NODRIVER;
+    /* Disable the direct sound driver to force emulation if requested. */
+    device->driver = NULL;
+    if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
+    {
+        err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&device->driver,0));
+        if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
+            WARN("waveInMessage failed; err=%x\n",err);
+            return err;
+        }
     }
+    err = DS_OK;
 
-    for(fmt = formats_to_test; fmt->flag; ++fmt){
-        if(DSOUND_check_supported(client, fmt->rate, fmt->depth, fmt->channels)){
-            device->drvcaps.dwFormats |= fmt->flag;
-            if(fmt->channels > device->drvcaps.dwChannels)
-                device->drvcaps.dwChannels = fmt->channels;
+    /* Get driver description */
+    if (device->driver) {
+        TRACE("using DirectSound driver\n");
+        err = IDsCaptureDriver_GetDriverDesc(device->driver, &(device->drvdesc));
+       if (err != DS_OK) {
+           WARN("IDsCaptureDriver_GetDriverDesc failed\n");
+           return err;
+       }
+    } else {
+        TRACE("using WINMM\n");
+        /* if no DirectSound interface available, use WINMM API instead */
+        device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
+            DSDDESC_DOMMSYSTEMSETFORMAT;
+    }
+
+    device->drvdesc.dnDevNode = wid;
+
+    /* open the DirectSound driver if available */
+    if (device->driver && (err == DS_OK))
+        err = IDsCaptureDriver_Open(device->driver);
+
+    if (err == DS_OK) {
+        *ppDevice = device;
+
+        /* the driver is now open, so it's now allowed to call GetCaps */
+        if (device->driver) {
+           device->drvcaps.dwSize = sizeof(device->drvcaps);
+            err = IDsCaptureDriver_GetCaps(device->driver,&(device->drvcaps));
+           if (err != DS_OK) {
+               WARN("IDsCaptureDriver_GetCaps failed\n");
+               return err;
+           }
+        } else /*if (device->hwi)*/ {
+            WAVEINCAPSA    wic;
+            err = mmErr(waveInGetDevCapsA((UINT)device->drvdesc.dnDevNode, &wic, sizeof(wic)));
+
+            if (err == DS_OK) {
+                device->drvcaps.dwFlags = 0;
+                lstrcpynA(device->drvdesc.szDrvname, wic.szPname,
+                          sizeof(device->drvdesc.szDrvname));
+
+                device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
+                device->drvcaps.dwFormats = wic.dwFormats;
+                device->drvcaps.dwChannels = wic.wChannels;
+            }
         }
     }
-    IAudioClient_Release(client);
-
-    device->timerID = DSOUND_create_timer(DSOUND_capture_timer, (DWORD_PTR)device);
-
-    list_add_tail(&DSOUND_capturers, &device->entry);
 
-    *ppDevice = device;
-
-    LeaveCriticalSection(&DSOUND_capturers_lock);
-
-    return S_OK;
+    return err;
 }
 
 
 /*****************************************************************************
  * IDirectSoundCapture implementation structure
  */
-typedef struct IDirectSoundCaptureImpl
-{
-    IUnknown                 IUnknown_inner;
-    IDirectSoundCapture      IDirectSoundCapture_iface;
-    LONG                     ref, refdsc, numIfaces;
-    IUnknown                 *outer_unk;        /* internal */
-    DirectSoundCaptureDevice *device;
-    BOOL                     has_dsc8;
-} IDirectSoundCaptureImpl;
-
-static void capture_destroy(IDirectSoundCaptureImpl *This)
-{
-    if (This->device)
-        DirectSoundCaptureDevice_Release(This->device);
-    HeapFree(GetProcessHeap(),0,This);
-    TRACE("(%p) released\n", This);
-}
-
-/*******************************************************************************
- *      IUnknown Implementation for DirectSoundCapture
- */
-static inline IDirectSoundCaptureImpl *impl_from_IUnknown(IUnknown *iface)
-{
-    return CONTAINING_RECORD(iface, IDirectSoundCaptureImpl, IUnknown_inner);
-}
-
-static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
-{
-    IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
-
-    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
-
-    if (!ppv) {
-        WARN("invalid parameter\n");
-        return E_INVALIDARG;
-    }
-    *ppv = NULL;
-
-    if (IsEqualIID(riid, &IID_IUnknown))
-        *ppv = &This->IUnknown_inner;
-    else if (IsEqualIID(riid, &IID_IDirectSoundCapture))
-        *ppv = &This->IDirectSoundCapture_iface;
-    else {
-        WARN("unknown IID %s\n", debugstr_guid(riid));
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown*)*ppv);
-    return S_OK;
-}
-
-static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
+struct IDirectSoundCaptureImpl
 {
-    IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
-    return ref;
-}
+    /* IUnknown fields */
+    const IDirectSoundCaptureVtbl     *lpVtbl;
+    LONG                               ref;
 
-static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
-{
-    IDirectSoundCaptureImpl *This = impl_from_IUnknown(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        capture_destroy(This);
-    return ref;
-}
-
-static const IUnknownVtbl unk_vtbl =
-{
-    IUnknownImpl_QueryInterface,
-    IUnknownImpl_AddRef,
-    IUnknownImpl_Release
+    DirectSoundCaptureDevice          *device;
 };
 
 /***************************************************************************
  * IDirectSoundCaptureImpl
  */
-static inline struct IDirectSoundCaptureImpl *impl_from_IDirectSoundCapture(IDirectSoundCapture *iface)
+static HRESULT WINAPI
+IDirectSoundCaptureImpl_QueryInterface(
+    LPDIRECTSOUNDCAPTURE iface,
+    REFIID riid,
+    LPVOID* ppobj )
 {
-    return CONTAINING_RECORD(iface, struct IDirectSoundCaptureImpl, IDirectSoundCapture_iface);
-}
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
+    TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
 
-static HRESULT WINAPI IDirectSoundCaptureImpl_QueryInterface(IDirectSoundCapture *iface,
-        REFIID riid, void **ppv)
-{
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
-    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
-    return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
-}
+    if (ppobj == NULL) {
+       WARN("invalid parameter\n");
+       return E_INVALIDARG;
+    }
 
-static ULONG WINAPI IDirectSoundCaptureImpl_AddRef(IDirectSoundCapture *iface)
-{
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
-    ULONG ref = InterlockedIncrement(&This->refdsc);
+    *ppobj = NULL;
 
-    TRACE("(%p) ref=%d\n", This, ref);
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
+        *ppobj = This;
+        return DS_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
+        IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This);
+        *ppobj = This;
+        return DS_OK;
+    }
 
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
+    WARN("unsupported riid: %s\n", debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI
+IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
+{
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
-static ULONG WINAPI IDirectSoundCaptureImpl_Release(IDirectSoundCapture *iface)
+static ULONG WINAPI
+IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
 {
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
-    ULONG ref = InterlockedDecrement(&This->refdsc);
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
-    TRACE("(%p) ref=%d\n", This, ref);
+    if (!ref) {
+        if (This->device)
+            DirectSoundCaptureDevice_Release(This->device);
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        capture_destroy(This);
+        HeapFree( GetProcessHeap(), 0, This );
+        TRACE("(%p) released\n", This);
+    }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCapture *iface,
-        LPCDSCBUFFERDESC lpcDSCBufferDesc, IDirectSoundCaptureBuffer **lplpDSCaptureBuffer,
-        IUnknown *pUnk)
+static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc,
+    LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
+    LPUNKNOWN pUnk )
 {
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
     HRESULT hr;
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
 
     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
 
-    if (pUnk) {
-        WARN("invalid parameter: pUnk != NULL\n");
-        return DSERR_NOAGGREGATION;
-    }
-
     if (lpcDSCBufferDesc == NULL) {
        WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
        return DSERR_INVALIDPARAM;
@@ -1188,11 +1245,11 @@ static HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(IDirectSoundCa
     return hr;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface,
-        LPDSCCAPS lpDSCCaps)
+static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPDSCCAPS lpDSCCaps )
 {
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
-
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
     TRACE("(%p,%p)\n",This,lpDSCCaps);
 
     if (This->device == NULL) {
@@ -1220,11 +1277,11 @@ static HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(IDirectSoundCapture *iface
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(IDirectSoundCapture *iface,
-        LPCGUID lpcGUID)
+static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID )
 {
-    IDirectSoundCaptureImpl *This = impl_from_IDirectSoundCapture(iface);
-
+    IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
     TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
 
     if (This->device != NULL) {
@@ -1247,50 +1304,85 @@ static const IDirectSoundCaptureVtbl dscvt =
     IDirectSoundCaptureImpl_Initialize
 };
 
-HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_dsc8)
+static HRESULT IDirectSoundCaptureImpl_Create(
+    LPDIRECTSOUNDCAPTURE8 * ppDSC)
 {
-    IDirectSoundCaptureImpl *obj;
-    HRESULT hr;
-
-    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+    IDirectSoundCaptureImpl *pDSC;
+    TRACE("(%p)\n", ppDSC);
 
-    *ppv = NULL;
-    obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
-    if (obj == NULL) {
+    /* Allocate memory */
+    pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
+    if (pDSC == NULL) {
         WARN("out of memory\n");
+        *ppDSC = NULL;
         return DSERR_OUTOFMEMORY;
     }
 
-    setup_dsound_options();
+    pDSC->lpVtbl = &dscvt;
+    pDSC->ref    = 0;
+    pDSC->device = NULL;
 
-    obj->IUnknown_inner.lpVtbl = &unk_vtbl;
-    obj->IDirectSoundCapture_iface.lpVtbl = &dscvt;
-    obj->ref = 1;
-    obj->refdsc = 0;
-    obj->numIfaces = 1;
-    obj->device = NULL;
-    obj->has_dsc8 = has_dsc8;
+    *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
 
-    /* COM aggregation supported only internally */
-    if (outer_unk)
-        obj->outer_unk = outer_unk;
-    else
-        obj->outer_unk = &obj->IUnknown_inner;
+    return DS_OK;
+}
 
-    hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
-    IUnknown_Release(&obj->IUnknown_inner);
+HRESULT DSOUND_CaptureCreate(
+    REFIID riid,
+    LPDIRECTSOUNDCAPTURE *ppDSC)
+{
+    LPDIRECTSOUNDCAPTURE pDSC;
+    HRESULT hr;
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC);
+
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSoundCapture)) {
+        *ppDSC = 0;
+        return E_NOINTERFACE;
+    }
+
+    /* Get dsound configuration */
+    setup_dsound_options();
+
+    hr = IDirectSoundCaptureImpl_Create(&pDSC);
+    if (hr == DS_OK) {
+        IDirectSoundCapture_AddRef(pDSC);
+        *ppDSC = pDSC;
+    } else {
+        WARN("IDirectSoundCaptureImpl_Create failed\n");
+        *ppDSC = 0;
+    }
 
     return hr;
 }
 
-HRESULT DSOUND_CaptureCreate(REFIID riid, void **ppv)
+HRESULT DSOUND_CaptureCreate8(
+    REFIID riid,
+    LPDIRECTSOUNDCAPTURE8 *ppDSC8)
 {
-    return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, FALSE);
-}
+    LPDIRECTSOUNDCAPTURE8 pDSC8;
+    HRESULT hr;
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
 
-HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
-{
-    return IDirectSoundCaptureImpl_Create(NULL, riid, ppv, TRUE);
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
+        *ppDSC8 = 0;
+        return E_NOINTERFACE;
+    }
+
+    /* Get dsound configuration */
+    setup_dsound_options();
+
+    hr = IDirectSoundCaptureImpl_Create(&pDSC8);
+    if (hr == DS_OK) {
+        IDirectSoundCapture_AddRef(pDSC8);
+        *ppDSC8 = pDSC8;
+    } else {
+        WARN("IDirectSoundCaptureImpl_Create failed\n");
+        *ppDSC8 = 0;
+    }
+
+    return hr;
 }
 
 /***************************************************************************
@@ -1315,12 +1407,13 @@ HRESULT DSOUND_CaptureCreate8(REFIID riid, void **ppv)
  *
  *    DSERR_ALLOCATED is returned for sound devices that do not support full duplex.
  */
-HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **ppDSC,
-        IUnknown *pUnkOuter)
+HRESULT WINAPI DirectSoundCaptureCreate(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUNDCAPTURE *ppDSC,
+    LPUNKNOWN pUnkOuter)
 {
     HRESULT hr;
-    IDirectSoundCapture *pDSC;
-
+    LPDIRECTSOUNDCAPTURE pDSC;
     TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter);
 
     if (ppDSC == NULL) {
@@ -1330,10 +1423,11 @@ HRESULT WINAPI DirectSoundCaptureCreate(LPCGUID lpcGUID, IDirectSoundCapture **p
 
     if (pUnkOuter) {
        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDSC = NULL;
         return DSERR_NOAGGREGATION;
     }
 
-    hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, (void**)&pDSC);
+    hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
     if (hr == DS_OK) {
         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
         if (hr != DS_OK) {
@@ -1389,7 +1483,7 @@ HRESULT WINAPI DirectSoundCaptureCreate8(
         return DSERR_NOAGGREGATION;
     }
 
-    hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, (void**)&pDSC8);
+    hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
     if (hr == DS_OK) {
         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
         if (hr != DS_OK) {