- fix some prototypes, remove dxroslayer from dsound
authorKamil Hornicek <kamil.hornicek@reactos.org>
Mon, 9 Mar 2009 19:46:37 +0000 (19:46 +0000)
committerKamil Hornicek <kamil.hornicek@reactos.org>
Mon, 9 Mar 2009 19:46:37 +0000 (19:46 +0000)
- sync dsound with wine head, it now works again (tested on win xp and reactos)

svn path=/trunk/; revision=39921

23 files changed:
reactos/dll/directx/dsound/buffer.c
reactos/dll/directx/dsound/capture.c
reactos/dll/directx/dsound/dsound.c
reactos/dll/directx/dsound/dsound.rbuild
reactos/dll/directx/dsound/dsound_convert.c [new file with mode: 0644]
reactos/dll/directx/dsound/dsound_main.c
reactos/dll/directx/dsound/dsound_private.h
reactos/dll/directx/dsound/duplex.c
reactos/dll/directx/dsound/dxroslayer/dxros_layer.h [deleted file]
reactos/dll/directx/dsound/dxroslayer/dxrosdrv_querydsounddesc.c [deleted file]
reactos/dll/directx/dsound/dxroslayer/dxrosdrv_querydsoundiface.c [deleted file]
reactos/dll/directx/dsound/dxroslayer/dxroslayer.c [deleted file]
reactos/dll/directx/dsound/dxroslayer/getguidfromstring.c [deleted file]
reactos/dll/directx/dsound/mixer.c
reactos/dll/directx/dsound/primary.c
reactos/dll/directx/dsound/propset.c
reactos/dll/directx/dsound/regsvr.c
reactos/dll/directx/dsound/sound3d.c
reactos/dll/directx/dsound/version.rc
reactos/include/psdk/dsdriver.h
reactos/include/psdk/dsound.h
reactos/include/reactos/wine/mmsystem.h
reactos/lib/sdk/dxguid/dxguid-mingw.c

index 2541b99..251c436 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -25,8 +25,8 @@
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "mmsystem.h"
-#include "winreg.h"
 #include "winternl.h"
 #include "wine/debug.h"
 #include "dsound.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
+static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);
+
 /*******************************************************************************
  *             IDirectSoundNotify
  */
+
+struct IDirectSoundNotifyImpl
+{
+    /* IUnknown fields */
+    const IDirectSoundNotifyVtbl *lpVtbl;
+    LONG                        ref;
+    IDirectSoundBufferImpl*     dsb;
+};
+
+static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
+                                             IDirectSoundNotifyImpl **pdsn);
+static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
+
 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
        LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
 ) {
@@ -56,7 +71,7 @@ static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
 {
     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -64,7 +79,7 @@ static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
 {
     IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
@@ -79,7 +94,7 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
        LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
 ) {
        IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
-       TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+       TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
 
         if (howmuch > 0 && notify == NULL) {
            WARN("invalid parameter: notify == NULL\n");
@@ -89,7 +104,7 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
        if (TRACE_ON(dsound)) {
            unsigned int        i;
            for (i=0;i<howmuch;i++)
-               TRACE("notify at %ld to %p\n",
+               TRACE("notify at %d to %p\n",
                    notify[i].dwOffset,notify[i].hEventNotify);
        }
 
@@ -102,11 +117,8 @@ static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
         } else if (howmuch > 0) {
            /* Make an internal copy of the caller-supplied array.
             * Replace the existing copy if one is already present. */
-           if (This->dsb->notifies)
-                   This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
-                       This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
-           else
-                   This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+           HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
+           This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
                        howmuch * sizeof(DSBPOSITIONNOTIFY));
 
            if (This->dsb->notifies == NULL) {
@@ -132,14 +144,14 @@ static const IDirectSoundNotifyVtbl dsnvt =
     IDirectSoundNotifyImpl_SetNotificationPositions,
 };
 
-HRESULT WINAPI IDirectSoundNotifyImpl_Create(
+static HRESULT IDirectSoundNotifyImpl_Create(
     IDirectSoundBufferImpl * dsb,
     IDirectSoundNotifyImpl **pdsn)
 {
     IDirectSoundNotifyImpl * dsn;
     TRACE("(%p,%p)\n",dsb,pdsn);
 
-    dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
+    dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn));
 
     if (dsn == NULL) {
         WARN("out of memory\n");
@@ -156,7 +168,7 @@ HRESULT WINAPI IDirectSoundNotifyImpl_Create(
     return DS_OK;
 }
 
-HRESULT WINAPI IDirectSoundNotifyImpl_Destroy(
+static HRESULT IDirectSoundNotifyImpl_Destroy(
     IDirectSoundNotifyImpl *pdsn)
 {
     TRACE("(%p)\n",pdsn);
@@ -188,24 +200,27 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
        LONG oldVol;
        HRESULT hres = DS_OK;
 
-       TRACE("(%p,%ld)\n",This,vol);
+       TRACE("(%p,%d)\n",This,vol);
 
        if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
-               WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
+               WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
                return DSERR_CONTROLUNAVAIL;
        }
 
        if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
-               WARN("invalid parameter: vol = %ld\n", vol);
+               WARN("invalid parameter: vol = %d\n", vol);
                return DSERR_INVALIDPARAM;
        }
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
                oldVol = This->ds3db_lVolume;
                This->ds3db_lVolume = vol;
+               if (vol != oldVol)
+                       /* recalc 3d volume, which in turn recalcs the pans */
+                       DSOUND_Calc3DBuffer(This);
        } else {
                oldVol = This->volpan.lVolume;
                This->volpan.lVolume = vol;
@@ -218,11 +233,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
                        hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
                        if (hres != DS_OK)
                                WARN("IDsDriverBuffer_SetVolumePan failed\n");
-               } else
-                       DSOUND_ForceRemix(This);
+               }
        }
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return hres;
@@ -255,7 +269,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
        DWORD oldFreq;
 
-       TRACE("(%p,%ld)\n",This,freq);
+       TRACE("(%p,%d)\n",This,freq);
 
        if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
                WARN("control unavailable\n");
@@ -266,24 +280,23 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
                freq = This->pwfx->nSamplesPerSec;
 
        if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
-               WARN("invalid parameter: freq = %ld\n", freq);
+               WARN("invalid parameter: freq = %d\n", freq);
                return DSERR_INVALIDPARAM;
        }
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        oldFreq = This->freq;
        This->freq = freq;
        if (freq != oldFreq) {
-               This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->device->pwfx->nSamplesPerSec;
+               This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
                This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
                DSOUND_RecalcFormat(This);
-               if (!This->hwbuf)
-                       DSOUND_ForceRemix(This);
+               DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
        }
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return DS_OK;
@@ -294,15 +307,14 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Play(
 ) {
        HRESULT hres = DS_OK;
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-       TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
+       TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        This->playflags = flags;
-       if (This->state == STATE_STOPPED) {
+       if (This->state == STATE_STOPPED && !This->hwbuf) {
                This->leadin = TRUE;
-               This->startpos = This->buf_mixpos;
                This->state = STATE_STARTING;
        } else if (This->state == STATE_STOPPING)
                This->state = STATE_PLAYING;
@@ -314,7 +326,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Play(
                        This->state = STATE_PLAYING;
        }
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return hres;
@@ -327,12 +339,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
        TRACE("(%p)\n",This);
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        if (This->state == STATE_PLAYING)
                This->state = STATE_STOPPING;
        else if (This->state == STATE_STARTING)
+       {
                This->state = STATE_STOPPED;
+               DSOUND_CheckEvent(This, 0, 0);
+       }
        if (This->hwbuf) {
                hres = IDsDriverBuffer_Stop(This->hwbuf);
                if (hres != DS_OK)
@@ -340,9 +355,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
                else
                        This->state = STATE_STOPPED;
        }
-       DSOUND_CheckEvent(This, 0);
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return hres;
@@ -352,7 +366,7 @@ static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
 {
     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -360,31 +374,24 @@ static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
 {
     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
-       DSOUND_RemoveBuffer(This->dsound, This);
+       DirectSoundDevice_RemoveBuffer(This->device, This);
+       RtlDeleteResource(&This->lock);
 
-       This->lock.DebugInfo->Spare[0] = 0;
-       DeleteCriticalSection(&(This->lock));
-
-       if (This->hwbuf) {
+       if (This->hwbuf)
                IDsDriverBuffer_Release(This->hwbuf);
-               if (This->dsound->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
-                       This->buffer->ref--;
-                       if (This->buffer->ref==0) {
-                               HeapFree(GetProcessHeap(),0,This->buffer->memory);
-                               HeapFree(GetProcessHeap(),0,This->buffer);
-                       }
-               }
-       } else {
+       if (!This->hwbuf || (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)) {
                This->buffer->ref--;
+               list_remove(&This->entry);
                if (This->buffer->ref==0) {
                        HeapFree(GetProcessHeap(),0,This->buffer->memory);
                        HeapFree(GetProcessHeap(),0,This->buffer);
                }
        }
 
+       HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
        HeapFree(GetProcessHeap(), 0, This->notifies);
        HeapFree(GetProcessHeap(), 0, This->pwfx);
        HeapFree(GetProcessHeap(), 0, This);
@@ -394,50 +401,14 @@ static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
     return ref;
 }
 
-DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite)
-{
-       DWORD bplay = This->buf_mixpos;
-       DWORD pmix = This->primary_mixpos;
-       TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);
-
-       /* the actual primary play position (pplay) is always behind last mixed (pmix),
-        * unless the computer is too slow or something */
-       /* we need to know how far away we are from there */
-       if (pmix < pplay) pmix += This->dsound->device->buflen; /* wraparound */
-       pmix -= pplay;
-       /* detect buffer underrun */
-       if (pwrite < pplay) pwrite += This->dsound->device->buflen; /* wraparound */
-       pwrite -= pplay;
-       if (pmix > (ds_snd_queue_max * This->dsound->device->fraglen + pwrite + This->dsound->device->writelead)) {
-               WARN("detected an underrun: primary queue was %ld\n",pmix);
-               pmix = 0;
-       }
-       /* divide the offset by its sample size */
-       pmix /= This->dsound->device->pwfx->nBlockAlign;
-       TRACE("primary back-samples=%ld\n",pmix);
-       /* adjust for our frequency */
-       pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
-       /* multiply by our own sample size */
-       pmix *= This->pwfx->nBlockAlign;
-       TRACE("this back-offset=%ld\n", pmix);
-       /* subtract from our last mixed position */
-       while (bplay < pmix) bplay += This->buflen; /* wraparound */
-       bplay -= pmix;
-       if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
-               /* seems we haven't started playing yet */
-               TRACE("this still in lead-in phase\n");
-               bplay = This->startpos;
-       }
-       /* return the result */
-       return bplay;
-}
-
 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
        LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
 ) {
        HRESULT hres;
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
        TRACE("(%p,%p,%p)\n",This,playpos,writepos);
+
+       RtlAcquireResourceShared(&This->lock, TRUE);
        if (This->hwbuf) {
                hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
                if (hres != DS_OK) {
@@ -445,47 +416,29 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
                    return hres;
                }
        } else {
-               if (playpos && (This->state != STATE_PLAYING)) {
-                       /* we haven't been merged into the primary buffer (yet) */
-                       *playpos = This->buf_mixpos;
-               } else if (playpos) {
-                       DWORD pplay, pwrite;
-                       /* let's get this exact; first, recursively call GetPosition on the primary */
-                       EnterCriticalSection(&(This->dsound->device->mixlock));
-                       if (DSOUND_PrimaryGetPosition(This->dsound->device, &pplay, &pwrite) != DS_OK)
-                               WARN("DSOUND_PrimaryGetPosition failed\n");
-                       /* detect HEL mode underrun */
-                       if (!(This->dsound->device->hwbuf || This->dsound->device->pwqueue))
-                               TRACE("detected an underrun\n");
-                       if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->device->hwbuf) {
-                               /* calculate play position using this */
-                               *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
-                       } else {
-                               /* (unless the app isn't using GETCURRENTPOSITION2) */
-                               /* don't know exactly how this should be handled...
-                                * the docs says that play cursor is reported as directly
-                                * behind write cursor, hmm... */
-                               /* let's just do what might work for Half-Life */
-                               DWORD wp;
-                               wp = (This->dsound->device->pwplay + ds_hel_margin) * This->dsound->device->fraglen;
-                               wp %= This->dsound->device->buflen;
-                               *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
-                       }
-                       LeaveCriticalSection(&(This->dsound->device->mixlock));
+               DWORD pos = This->sec_mixpos;
+
+               /* sanity */
+               if (pos >= This->buflen){
+                       FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
+                       pos %= This->buflen;
                }
+
+               if (playpos)
+                       *playpos = pos;
                if (writepos)
-                    *writepos = This->buf_mixpos;
+                       *writepos = pos;
        }
-       if (writepos) {
-               if (This->state != STATE_STOPPED) {
-                       /* apply the documented 10ms lead to writepos */
-                       *writepos += This->writelead;
-               }
+       if (writepos && This->state != STATE_STOPPED && (!This->hwbuf || !(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD))) {
+               /* apply the documented 10ms lead to writepos */
+               *writepos += This->writelead;
                *writepos %= This->buflen;
        }
-       if (playpos)
-            This->last_playpos = *playpos;
-       TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
+       RtlReleaseResource(&This->lock);
+
+       TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
+               playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
+
        return DS_OK;
 }
 
@@ -493,7 +446,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
        LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
 ) {
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-       TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
+       TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
 
        if (status == NULL) {
                WARN("invalid parameter: status = NULL\n");
@@ -501,13 +454,15 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
        }
 
        *status = 0;
+       RtlAcquireResourceShared(&This->lock, TRUE);
        if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
                *status |= DSBSTATUS_PLAYING;
                if (This->playflags & DSBPLAY_LOOPING)
                        *status |= DSBSTATUS_LOOPING;
        }
+       RtlReleaseResource(&This->lock);
 
-       TRACE("status=%lx\n", *status);
+       TRACE("status=%x\n", *status);
        return DS_OK;
 }
 
@@ -520,7 +475,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
 {
     DWORD size;
     IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-    TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
+    TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
 
     size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
 
@@ -531,8 +486,9 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
                 *wfwritten = size;
         } else {
             WARN("invalid parameter: wfsize too small\n");
+            CopyMemory(lpwf,This->pwfx,wfsize);
             if (wfwritten)
-                *wfwritten = 0;
+                *wfwritten = wfsize;
             return DSERR_INVALIDPARAM;
         }
     } else {
@@ -548,12 +504,12 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
 }
 
 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
-       LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
+       LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
 ) {
        HRESULT hres = DS_OK;
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
 
-       TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
+       TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
                This,
                writecursor,
                writebytes,
@@ -565,36 +521,39 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
                GetTickCount()
        );
 
+        if (!audiobytes1)
+            return DSERR_INVALIDPARAM;
+
+        /* when this flag is set, writecursor is meaningless and must be calculated */
        if (flags & DSBLOCK_FROMWRITECURSOR) {
-               DWORD writepos;
                /* GetCurrentPosition does too much magic to duplicate here */
-               hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
+               hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
                if (hres != DS_OK) {
                        WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
                        return hres;
                }
-               writecursor += writepos;
        }
-       writecursor %= This->buflen;
+
+        /* when this flag is set, writebytes is meaningless and must be set */
        if (flags & DSBLOCK_ENTIREBUFFER)
                writebytes = This->buflen;
-       if (writebytes > This->buflen)
-               writebytes = This->buflen;
 
-       EnterCriticalSection(&(This->lock));
+       if (writecursor >= This->buflen) {
+               WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
+                    writecursor, This->buflen);
+               return DSERR_INVALIDPARAM;
+        }
 
-       if ((writebytes == This->buflen) &&
-           ((This->state == STATE_STARTING) ||
-            (This->state == STATE_PLAYING)))
-               /* some games, like Half-Life, try to be clever (not) and
-                * keep one secondary buffer, and mix sounds into it itself,
-                * locking the entire buffer every time... so we can just forget
-                * about tracking the last-written-to-position... */
-               This->probably_valid_to = (DWORD)-1;
-       else
-               This->probably_valid_to = writecursor;
+       if (writebytes > This->buflen) {
+               WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
+                    writebytes, This->buflen);
+               return DSERR_INVALIDPARAM;
+        }
+
+       /* **** */
+       RtlAcquireResourceShared(&This->lock, TRUE);
 
-       if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
+       if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
                hres = IDsDriverBuffer_Lock(This->hwbuf,
                                     lplpaudioptr1, audiobytes1,
                                     lplpaudioptr2, audiobytes2,
@@ -602,50 +561,41 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
                                     0);
                if (hres != DS_OK) {
                        WARN("IDsDriverBuffer_Lock failed\n");
-                       LeaveCriticalSection(&(This->lock));
+                       RtlReleaseResource(&This->lock);
                        return hres;
                }
        } else {
-               BOOL remix = FALSE;
                if (writecursor+writebytes <= This->buflen) {
                        *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
+                       if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 1\n");
                        *audiobytes1 = writebytes;
                        if (lplpaudioptr2)
                                *(LPBYTE*)lplpaudioptr2 = NULL;
                        if (audiobytes2)
                                *audiobytes2 = 0;
-                       TRACE("->%ld.0\n",writebytes);
+                       TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
+                         *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
+                       TRACE("->%d.0\n",writebytes);
                } else {
+                       DWORD remainder = writebytes + writecursor - This->buflen;
                        *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
                        *audiobytes1 = This->buflen-writecursor;
+                       if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 2\n");
                        if (lplpaudioptr2)
                                *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
                        if (audiobytes2)
                                *audiobytes2 = writebytes-(This->buflen-writecursor);
-                       TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
-               }
-               if (This->state == STATE_PLAYING) {
-                       /* if the segment between playpos and buf_mixpos is touched,
-                        * we need to cancel some mixing */
-                       /* we'll assume that the app always calls GetCurrentPosition before
-                        * locking a playing buffer, so that last_playpos is up-to-date */
-                       if (This->buf_mixpos >= This->last_playpos) {
-                               if (This->buf_mixpos > writecursor &&
-                                   This->last_playpos < writecursor+writebytes)
-                                       remix = TRUE;
-                       } else {
-                               if (This->buf_mixpos > writecursor ||
-                                   This->last_playpos < writecursor+writebytes)
-                                       remix = TRUE;
-                       }
-                       if (remix) {
-                               TRACE("locking prebuffered region, ouch\n");
-                               DSOUND_MixCancelAt(This, writecursor);
-                       }
+                       if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
+                               WARN("Overwriting mixing position, case 3\n");
+                       TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
                }
        }
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
+       /* **** */
+
        return DS_OK;
 }
 
@@ -654,20 +604,33 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
 ) {
        HRESULT hres = DS_OK;
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-       TRACE("(%p,%ld)\n",This,newpos);
+       DWORD oldpos;
+       TRACE("(%p,%d)\n",This,newpos);
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
+
+       oldpos = This->sec_mixpos;
 
+       /* start mixing from this new location instead */
        newpos %= This->buflen;
-       This->buf_mixpos = newpos;
+       newpos -= newpos%This->pwfx->nBlockAlign;
+       This->sec_mixpos = newpos;
+
+       /* at this point, do not attempt to reset buffers, mess with primary mix position,
+           or anything like that to reduce latancy. The data already prebuffered cannot be changed */
+
+       /* position HW buffer if applicable, else just start mixing from new location instead */
        if (This->hwbuf) {
                hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
                if (hres != DS_OK)
                        WARN("IDsDriverBuffer_SetPosition failed\n");
        }
+       else if (oldpos != newpos)
+               /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
+               This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return hres;
@@ -679,10 +642,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
        HRESULT hres = DS_OK;
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
 
-       TRACE("(%p,%ld)\n",This,pan);
+       TRACE("(%p,%d)\n",This,pan);
 
        if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
-               WARN("invalid parameter: pan = %ld\n", pan);
+               WARN("invalid parameter: pan = %d\n", pan);
                return DSERR_INVALIDPARAM;
        }
 
@@ -694,7 +657,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
        }
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceExclusive(&This->lock, TRUE);
 
        if (This->volpan.lPan != pan) {
                This->volpan.lPan = pan;
@@ -704,11 +667,10 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
                        hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
                        if (hres != DS_OK)
                                WARN("IDsDriverBuffer_SetVolumePan failed\n");
-               } else
-                       DSOUND_ForceRemix(This);
+               }
        }
 
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
        return hres;
@@ -738,37 +700,46 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
        LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
 ) {
-       IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-       DWORD probably_valid_to;
+       IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface, *iter;
        HRESULT hres = DS_OK;
 
-       TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
+       TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
 
        /* **** */
-       EnterCriticalSection(&(This->lock));
+       RtlAcquireResourceShared(&This->lock, TRUE);
 
-       if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
+       if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
                hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
                if (hres != DS_OK)
                        WARN("IDsDriverBuffer_Unlock failed\n");
        }
 
-        if (hres == DS_OK) {
-               if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
-               else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
-               probably_valid_to %= This->buflen;
-               if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
-                   ((This->state == STATE_STARTING) ||
-                    (This->state == STATE_PLAYING)))
-                       /* see IDirectSoundBufferImpl_Lock */
-                       probably_valid_to = (DWORD)-1;
-               This->probably_valid_to = probably_valid_to;
-       }
-
-       LeaveCriticalSection(&(This->lock));
+       RtlReleaseResource(&This->lock);
        /* **** */
 
-       TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
+       if (!p2)
+               x2 = 0;
+
+       if (!This->hwbuf && (x1 || x2))
+       {
+               RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
+               LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
+               {
+                       RtlAcquireResourceShared(&iter->lock, TRUE);
+                       if (x1)
+                        {
+                           if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
+                             hres = DSERR_INVALIDPARAM;
+                           else
+                             DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
+                        }
+                       if (x2)
+                               DSOUND_MixToTemporary(iter, 0, x2, FALSE);
+                       RtlReleaseResource(&iter->lock);
+               }
+               RtlReleaseResource(&This->device->buffer_list_lock);
+       }
+
        return hres;
 }
 
@@ -792,7 +763,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
        }
 
        *freq = This->freq;
-       TRACE("-> %ld\n", *freq);
+       TRACE("-> %d\n", *freq);
 
        return DS_OK;
 }
@@ -803,7 +774,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
        DWORD u;
 
-       FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
+       FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
 
        if (pdwResultCodes)
                for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
@@ -818,7 +789,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
        DWORD u;
 
-       FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
+       FIXME("(%p,%08u,%u,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
 
        if (pdwResultCodes)
                for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
@@ -832,7 +803,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
 ) {
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
 
-       FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
+       FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
 
        WARN("control unavailable\n");
        return DSERR_CONTROLUNAVAIL;
@@ -842,9 +813,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
        LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
 ) {
        IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-       FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
-       DPRINTF("Re-Init!!!\n");
-       WARN("already initialized\n");
+       WARN("(%p) already initialized\n", This);
        return DSERR_ALREADYINITIALIZED;
 }
 
@@ -860,7 +829,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
        }
 
        if (caps->dwSize < sizeof(*caps)) {
-               WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
+               WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
                return DSERR_INVALIDPARAM;
        }
 
@@ -870,11 +839,8 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
 
        caps->dwBufferBytes = This->buflen;
 
-       /* This value represents the speed of the "unlock" command.
-          As unlock is quite fast (it does not do anything), I put
-          4096 ko/s = 4 Mo / s */
-       /* FIXME: hwbuf speed */
-       caps->dwUnlockTransferRate = 4096;
+       /* According to windows, this is zero*/
+       caps->dwUnlockTransferRate = 0;
        caps->dwPlayCpuOverhead = 0;
 
        return DS_OK;
@@ -897,11 +863,11 @@ static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
        if ( IsEqualGUID(riid, &IID_IUnknown) ||
             IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
             IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
-               if (!This->dsb)
-                       SecondaryBufferImpl_Create(This, &(This->dsb));
-               if (This->dsb) {
-                       IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
-                       *ppobj = This->dsb;
+               if (!This->secondary)
+                       SecondaryBufferImpl_Create(This, &(This->secondary));
+               if (This->secondary) {
+                       IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
+                       *ppobj = This->secondary;
                        return S_OK;
                }
                WARN("IID_IDirectSoundBuffer\n");
@@ -982,8 +948,8 @@ static const IDirectSoundBuffer8Vtbl dsbvt =
        IDirectSoundBufferImpl_GetObjectInPath
 };
 
-HRESULT WINAPI IDirectSoundBufferImpl_Create(
-       IDirectSoundImpl *ds,
+HRESULT IDirectSoundBufferImpl_Create(
+       DirectSoundDevice * device,
        IDirectSoundBufferImpl **pdsb,
        LPCDSBUFFERDESC dsbd)
 {
@@ -992,10 +958,10 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        HRESULT err = DS_OK;
        DWORD capf = 0;
        int use_hw, alloc_size, cp_size;
-       TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
+       TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
 
        if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
-               WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
+               WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
                *pdsb = NULL;
                return DSERR_INVALIDPARAM; /* FIXME: which error? */
        }
@@ -1011,8 +977,8 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        TRACE("Created buffer at %p\n", dsb);
 
        dsb->ref = 0;
-       dsb->dsb = 0;
-       dsb->dsound = ds;
+       dsb->secondary = 0;
+       dsb->device = device;
        dsb->lpVtbl = &dsbvt;
        dsb->iks = NULL;
 
@@ -1023,7 +989,7 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
                alloc_size = sizeof(WAVEFORMATEX);
                cp_size = sizeof(PCMWAVEFORMAT);
-       } else
+       } else 
                alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;
 
        dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
@@ -1037,8 +1003,8 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        CopyMemory(dsb->pwfx, wfex, cp_size);
 
        if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
-               dsb->buflen = dsbd->dwBufferBytes +
-                       (dsbd->lpwfxFormat->nBlockAlign -
+               dsb->buflen = dsbd->dwBufferBytes + 
+                       (dsbd->lpwfxFormat->nBlockAlign - 
                        (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
        else
                dsb->buflen = dsbd->dwBufferBytes;
@@ -1055,8 +1021,19 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
        else capf |= DSCAPS_SECONDARY8BIT;
 
-       use_hw = (ds->device->drvcaps.dwFlags & capf) == capf;
-       TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->device->drvcaps.dwFlags);
+       use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE);
+       TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
+       if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver))
+       {
+               if (device->driver)
+                       WARN("Format not supported for hardware buffer\n");
+               HeapFree(GetProcessHeap(),0,dsb->pwfx);
+               HeapFree(GetProcessHeap(),0,dsb);
+               *pdsb = NULL;
+               if ((device->drvcaps.dwFlags & capf) != capf)
+                       return DSERR_BADFORMAT;
+               return DSERR_GENERIC;
+       }
 
        /* FIXME: check hardware sample rate mixing capabilities */
        /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
@@ -1074,7 +1051,7 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        }
 
        /* Allocate system memory for buffer if applicable */
-       if ((ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
+       if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
                dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
                if (dsb->buffer->memory == NULL) {
                        WARN("out of memory\n");
@@ -1084,50 +1061,43 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
                        *pdsb = NULL;
                        return DSERR_OUTOFMEMORY;
                }
-               dsb->buffer->ref = 1;
-               FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
        }
 
        /* Allocate the hardware buffer */
        if (use_hw) {
-               err = IDsDriver_CreateSoundBuffer(ds->device->driver,wfex,dsbd->dwFlags,0,
+               err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
                                                  &(dsb->buflen),&(dsb->buffer->memory),
                                                  (LPVOID*)&(dsb->hwbuf));
-                /* fall back to software buffer on failure */
-               if (err != DS_OK) {
-                       TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
-                       use_hw = 0;
-                       if (ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
-                               dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
-                               if (dsb->buffer->memory == NULL) {
-                                       WARN("out of memory\n");
-                                       HeapFree(GetProcessHeap(),0,dsb->buffer);
-                                       HeapFree(GetProcessHeap(),0,dsb->pwfx);
-                                       HeapFree(GetProcessHeap(),0,dsb);
-                                       *pdsb = NULL;
-                                       return DSERR_OUTOFMEMORY;
-                               }
-                               dsb->buffer->ref = 1;
-                               FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
-                       }
-                       err = DS_OK;
+               if (FAILED(err))
+               {
+                       WARN("Failed to create hardware secondary buffer: %08x\n", err);
+                       if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
+                               HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
+                       HeapFree(GetProcessHeap(),0,dsb->buffer);
+                       HeapFree(GetProcessHeap(),0,dsb->pwfx);
+                       HeapFree(GetProcessHeap(),0,dsb);
+                       *pdsb = NULL;
+                       return DSERR_GENERIC;
                }
        }
 
-       /* calculate fragment size and write lead */
-       DSOUND_RecalcFormat(dsb);
+       dsb->buffer->ref = 1;
+       list_init(&dsb->buffer->buffers);
+       list_add_head(&dsb->buffer->buffers, &dsb->entry);
+       FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
 
        /* It's not necessary to initialize values to zero since */
        /* we allocated this structure with HEAP_ZERO_MEMORY... */
-       dsb->playpos = 0;
-       dsb->buf_mixpos = 0;
+       dsb->buf_mixpos = dsb->sec_mixpos = 0;
        dsb->state = STATE_STOPPED;
 
-       dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
-               ds->device->pwfx->nSamplesPerSec;
+       dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
        dsb->nAvgBytesPerSec = dsb->freq *
                dsbd->lpwfxFormat->nBlockAlign;
 
+       /* calculate fragment size and write lead */
+       DSOUND_RecalcFormat(dsb);
+
        if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
                dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
                dsb->ds3db_ds3db.vPosition.x = 0.0;
@@ -1151,17 +1121,15 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        } else
                DSOUND_RecalcVolPan(&(dsb->volpan));
 
-       InitializeCriticalSection(&(dsb->lock));
-        dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
+       RtlInitializeResource(&dsb->lock);
 
        /* register buffer if not primary */
        if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
-               err = DSOUND_AddBuffer(ds, dsb);
+               err = DirectSoundDevice_AddBuffer(device, dsb);
                if (err != DS_OK) {
                        HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
                        HeapFree(GetProcessHeap(),0,dsb->buffer);
-                       dsb->lock.DebugInfo->Spare[0] = 0;
-                       DeleteCriticalSection(&(dsb->lock));
+                       RtlDeleteResource(&dsb->lock);
                        HeapFree(GetProcessHeap(),0,dsb->pwfx);
                        HeapFree(GetProcessHeap(),0,dsb);
                        dsb = NULL;
@@ -1172,7 +1140,7 @@ HRESULT WINAPI IDirectSoundBufferImpl_Create(
        return err;
 }
 
-HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
+HRESULT IDirectSoundBufferImpl_Destroy(
     IDirectSoundBufferImpl *pdsb)
 {
     TRACE("(%p)\n",pdsb);
@@ -1199,10 +1167,10 @@ HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
         pdsb->notify = NULL;
     }
 
-    if (pdsb->dsb) {
+    if (pdsb->secondary) {
         WARN("dsb not NULL\n");
-        SecondaryBufferImpl_Destroy(pdsb->dsb);
-        pdsb->dsb = NULL;
+        SecondaryBufferImpl_Destroy(pdsb->secondary);
+        pdsb->secondary = NULL;
     }
 
     while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
@@ -1210,6 +1178,83 @@ HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
     return S_OK;
 }
 
+HRESULT IDirectSoundBufferImpl_Duplicate(
+    DirectSoundDevice *device,
+    IDirectSoundBufferImpl **ppdsb,
+    IDirectSoundBufferImpl *pdsb)
+{
+    IDirectSoundBufferImpl *dsb;
+    HRESULT hres = DS_OK;
+    int size;
+    TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);
+
+    dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
+
+    if (dsb == NULL) {
+        WARN("out of memory\n");
+        *ppdsb = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
+
+    if (pdsb->hwbuf) {
+        TRACE("duplicating hardware buffer\n");
+
+        hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
+                                              (LPVOID *)&dsb->hwbuf);
+        if (FAILED(hres)) {
+            WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres);
+            HeapFree(GetProcessHeap(),0,dsb);
+            *ppdsb = NULL;
+            return hres;
+        }
+    }
+
+    dsb->buffer->ref++;
+    list_add_head(&dsb->buffer->buffers, &dsb->entry);
+    dsb->ref = 0;
+    dsb->state = STATE_STOPPED;
+    dsb->buf_mixpos = dsb->sec_mixpos = 0;
+    dsb->device = device;
+    dsb->ds3db = NULL;
+    dsb->iks = NULL; /* FIXME? */
+    dsb->secondary = NULL;
+    dsb->tmp_buffer = NULL;
+    DSOUND_RecalcFormat(dsb);
+    DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
+
+    /* variable sized struct so calculate size based on format */
+    size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
+
+    dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
+    if (dsb->pwfx == NULL) {
+            WARN("out of memory\n");
+            HeapFree(GetProcessHeap(),0,dsb->buffer);
+            HeapFree(GetProcessHeap(),0,dsb);
+            *ppdsb = NULL;
+            return DSERR_OUTOFMEMORY;
+    }
+
+    CopyMemory(dsb->pwfx, pdsb->pwfx, size);
+
+    RtlInitializeResource(&dsb->lock);
+
+    /* register buffer */
+    hres = DirectSoundDevice_AddBuffer(device, dsb);
+    if (hres != DS_OK) {
+        RtlDeleteResource(&dsb->lock);
+        HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
+        HeapFree(GetProcessHeap(),0,dsb->buffer);
+        HeapFree(GetProcessHeap(),0,dsb->pwfx);
+        HeapFree(GetProcessHeap(),0,dsb);
+        *ppdsb = 0;
+    }
+
+    *ppdsb = dsb;
+    return hres;
+}
+
 /*******************************************************************************
  *             SecondaryBuffer
  */
@@ -1225,20 +1270,22 @@ static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
 
 static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
 {
-    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
 static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
 {
-    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
+    ULONG ref;
+    TRACE("(%p)\n", This);
+    ref = InterlockedDecrement(&(This->ref));
+    TRACE("ref was %d\n", ref + 1);
 
     if (!ref) {
-        This->dsb->dsb = NULL;
+        This->dsb->secondary = NULL;
         IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
         HeapFree(GetProcessHeap(), 0, This);
         TRACE("(%p) released\n", This);
@@ -1268,7 +1315,7 @@ static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
        LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
+       TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
 
        return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
 }
@@ -1322,14 +1369,14 @@ static HRESULT WINAPI SecondaryBufferImpl_Lock(
     LPDIRECTSOUNDBUFFER8 iface,
     DWORD writecursor,
     DWORD writebytes,
-    LPVOID lplpaudioptr1,
+    LPVOID *lplpaudioptr1,
     LPDWORD audiobytes1,
-    LPVOID lplpaudioptr2,
+    LPVOID *lplpaudioptr2,
     LPDWORD audiobytes2,
     DWORD dwFlags)
 {
     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-    TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
+    TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n",
         This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
 
     return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
@@ -1340,7 +1387,7 @@ static HRESULT WINAPI SecondaryBufferImpl_Play(
        LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
+       TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
 
        return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
 }
@@ -1349,7 +1396,7 @@ static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
        LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%ld)\n",This,newpos);
+       TRACE("(%p,%d)\n",This,newpos);
 
        return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
 }
@@ -1367,7 +1414,7 @@ static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
        LPDIRECTSOUNDBUFFER8 iface,LONG vol)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%ld)\n",This,vol);
+       TRACE("(%p,%d)\n",This,vol);
 
        return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
 }
@@ -1376,7 +1423,7 @@ static HRESULT WINAPI SecondaryBufferImpl_SetPan(
        LPDIRECTSOUNDBUFFER8 iface,LONG pan)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%ld)\n",This,pan);
+       TRACE("(%p,%d)\n",This,pan);
 
        return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
 }
@@ -1385,7 +1432,7 @@ static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
        LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%ld)\n",This,freq);
+       TRACE("(%p,%d)\n",This,freq);
 
        return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
 }
@@ -1406,7 +1453,7 @@ static HRESULT WINAPI SecondaryBufferImpl_Unlock(
     DWORD dwAudioBytes2)
 {
     SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-    TRACE("(%p,%p,%ld,%p,%ld)\n",
+    TRACE("(%p,%p,%d,%p,%d)\n",
         This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
 
     return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
@@ -1426,7 +1473,7 @@ static HRESULT WINAPI SecondaryBufferImpl_SetFX(
        LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
+       TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
 
        return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
 }
@@ -1435,7 +1482,7 @@ static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
        LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
+       TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
 
        return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
 }
@@ -1444,7 +1491,7 @@ static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
        LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
 {
        SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
-       TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
+       TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
 
        return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
 }
@@ -1477,7 +1524,7 @@ static const IDirectSoundBuffer8Vtbl sbvt =
        SecondaryBufferImpl_GetObjectInPath
 };
 
-HRESULT WINAPI SecondaryBufferImpl_Create(
+HRESULT SecondaryBufferImpl_Create(
        IDirectSoundBufferImpl *dsb,
        SecondaryBufferImpl **psb)
 {
@@ -1500,7 +1547,7 @@ HRESULT WINAPI SecondaryBufferImpl_Create(
        return S_OK;
 }
 
-HRESULT WINAPI SecondaryBufferImpl_Destroy(
+static HRESULT SecondaryBufferImpl_Destroy(
     SecondaryBufferImpl *pdsb)
 {
     TRACE("(%p)\n",pdsb);
index 35dbeff..2a8252f 100644 (file)
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 /*
  * TODO:
@@ -31,9 +31,9 @@
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "mmsystem.h"
 #include "mmddk.h"
-#include "winreg.h"
 #include "winternl.h"
 #include "winnls.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
-    LPDIRECTSOUNDCAPTURE iface,
-    LPCGUID lpcGUID );
-static ULONG WINAPI IDirectSoundCaptureImpl_Release(
-    LPDIRECTSOUNDCAPTURE iface );
-static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release(
-    LPDIRECTSOUNDCAPTUREBUFFER8 iface );
-static HRESULT DSOUND_CreateDirectSoundCaptureBuffer(
-    IDirectSoundCaptureImpl *ipDSC,
-    LPCDSCBUFFERDESC lpcDSCBufferDesc,
-    LPVOID* ppobj );
+/*****************************************************************************
+ * IDirectSoundCapture implementation structure
+ */
+struct IDirectSoundCaptureImpl
+{
+    /* IUnknown fields */
+    const IDirectSoundCaptureVtbl     *lpVtbl;
+    LONG                               ref;
 
-static const IDirectSoundCaptureVtbl dscvt;
-static const IDirectSoundCaptureBuffer8Vtbl dscbvt;
+    DirectSoundCaptureDevice          *device;
+};
 
-DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
+static HRESULT IDirectSoundCaptureImpl_Create(LPDIRECTSOUNDCAPTURE8 * ppds);
 
-static const char * captureStateString[] = {
-    "STATE_STOPPED",
-    "STATE_STARTING",
-    "STATE_CAPTURING",
-    "STATE_STOPPING"
-};
 
-HRESULT WINAPI IDirectSoundCaptureImpl_Create(
-    LPDIRECTSOUNDCAPTURE8 * ppDSC)
+/*****************************************************************************
+ * IDirectSoundCaptureNotify implementation structure
+ */
+struct IDirectSoundCaptureNotifyImpl
 {
-    IDirectSoundCaptureImpl *pDSC;
-    TRACE("(%p)\n", ppDSC);
+    /* IUnknown fields */
+    const IDirectSoundNotifyVtbl       *lpVtbl;
+    LONG                                ref;
+    IDirectSoundCaptureBufferImpl*      dscb;
+};
 
-    /* Allocate memory */
-    pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
-    if (pDSC == NULL) {
-        WARN("out of memory\n");
-        *ppDSC = NULL;
-        return DSERR_OUTOFMEMORY;
-    }
+static HRESULT IDirectSoundCaptureNotifyImpl_Create(IDirectSoundCaptureBufferImpl *dscb,
+                                                    IDirectSoundCaptureNotifyImpl ** pdscn);
 
-    pDSC->lpVtbl = &dscvt;
-    pDSC->ref    = 0;
-    pDSC->device = NULL;
 
-    *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
+DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
 
-    return DS_OK;
-}
+static HRESULT DirectSoundCaptureDevice_Create(DirectSoundCaptureDevice ** ppDevice);
 
-HRESULT WINAPI DSOUND_CaptureCreate(
-    LPDIRECTSOUNDCAPTURE *ppDSC,
-    IUnknown *pUnkOuter)
+static const char * const captureStateString[] = {
+    "STATE_STOPPED",
+    "STATE_STARTING",
+    "STATE_CAPTURING",
+    "STATE_STOPPING"
+};
+
+HRESULT DSOUND_CaptureCreate(
+    REFIID riid,
+    LPDIRECTSOUNDCAPTURE *ppDSC)
 {
     LPDIRECTSOUNDCAPTURE pDSC;
     HRESULT hr;
-    TRACE("(%p,%p)\n",ppDSC,pUnkOuter);
+    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();
@@ -113,13 +113,19 @@ HRESULT WINAPI DSOUND_CaptureCreate(
     return hr;
 }
 
-HRESULT WINAPI DSOUND_CaptureCreate8(
-    LPDIRECTSOUNDCAPTURE8 *ppDSC8,
-    IUnknown *pUnkOuter)
+HRESULT DSOUND_CaptureCreate8(
+    REFIID riid,
+    LPDIRECTSOUNDCAPTURE8 *ppDSC8)
 {
     LPDIRECTSOUNDCAPTURE8 pDSC8;
     HRESULT hr;
-    TRACE("(%p,%p)\n",ppDSC8,pUnkOuter);
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSC8);
+
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSoundCapture8)) {
+        *ppDSC8 = 0;
+        return E_NOINTERFACE;
+    }
 
     /* Get dsound configuration */
     setup_dsound_options();
@@ -178,7 +184,7 @@ HRESULT WINAPI DirectSoundCaptureCreate(
         return DSERR_NOAGGREGATION;
     }
 
-    hr = DSOUND_CaptureCreate(&pDSC, (IUnknown *)pUnkOuter);
+    hr = DSOUND_CaptureCreate(&IID_IDirectSoundCapture, &pDSC);
     if (hr == DS_OK) {
         hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID);
         if (hr != DS_OK) {
@@ -234,7 +240,7 @@ HRESULT WINAPI DirectSoundCaptureCreate8(
         return DSERR_NOAGGREGATION;
     }
 
-    hr = DSOUND_CaptureCreate8(&pDSC8, (IUnknown *)pUnkOuter);
+    hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &pDSC8);
     if (hr == DS_OK) {
         hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID);
         if (hr != DS_OK) {
@@ -248,31 +254,6 @@ HRESULT WINAPI DirectSoundCaptureCreate8(
     return hr;
 }
 
-static HRESULT DirectSoundCaptureDevice_Create(
-    DirectSoundCaptureDevice ** ppDevice)
-{
-    DirectSoundCaptureDevice * device;
-    TRACE("(%p)\n", ppDevice);
-
-    /* Allocate memory */
-    device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
-
-    if (device == NULL) {
-       WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    device->ref = 1;
-    device->state = STATE_STOPPED;
-
-    InitializeCriticalSection( &(device->lock) );
-    device->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSCAPTURE_lock";
-
-    *ppDevice = device;
-
-    return DS_OK;
-}
-
 /***************************************************************************
  * DirectSoundCaptureEnumerateA [DSOUND.7]
  *
@@ -308,7 +289,7 @@ DirectSoundCaptureEnumerateA(
        if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
            for (wid = 0; wid < devs; ++wid) {
                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
-                    err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+                    err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
                     if (err == DS_OK) {
                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
@@ -321,7 +302,7 @@ DirectSoundCaptureEnumerateA(
     }
 
     for (wid = 0; wid < devs; ++wid) {
-       err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+        err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
        if (err == DS_OK) {
             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
@@ -370,7 +351,7 @@ DirectSoundCaptureEnumerateW(
        if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) {
            for (wid = 0; wid < devs; ++wid) {
                 if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) {
-                    err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+                    err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
                     if (err == DS_OK) {
                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
                               "Primary Sound Capture Driver",desc.szDrvname,lpContext);
@@ -387,7 +368,7 @@ DirectSoundCaptureEnumerateW(
     }
 
     for (wid = 0; wid < devs; ++wid) {
-       err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+        err = mmErr(waveInMessage(UlongToHandle(wid),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
        if (err == DS_OK) {
             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
                   debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext);
@@ -395,7 +376,7 @@ DirectSoundCaptureEnumerateW(
                                  wDesc, sizeof(wDesc)/sizeof(WCHAR) );
             MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
                                  wName, sizeof(wName)/sizeof(WCHAR) );
-            if (lpDSEnumCallback((LPGUID)&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
+            if (lpDSEnumCallback(&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE)
                 return DS_OK;
        }
     }
@@ -403,38 +384,59 @@ DirectSoundCaptureEnumerateW(
     return DS_OK;
 }
 
+static void capture_CheckNotify(IDirectSoundCaptureBufferImpl *This, DWORD from, DWORD len)
+{
+    int i;
+    for (i = 0; i < This->nrofnotifies; ++i) {
+        LPDSBPOSITIONNOTIFY event = This->notifies + i;
+        DWORD offset = event->dwOffset;
+        TRACE("checking %d, position %d, event = %p\n", i, offset, event->hEventNotify);
+
+        if (offset == DSBPN_OFFSETSTOP) {
+            if (!from && !len) {
+                SetEvent(event->hEventNotify);
+                TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
+                return;
+            }
+            else return;
+        }
+
+        if (offset >= from && offset < (from + len))
+        {
+            TRACE("signalled event %p (%d)\n", event->hEventNotify, i);
+            SetEvent(event->hEventNotify);
+        }
+    }
+}
+
 static void CALLBACK
-DSOUND_capture_callback(
-    HWAVEIN hwi,
-    UINT msg,
-    DWORD dwUser,
-    DWORD dw1,
-    DWORD dw2 )
+DSOUND_capture_callback(HWAVEIN hwi, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1,
+                        DWORD_PTR dw2)
 {
     DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser;
-    TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg,
+    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) {
-        LPWAVEHDR pHdr = (LPWAVEHDR)dw1;
        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->read_position = pHdr->dwBytesRecorded;
+           if (This->state == STATE_STARTING)
                This->state = STATE_CAPTURING;
-           }
-           if (This->capture_buffer->nrofnotifies)
-               SetEvent(This->capture_buffer->notifies[This->index].hEventNotify);
-           This->index = (This->index + 1) % This->nrofpwaves;
+           capture_CheckNotify(Moi, (DWORD_PTR)This->pwave[index].lpData - (DWORD_PTR)This->buffer, This->pwave[index].dwBufferLength);
+           This->index = (++This->index) % 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");
@@ -450,6 +452,9 @@ DSOUND_capture_callback(
     TRACE("completed\n");
 }
 
+/***************************************************************************
+ * IDirectSoundCaptureImpl
+ */
 static HRESULT WINAPI
 IDirectSoundCaptureImpl_QueryInterface(
     LPDIRECTSOUNDCAPTURE iface,
@@ -485,36 +490,7 @@ IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface )
 {
     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
-
-static ULONG DirectSoundCaptureDevice_Release(
-    DirectSoundCaptureDevice * device)
-{
-    ULONG ref;
-    TRACE("(%p) ref was %lu\n", device, device->ref);
-
-    device->ref--;
-    ref=device->ref;
-    if (device->ref == 0) {
-        TRACE("deleting object\n");
-        if (device->capture_buffer)
-            IDirectSoundCaptureBufferImpl_Release(
-               (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
-
-        if (device->driver) {
-            IDsCaptureDriver_Close(device->driver);
-            IDsCaptureDriver_Release(device->driver);
-        }
-
-        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);
-    }
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -523,20 +499,19 @@ IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface )
 {
     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
         if (This->device)
             DirectSoundCaptureDevice_Release(This->device);
 
         HeapFree( GetProcessHeap(), 0, This );
-       TRACE("(%p) released\n", This);
+        TRACE("(%p) released\n", This);
     }
     return ref;
 }
 
-static HRESULT WINAPI
-IDirectSoundCaptureImpl_CreateCaptureBuffer(
+HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
     LPDIRECTSOUNDCAPTURE iface,
     LPCDSCBUFFERDESC lpcDSCBufferDesc,
     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
@@ -547,11 +522,6 @@ IDirectSoundCaptureImpl_CreateCaptureBuffer(
 
     TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
 
-    if (This == NULL) {
-       WARN("invalid parameter: This == NULL\n");
-       return DSERR_INVALIDPARAM;
-    }
-
     if (lpcDSCBufferDesc == NULL) {
        WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n");
        return DSERR_INVALIDPARAM;
@@ -573,17 +543,16 @@ IDirectSoundCaptureImpl_CreateCaptureBuffer(
        return DSERR_INVALIDPARAM;    /* DSERR_GENERIC ? */
     }
 
-    hr = DSOUND_CreateDirectSoundCaptureBuffer(This, lpcDSCBufferDesc,
-        (LPVOID*)lplpDSCaptureBuffer );
+    hr = IDirectSoundCaptureBufferImpl_Create(This->device,
+        (IDirectSoundCaptureBufferImpl **)lplpDSCaptureBuffer, lpcDSCBufferDesc);
 
     if (hr != DS_OK)
-       WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n");
+       WARN("IDirectSoundCaptureBufferImpl_Create failed\n");
 
     return hr;
 }
 
-static HRESULT WINAPI
-IDirectSoundCaptureImpl_GetCaps(
+HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
     LPDIRECTSOUNDCAPTURE iface,
     LPDSCCAPS lpDSCCaps )
 {
@@ -601,8 +570,7 @@ IDirectSoundCaptureImpl_GetCaps(
     }
 
     if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) {
-       WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n",
-           lpDSCCaps->dwSize, sizeof(*lpDSCCaps));
+       WARN("invalid parameter: lpDSCCaps->dwSize = %d\n", lpDSCCaps->dwSize);
        return DSERR_INVALIDPARAM;
     }
 
@@ -610,137 +578,24 @@ IDirectSoundCaptureImpl_GetCaps(
     lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats;
     lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels;
 
-    TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags,
+    TRACE("(flags=0x%08x,format=0x%08x,channels=%d)\n",lpDSCCaps->dwFlags,
         lpDSCCaps->dwFormats, lpDSCCaps->dwChannels);
 
     return DS_OK;
 }
 
-static HRESULT WINAPI
-IDirectSoundCaptureImpl_Initialize(
+HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
     LPDIRECTSOUNDCAPTURE iface,
     LPCGUID lpcGUID )
 {
-    HRESULT err = DSERR_INVALIDPARAM;
-    unsigned wid, widn;
-    BOOLEAN found = FALSE;
-    GUID devGUID;
     IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface;
-    DirectSoundCaptureDevice *device = This->device;
-    TRACE("(%p)\n", This);
-
-    if (!This) {
-       WARN("invalid parameter: This == NULL\n");
-       return DSERR_INVALIDPARAM;
-    }
+    TRACE("(%p,%s)\n", This, debugstr_guid(lpcGUID));
 
-    if (device != NULL) {
+    if (This->device != NULL) {
        WARN("already initialized\n");
        return DSERR_ALREADYINITIALIZED;
     }
-
-    /* Default device? */
-    if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
-       lpcGUID = &DSDEVID_DefaultCapture;
-
-    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
-        WARN("invalid parameter: lpcGUID\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    widn = waveInGetNumDevs();
-    if (!widn) {
-       WARN("no audio devices found\n");
-       return DSERR_NODRIVER;
-    }
-
-    /* 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;
-       }
-    }
-
-    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;
-    }
-
-    err = DirectSoundCaptureDevice_Create(&(device));
-    if (err != DS_OK) {
-        WARN("DirectSoundCaptureDevice_Create failed\n");
-        return err;
-    }
-
-    This->device = device;
-    device->guid = devGUID;
-
-    err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&(This->device->driver),0));
-    if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) {
-       WARN("WineWaveInMessage failed; err=%lx\n",err);
-       return err;
-    }
-    err = DS_OK;
-
-    /* Disable the direct sound driver to force emulation if requested. */
-    if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
-       This->device->driver = NULL;
-
-    /* Get driver description */
-    if (This->device->driver) {
-        TRACE("using DirectSound driver\n");
-        err = IDsCaptureDriver_GetDriverDesc(This->device->driver, &(This->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 */
-        This->device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN |
-            DSDDESC_DOMMSYSTEMSETFORMAT;
-    }
-
-    This->device->drvdesc.dnDevNode = wid;
-
-    /* open the DirectSound driver if available */
-    if (This->device->driver && (err == DS_OK))
-        err = IDsCaptureDriver_Open(This->device->driver);
-
-    if (err == DS_OK) {
-        This->device = device;
-
-        /* the driver is now open, so it's now allowed to call GetCaps */
-        if (This->device->driver) {
-           This->device->drvcaps.dwSize = sizeof(This->device->drvcaps);
-            err = IDsCaptureDriver_GetCaps(This->device->driver,&(This->device->drvcaps));
-           if (err != DS_OK) {
-               WARN("IDsCaptureDriver_GetCaps failed\n");
-               return err;
-           }
-        } else /*if (This->hwi)*/ {
-            WAVEINCAPSA    wic;
-            err = mmErr(waveInGetDevCapsA((UINT)This->device->drvdesc.dnDevNode, &wic, sizeof(wic)));
-
-            if (err == DS_OK) {
-                This->device->drvcaps.dwFlags = 0;
-                lstrcpynA(This->device->drvdesc.szDrvname, wic.szPname,
-                          sizeof(This->device->drvdesc.szDrvname));
-
-                This->device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER;
-                This->device->drvcaps.dwFormats = wic.dwFormats;
-                This->device->drvcaps.dwChannels = wic.wChannels;
-            }
-        }
-    }
-
-    return err;
+    return DirectSoundCaptureDevice_Initialize(&This->device, lpcGUID);
 }
 
 static const IDirectSoundCaptureVtbl dscvt =
@@ -756,200 +611,53 @@ static const IDirectSoundCaptureVtbl dscvt =
     IDirectSoundCaptureImpl_Initialize
 };
 
-static HRESULT
-DSOUND_CreateDirectSoundCaptureBuffer(
-    IDirectSoundCaptureImpl *ipDSC,
-    LPCDSCBUFFERDESC lpcDSCBufferDesc,
-    LPVOID* ppobj )
+static HRESULT IDirectSoundCaptureImpl_Create(
+    LPDIRECTSOUNDCAPTURE8 * ppDSC)
 {
-    LPWAVEFORMATEX  wfex;
-    TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj );
+    IDirectSoundCaptureImpl *pDSC;
+    TRACE("(%p)\n", ppDSC);
 
-    if (ipDSC == NULL) {
-       WARN("invalid parameter: ipDSC == NULL\n");
-       return DSERR_INVALIDPARAM;
+    /* Allocate memory */
+    pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl));
+    if (pDSC == NULL) {
+        WARN("out of memory\n");
+        *ppDSC = NULL;
+        return DSERR_OUTOFMEMORY;
     }
 
-    if (lpcDSCBufferDesc == NULL) {
-       WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
-       return DSERR_INVALIDPARAM;
-    }
+    pDSC->lpVtbl = &dscvt;
+    pDSC->ref    = 0;
+    pDSC->device = NULL;
 
-    if (ppobj == NULL) {
-       WARN("invalid parameter: ppobj == NULL\n");
-       return DSERR_INVALIDPARAM;
-    }
+    *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC;
 
-    if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
-          (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
-        (lpcDSCBufferDesc->dwBufferBytes == 0) ||
-        (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
-       WARN("invalid lpcDSCBufferDesc\n");
-       *ppobj = NULL;
-       return DSERR_INVALIDPARAM;
-    }
+    return DS_OK;
+}
 
-    if ( !ipDSC->device) {
-       WARN("not initialized\n");
-       *ppobj = NULL;
-       return DSERR_UNINITIALIZED;
+/*******************************************************************************
+ *             IDirectSoundCaptureNotify
+ */
+static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
+    LPDIRECTSOUNDNOTIFY iface,
+    REFIID riid,
+    LPVOID *ppobj)
+{
+    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+
+    if (This->dscb == NULL) {
+       WARN("invalid parameter\n");
+       return E_INVALIDARG;
     }
 
-    wfex = lpcDSCBufferDesc->lpwfxFormat;
-
-    if (wfex) {
-        TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
-            "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
-            wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
-            wfex->nAvgBytesPerSec, wfex->nBlockAlign,
-            wfex->wBitsPerSample, wfex->cbSize);
-
-        if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
-           ipDSC->device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
-            CopyMemory(ipDSC->device->pwfx, wfex, sizeof(WAVEFORMATEX));
-           ipDSC->device->pwfx->cbSize = 0;
-       } else {
-           ipDSC->device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
-            CopyMemory(ipDSC->device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
-        }
-    } else {
-       WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
-       *ppobj = NULL;
-       return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
-    }
-
-    *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
-        sizeof(IDirectSoundCaptureBufferImpl));
-
-    if ( *ppobj == NULL ) {
-       WARN("out of memory\n");
-       *ppobj = NULL;
-       return DSERR_OUTOFMEMORY;
-    } else {
-       HRESULT err = DS_OK;
-        LPBYTE newbuf;
-        DWORD buflen;
-        IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj;
-
-        This->ref = 1;
-        This->dsound = ipDSC;
-        This->dsound->device->capture_buffer = This;
-       This->notify = NULL;
-       This->nrofnotifies = 0;
-       This->hwnotify = NULL;
-
-        This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
-            lpcDSCBufferDesc->dwSize);
-        if (This->pdscbd)
-            CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
-        else {
-            WARN("no memory\n");
-            This->dsound->device->capture_buffer = 0;
-            HeapFree( GetProcessHeap(), 0, This );
-            *ppobj = NULL;
-            return DSERR_OUTOFMEMORY;
-        }
-
-        This->lpVtbl = &dscbvt;
-
-       if (ipDSC->device->driver) {
-            if (This->dsound->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
-                FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n");
-
-            if (This->dsound->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
-                /* allocate buffer from system memory */
-                buflen = lpcDSCBufferDesc->dwBufferBytes;
-                TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->device->buffer);
-                if (ipDSC->device->buffer)
-                    newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->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 {
-                    ipDSC->device->buffer = newbuf;
-                    ipDSC->device->buflen = buflen;
-                }
-            } else {
-                /* let driver allocate memory */
-                ipDSC->device->buflen = lpcDSCBufferDesc->dwBufferBytes;
-                /* FIXME: */
-                HeapFree( GetProcessHeap(), 0, ipDSC->device->buffer);
-                ipDSC->device->buffer = NULL;
-            }
-
-           err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->device->driver,
-               ipDSC->device->pwfx,0,0,&(ipDSC->device->buflen),&(ipDSC->device->buffer),(LPVOID*)&(ipDSC->device->hwbuf));
-           if (err != DS_OK) {
-               WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n");
-               This->dsound->device->capture_buffer = 0;
-               HeapFree( GetProcessHeap(), 0, This );
-               *ppobj = NULL;
-               return err;
-           }
-       } else {
-           DWORD flags = CALLBACK_FUNCTION;
-           if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
-               flags |= WAVE_DIRECTSOUND;
-            err = mmErr(waveInOpen(&(ipDSC->device->hwi),
-                ipDSC->device->drvdesc.dnDevNode, ipDSC->device->pwfx,
-                (DWORD_PTR)DSOUND_capture_callback, (DWORD)ipDSC->device, flags));
-            if (err != DS_OK) {
-                WARN("waveInOpen failed\n");
-               This->dsound->device->capture_buffer = 0;
-               HeapFree( GetProcessHeap(), 0, This );
-               *ppobj = NULL;
-               return err;
-            }
-
-           buflen = lpcDSCBufferDesc->dwBufferBytes;
-            TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->device->buffer);
-           if (ipDSC->device->buffer)
-                newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->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 {
-                ipDSC->device->buffer = newbuf;
-                ipDSC->device->buflen = buflen;
-            }
-       }
-    }
-
-    TRACE("returning DS_OK\n");
-    return DS_OK;
-}
-
-/*******************************************************************************
- *             IDirectSoundCaptureNotify
- */
-static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface(
-    LPDIRECTSOUNDNOTIFY iface,
-    REFIID riid,
-    LPVOID *ppobj)
-{
-    IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-
-    if (This->dscb == NULL) {
-       WARN("invalid parameter\n");
-       return E_INVALIDARG;
-    }
-
-    return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
-}
+    return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj);
+}
 
 static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
 {
     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -957,7 +665,7 @@ static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY if
 {
     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
         if (This->dscb->hwnotify)
@@ -976,7 +684,7 @@ static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
     LPCDSBPOSITIONNOTIFY notify)
 {
     IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface;
-    TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
+    TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
 
     if (howmuch > 0 && notify == NULL) {
        WARN("invalid parameter: notify == NULL\n");
@@ -986,7 +694,7 @@ static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions(
     if (TRACE_ON(dsound)) {
        unsigned int i;
        for (i=0;i<howmuch;i++)
-           TRACE("notify at %ld to %p\n",
+            TRACE("notify at %d to %p\n",
            notify[i].dwOffset,notify[i].hEventNotify);
     }
 
@@ -1029,14 +737,14 @@ static const IDirectSoundNotifyVtbl dscnvt =
     IDirectSoundCaptureNotifyImpl_SetNotificationPositions,
 };
 
-HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
+static HRESULT IDirectSoundCaptureNotifyImpl_Create(
     IDirectSoundCaptureBufferImpl *dscb,
     IDirectSoundCaptureNotifyImpl **pdscn)
 {
     IDirectSoundCaptureNotifyImpl * dscn;
     TRACE("(%p,%p)\n",dscb,pdscn);
 
-    dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn));
+    dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dscn));
 
     if (dscn == NULL) {
        WARN("out of memory\n");
@@ -1077,18 +785,19 @@ IDirectSoundCaptureBufferImpl_QueryInterface(
        if (!This->notify)
            hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify);
        if (This->notify) {
-           if (This->dsound->device->hwbuf) {
-               hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->device->hwbuf,
+           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;
                }
            }
 
-           IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
-           *ppobj = (LPVOID)This->notify;
+            *ppobj = This->notify;
            return DS_OK;
        }
 
@@ -1112,7 +821,7 @@ IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -1121,35 +830,38 @@ IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
         TRACE("deleting object\n");
-       if (This->dsound->device->state == STATE_CAPTURING)
-           This->dsound->device->state = STATE_STOPPING;
+       if (This->device->state == STATE_CAPTURING)
+           This->device->state = STATE_STOPPING;
 
         HeapFree(GetProcessHeap(),0, This->pdscbd);
 
-       if (This->dsound->device->hwi) {
-           waveInReset(This->dsound->device->hwi);
-           waveInClose(This->dsound->device->hwi);
-            HeapFree(GetProcessHeap(),0, This->dsound->device->pwave);
-            This->dsound->device->pwave = 0;
-           This->dsound->device->hwi = 0;
+       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->dsound->device->hwbuf)
-           IDsCaptureDriverBuffer_Release(This->dsound->device->hwbuf);
+       if (This->device->hwbuf)
+           IDsCaptureDriverBuffer_Release(This->device->hwbuf);
 
-        /* remove from IDirectSoundCaptureImpl */
-        if (This->dsound)
-            This->dsound->device->capture_buffer = NULL;
-        else
-            ERR("does not reference dsound\n");
+        /* 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);
@@ -1165,24 +877,18 @@ IDirectSoundCaptureBufferImpl_GetCaps(
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p,%p)\n", This, lpDSCBCaps );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
     if (lpDSCBCaps == NULL) {
         WARN("invalid parameter: lpDSCBCaps == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
     if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) {
-        WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n",
-           lpDSCBCaps->dwSize, sizeof(DSCBCAPS));
+        WARN("invalid parameter: lpDSCBCaps->dwSize = %d\n", lpDSCBCaps->dwSize);
         return DSERR_INVALIDPARAM;
     }
 
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
@@ -1205,51 +911,33 @@ IDirectSoundCaptureBufferImpl_GetCurrentPosition(
     HRESULT hres = DS_OK;
     TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (This->dsound->device->driver) {
-        hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_GetPosition(This->device->hwbuf, lpdwCapturePosition, lpdwReadPosition );
        if (hres != DS_OK)
            WARN("IDsCaptureDriverBuffer_GetPosition failed\n");
-    } else if (This->dsound->device->hwi) {
-       EnterCriticalSection(&(This->dsound->device->lock));
-       TRACE("old This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]);
-        if (lpdwCapturePosition) {
-            MMTIME mtime;
-            mtime.wType = TIME_BYTES;
-            waveInGetPosition(This->dsound->device->hwi, &mtime, sizeof(mtime));
-           TRACE("mtime.u.cb=%ld,This->dsound->device->buflen=%ld\n", mtime.u.cb,
-               This->dsound->device->buflen);
-           mtime.u.cb = mtime.u.cb % This->dsound->device->buflen;
-            *lpdwCapturePosition = mtime.u.cb;
-        }
+    } else if (This->device->hwi) {
+        DWORD pos;
+
+        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);
 
-       if (lpdwReadPosition) {
-            if (This->dsound->device->state == STATE_STARTING) {
-               if (lpdwCapturePosition)
-                   This->dsound->device->read_position = *lpdwCapturePosition;
-                This->dsound->device->state = STATE_CAPTURING;
-            }
-            *lpdwReadPosition = This->dsound->device->read_position;
-        }
-       TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]);
-       LeaveCriticalSection(&(This->dsound->device->lock));
-       if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition);
-       if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition);
     } else {
         WARN("no driver\n");
         hres = DSERR_NODRIVER;
     }
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("cappos=%d readpos=%d\n", (lpdwCapturePosition?*lpdwCapturePosition:-1), (lpdwReadPosition?*lpdwReadPosition:-1));
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1262,36 +950,31 @@ IDirectSoundCaptureBufferImpl_GetFormat(
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     HRESULT hres = DS_OK;
-    TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated,
+    TRACE( "(%p,%p,0x%08x,%p)\n", This, lpwfxFormat, dwSizeAllocated,
         lpdwSizeWritten );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize))
-        dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize;
+    if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize))
+        dwSizeAllocated = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
 
     if (lpwfxFormat) { /* NULL is valid (just want size) */
-        CopyMemory(lpwfxFormat, This->dsound->device->pwfx, dwSizeAllocated);
+        CopyMemory(lpwfxFormat, This->device->pwfx, dwSizeAllocated);
         if (lpdwSizeWritten)
             *lpdwSizeWritten = dwSizeAllocated;
     } else {
         if (lpdwSizeWritten)
-            *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize;
+            *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->device->pwfx->cbSize;
         else {
             TRACE("invalid parameter: lpdwSizeWritten = NULL\n");
             hres = DSERR_INVALIDPARAM;
         }
     }
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1301,15 +984,10 @@ IDirectSoundCaptureBufferImpl_GetStatus(
     LPDWORD lpdwStatus )
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
-    TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() );
-
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    TRACE( "(%p, %p), thread is %04x\n", This, lpdwStatus, GetCurrentThreadId() );
 
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
@@ -1319,21 +997,21 @@ IDirectSoundCaptureBufferImpl_GetStatus(
     }
 
     *lpdwStatus = 0;
-    EnterCriticalSection(&(This->dsound->device->lock));
+    EnterCriticalSection(&(This->device->lock));
 
-    TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n",
-       captureStateString[This->dsound->device->state],*lpdwStatus);
-    if ((This->dsound->device->state == STATE_STARTING) ||
-        (This->dsound->device->state == STATE_CAPTURING)) {
+    TRACE("old This->device->state=%s, old lpdwStatus=%08x\n",
+       captureStateString[This->device->state],*lpdwStatus);
+    if ((This->device->state == STATE_STARTING) ||
+        (This->device->state == STATE_CAPTURING)) {
         *lpdwStatus |= DSCBSTATUS_CAPTURING;
         if (This->flags & DSCBSTART_LOOPING)
             *lpdwStatus |= DSCBSTATUS_LOOPING;
     }
-    TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n",
-       captureStateString[This->dsound->device->state],*lpdwStatus);
-    LeaveCriticalSection(&(This->dsound->device->lock));
+    TRACE("new This->device->state=%s, new lpdwStatus=%08x\n",
+       captureStateString[This->device->state],*lpdwStatus);
+    LeaveCriticalSection(&(This->device->lock));
 
-    TRACE("status=%lx\n", *lpdwStatus);
+    TRACE("status=%x\n", *lpdwStatus);
     TRACE("returning DS_OK\n");
     return DS_OK;
 }
@@ -1364,17 +1042,12 @@ IDirectSoundCaptureBufferImpl_Lock(
 {
     HRESULT hres = DS_OK;
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
-    TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor,
+    TRACE( "(%p,%08u,%08u,%p,%p,%p,%p,0x%08x) at %d\n", This, dwReadCusor,
         dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2,
         lpdwAudioBytes2, dwFlags, GetTickCount() );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
@@ -1388,21 +1061,21 @@ IDirectSoundCaptureBufferImpl_Lock(
         return DSERR_INVALIDPARAM;
     }
 
-    EnterCriticalSection(&(This->dsound->device->lock));
+    EnterCriticalSection(&(This->device->lock));
 
-    if (This->dsound->device->driver) {
-        hres = IDsCaptureDriverBuffer_Lock(This->dsound->device->hwbuf, lplpvAudioPtr1,
+    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->dsound->device->hwi) {
-        *lplpvAudioPtr1 = This->dsound->device->buffer + dwReadCusor;
-        if ( (dwReadCusor + dwReadBytes) > This->dsound->device->buflen) {
-            *lpdwAudioBytes1 = This->dsound->device->buflen - dwReadCusor;
+    } else if (This->device->hwi) {
+        *lplpvAudioPtr1 = This->device->buffer + dwReadCusor;
+        if ( (dwReadCusor + dwReadBytes) > This->device->buflen) {
+            *lpdwAudioBytes1 = This->device->buflen - dwReadCusor;
            if (lplpvAudioPtr2)
-               *lplpvAudioPtr2 = This->dsound->device->buffer;
+               *lplpvAudioPtr2 = This->device->buffer;
            if (lpdwAudioBytes2)
                *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1;
         } else {
@@ -1417,9 +1090,9 @@ IDirectSoundCaptureBufferImpl_Lock(
         hres = DSERR_INVALIDCALL;   /* DSERR_NODRIVER ? */
     }
 
-    LeaveCriticalSection(&(This->dsound->device->lock));
+    LeaveCriticalSection(&(This->device->lock));
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1430,155 +1103,99 @@ IDirectSoundCaptureBufferImpl_Start(
 {
     HRESULT hres = DS_OK;
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
-    TRACE( "(%p,0x%08lx)\n", This, dwFlags );
-
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    TRACE( "(%p,0x%08x)\n", This, dwFlags );
 
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if ( (This->dsound->device->driver == 0) && (This->dsound->device->hwi == 0) ) {
+    if ( (This->device->driver == 0) && (This->device->hwi == 0) ) {
         WARN("no driver\n");
         return DSERR_NODRIVER;
     }
 
-    EnterCriticalSection(&(This->dsound->device->lock));
+    EnterCriticalSection(&(This->device->lock));
 
     This->flags = dwFlags;
-    TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->device->state]);
-    if (This->dsound->device->state == STATE_STOPPED)
-        This->dsound->device->state = STATE_STARTING;
-    else if (This->dsound->device->state == STATE_STOPPING)
-        This->dsound->device->state = STATE_CAPTURING;
-    TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]);
+    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;
+    TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
 
-    LeaveCriticalSection(&(This->dsound->device->lock));
+    LeaveCriticalSection(&(This->device->lock));
 
-    if (This->dsound->device->driver) {
-        hres = IDsCaptureDriverBuffer_Start(This->dsound->device->hwbuf, dwFlags);
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Start(This->device->hwbuf, dwFlags);
        if (hres != DS_OK)
            WARN("IDsCaptureDriverBuffer_Start failed\n");
-    } else if (This->dsound->device->hwi) {
-        IDirectSoundCaptureImpl* ipDSC = This->dsound;
-
-        if (ipDSC->device->buffer) {
-            if (This->nrofnotifies) {
-               int c;
-
-               ipDSC->device->nrofpwaves = This->nrofnotifies;
-               TRACE("nrofnotifies=%d\n", This->nrofnotifies);
-
-                /* prepare headers */
-               if (ipDSC->device->pwave)
-                    ipDSC->device->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->pwave,
-                       ipDSC->device->nrofpwaves*sizeof(WAVEHDR));
-               else
-                    ipDSC->device->pwave = HeapAlloc(GetProcessHeap(),0,
-                       ipDSC->device->nrofpwaves*sizeof(WAVEHDR));
-
-                for (c = 0; c < ipDSC->device->nrofpwaves; c++) {
-                    if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) {
-                        TRACE("got DSBPN_OFFSETSTOP\n");
-                        ipDSC->device->nrofpwaves = c;
-                        break;
-                    }
-                    if (c == 0) {
-                        ipDSC->device->pwave[0].lpData = (LPSTR)ipDSC->device->buffer;
-                        ipDSC->device->pwave[0].dwBufferLength =
-                            This->notifies[0].dwOffset + 1;
-                    } else {
-                        ipDSC->device->pwave[c].lpData = (LPSTR)ipDSC->device->buffer +
-                            This->notifies[c-1].dwOffset + 1;
-                        ipDSC->device->pwave[c].dwBufferLength =
-                            This->notifies[c].dwOffset -
-                            This->notifies[c-1].dwOffset;
-                    }
-                    ipDSC->device->pwave[c].dwBytesRecorded = 0;
-                    ipDSC->device->pwave[c].dwUser = (DWORD)ipDSC;
-                    ipDSC->device->pwave[c].dwFlags = 0;
-                    ipDSC->device->pwave[c].dwLoops = 0;
-                    hres = mmErr(waveInPrepareHeader(ipDSC->device->hwi,
-                        &(ipDSC->device->pwave[c]),sizeof(WAVEHDR)));
-                   if (hres != DS_OK) {
-                        WARN("waveInPrepareHeader failed\n");
-                       while (c--)
-                           waveInUnprepareHeader(ipDSC->device->hwi,
-                               &(ipDSC->device->pwave[c]),sizeof(WAVEHDR));
-                       break;
-                   }
-
-                   hres = mmErr(waveInAddBuffer(ipDSC->device->hwi,
-                       &(ipDSC->device->pwave[c]), sizeof(WAVEHDR)));
-                   if (hres != DS_OK) {
-                        WARN("waveInAddBuffer failed\n");
-                        while (c--)
-                           waveInUnprepareHeader(ipDSC->device->hwi,
-                               &(ipDSC->device->pwave[c]),sizeof(WAVEHDR));
-                       break;
-                   }
+    } 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;
                 }
 
-                FillMemory(ipDSC->device->buffer, ipDSC->device->buflen,
-                    (ipDSC->device->pwfx->wBitsPerSample == 8) ? 128 : 0);
-            } else {
-               TRACE("no notifiers specified\n");
-               /* no notifiers specified so just create a single default header */
-               ipDSC->device->nrofpwaves = 1;
-               if (ipDSC->device->pwave)
-                    ipDSC->device->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->pwave,sizeof(WAVEHDR));
-               else
-                    ipDSC->device->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR));
-
-                ipDSC->device->pwave[0].lpData = (LPSTR)ipDSC->device->buffer;
-                ipDSC->device->pwave[0].dwBufferLength = ipDSC->device->buflen;
-                ipDSC->device->pwave[0].dwBytesRecorded = 0;
-                ipDSC->device->pwave[0].dwUser = (DWORD)ipDSC;
-                ipDSC->device->pwave[0].dwFlags = 0;
-                ipDSC->device->pwave[0].dwLoops = 0;
-
-                hres = mmErr(waveInPrepareHeader(ipDSC->device->hwi,
-                    &(ipDSC->device->pwave[0]),sizeof(WAVEHDR)));
+                hres = mmErr(waveInAddBuffer(device->hwi, &(device->pwave[c]), sizeof(WAVEHDR)));
                 if (hres != DS_OK) {
-                   WARN("waveInPrepareHeader failed\n");
-                    waveInUnprepareHeader(ipDSC->device->hwi,
-                        &(ipDSC->device->pwave[0]),sizeof(WAVEHDR));
-               }
-               hres = mmErr(waveInAddBuffer(ipDSC->device->hwi,
-                   &(ipDSC->device->pwave[0]), sizeof(WAVEHDR)));
-               if (hres != DS_OK) {
-                   WARN("waveInAddBuffer failed\n");
-                   waveInUnprepareHeader(ipDSC->device->hwi,
-                       &(ipDSC->device->pwave[0]),sizeof(WAVEHDR));
-               }
-           }
+                    WARN("waveInAddBuffer failed\n");
+                    while (c--)
+                        waveInUnprepareHeader(device->hwi, &(device->pwave[c]),sizeof(WAVEHDR));
+                    break;
+                }
+            }
+
+            FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
         }
 
-        ipDSC->device->index = 0;
-        ipDSC->device->read_position = 0;
+        device->index = 0;
 
        if (hres == DS_OK) {
            /* start filling the first buffer */
-           hres = mmErr(waveInStart(ipDSC->device->hwi));
+           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(This->dsound->device->hwi);
-            This->dsound->device->hwi = 0;
+            waveInClose(device->hwi);
+            device->hwi = 0;
         }
     } else {
         WARN("no driver\n");
         hres = DSERR_NODRIVER;
     }
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1589,33 +1206,28 @@ IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
     TRACE( "(%p)\n", This );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    if (This->dsound == NULL) {
-        WARN("invalid parameter: This->dsound == NULL\n");
+    if (This->device == NULL) {
+        WARN("invalid parameter: This->device == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    EnterCriticalSection(&(This->dsound->device->lock));
+    EnterCriticalSection(&(This->device->lock));
 
-    TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->device->state]);
-    if (This->dsound->device->state == STATE_CAPTURING)
-       This->dsound->device->state = STATE_STOPPING;
-    else if (This->dsound->device->state == STATE_STARTING)
-       This->dsound->device->state = STATE_STOPPED;
-    TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]);
+    TRACE("old This->device->state=%s\n",captureStateString[This->device->state]);
+    if (This->device->state == STATE_CAPTURING)
+       This->device->state = STATE_STOPPING;
+    else if (This->device->state == STATE_STARTING)
+       This->device->state = STATE_STOPPED;
+    TRACE("new This->device->state=%s\n",captureStateString[This->device->state]);
 
-    LeaveCriticalSection(&(This->dsound->device->lock));
+    LeaveCriticalSection(&(This->device->lock));
 
-    if (This->dsound->device->driver) {
-        hres = IDsCaptureDriverBuffer_Stop(This->dsound->device->hwbuf);
+    if (This->device->driver) {
+        hres = IDsCaptureDriverBuffer_Stop(This->device->hwbuf);
         if (hres != DS_OK)
             WARN("IDsCaptureDriverBuffer_Stop() failed\n");
-    } else if (This->dsound->device->hwi) {
-        hres = mmErr(waveInReset(This->dsound->device->hwi));
+    } else if (This->device->hwi) {
+        hres = mmErr(waveInReset(This->device->hwi));
         if (hres != DS_OK)
             WARN("waveInReset() failed\n");
     } else {
@@ -1623,7 +1235,7 @@ IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
         hres = DSERR_NODRIVER;
     }
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1637,33 +1249,25 @@ IDirectSoundCaptureBufferImpl_Unlock(
 {
     HRESULT hres = DS_OK;
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
-    TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1,
+    TRACE( "(%p,%p,%08u,%p,%08u)\n", This, lpvAudioPtr1, dwAudioBytes1,
         lpvAudioPtr2, dwAudioBytes2 );
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
     if (lpvAudioPtr1 == NULL) {
         WARN("invalid parameter: lpvAudioPtr1 == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (This->dsound->device->driver) {
-        hres = IDsCaptureDriverBuffer_Unlock(This->dsound->device->hwbuf, lpvAudioPtr1,
+    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->dsound->device->hwi) {
-        This->dsound->device->read_position = (This->dsound->device->read_position +
-            (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->device->buflen;
-    } else {
+    } else if (!This->device->hwi) {
         WARN("invalid call\n");
         hres = DSERR_INVALIDCALL;
     }
 
-    TRACE("returning %08lx\n", hres);
+    TRACE("returning %08x\n", hres);
     return hres;
 }
 
@@ -1677,7 +1281,7 @@ IDirectSoundCaptureBufferImpl_GetObjectInPath(
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
 
-    FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject),
+    FIXME( "(%p,%s,%u,%s,%p): stub\n", This, debugstr_guid(rguidObject),
         dwIndex, debugstr_guid(rguidInterface), ppObject );
 
     return DS_OK;
@@ -1691,7 +1295,7 @@ IDirectSoundCaptureBufferImpl_GetFXStatus(
 {
     IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface;
 
-    FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus );
+    FIXME( "(%p,%u,%p): stub\n", This, dwFXCount, pdwFXStatus );
 
     return DS_OK;
 }
@@ -1719,79 +1323,336 @@ static const IDirectSoundCaptureBuffer8Vtbl dscbvt =
     IDirectSoundCaptureBufferImpl_GetFXStatus
 };
 
-/*******************************************************************************
- * DirectSoundCapture ClassFactory
- */
-
-static HRESULT WINAPI
-DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+HRESULT IDirectSoundCaptureBufferImpl_Create(
+    DirectSoundCaptureDevice *device,
+    IDirectSoundCaptureBufferImpl ** ppobj,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    LPWAVEFORMATEX  wfex;
+    TRACE( "(%p,%p,%p)\n", device, ppobj, lpcDSCBufferDesc);
 
-    FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
-    return E_NOINTERFACE;
-}
+    if (ppobj == NULL) {
+       WARN("invalid parameter: ppobj == NULL\n");
+       return DSERR_INVALIDPARAM;
+    }
 
-static ULONG WINAPI
-DSCCF_AddRef(LPCLASSFACTORY iface)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
+    if (!device) {
+       WARN("not initialized\n");
+        *ppobj = NULL;
+       return DSERR_UNINITIALIZED;
+    }
 
-static ULONG WINAPI
-DSCCF_Release(LPCLASSFACTORY iface)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    /* static class, won't be  freed */
-    return ref;
+    if (lpcDSCBufferDesc == NULL) {
+       WARN("invalid parameter: lpcDSCBufferDesc == NULL\n");
+        *ppobj = NULL;
+       return DSERR_INVALIDPARAM;
+    }
+
+    if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) &&
+          (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) ||
+        (lpcDSCBufferDesc->dwBufferBytes == 0) ||
+        (lpcDSCBufferDesc->lpwfxFormat == NULL) ) {
+       WARN("invalid lpcDSCBufferDesc\n");
+       *ppobj = NULL;
+       return DSERR_INVALIDPARAM;
+    }
+
+    wfex = lpcDSCBufferDesc->lpwfxFormat;
+
+    if (wfex) {
+        TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
+            "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
+            wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec,
+            wfex->nAvgBytesPerSec, wfex->nBlockAlign,
+            wfex->wBitsPerSample, wfex->cbSize);
+
+        if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
+           device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX));
+            *device->pwfx = *wfex;
+           device->pwfx->cbSize = 0;
+       } else {
+           device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize);
+            CopyMemory(device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize);
+        }
+    } else {
+       WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n");
+       *ppobj = NULL;
+       return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */
+    }
+
+    *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+        sizeof(IDirectSoundCaptureBufferImpl));
+
+    if ( *ppobj == NULL ) {
+       WARN("out of memory\n");
+       *ppobj = NULL;
+       return DSERR_OUTOFMEMORY;
+    } else {
+       HRESULT err = DS_OK;
+        LPBYTE newbuf;
+        DWORD buflen;
+        IDirectSoundCaptureBufferImpl *This = *ppobj;
+
+        This->ref = 1;
+        This->device = device;
+        This->device->capture_buffer = This;
+       This->notify = NULL;
+       This->nrofnotifies = 0;
+       This->hwnotify = NULL;
+
+        This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+            lpcDSCBufferDesc->dwSize);
+        if (This->pdscbd)
+            CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize);
+        else {
+            WARN("no memory\n");
+            This->device->capture_buffer = 0;
+            HeapFree( GetProcessHeap(), 0, This );
+            *ppobj = NULL;
+            return DSERR_OUTOFMEMORY;
+        }
+
+        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 = 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;
+            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) {
+                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;
+            }
+       }
+    }
+
+    TRACE("returning DS_OK\n");
+    return DS_OK;
 }
 
-static HRESULT WINAPI
-DSCCF_CreateInstance(
-       LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
+/*******************************************************************************
+ * DirectSoundCaptureDevice
+ */
+HRESULT DirectSoundCaptureDevice_Initialize(
+    DirectSoundCaptureDevice ** ppDevice,
+    LPCGUID lpcGUID)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
+    HRESULT err = DSERR_INVALIDPARAM;
+    unsigned wid, widn;
+    BOOLEAN found = FALSE;
+    GUID devGUID;
+    DirectSoundCaptureDevice *device = *ppDevice;
+    TRACE("(%p, %s)\n", ppDevice, debugstr_guid(lpcGUID));
+
+    /* Default device? */
+    if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) )
+       lpcGUID = &DSDEVID_DefaultCapture;
 
-    if (pOuter) {
-        WARN("aggregation not supported\n");
-        return CLASS_E_NOAGGREGATION;
+    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
+        WARN("invalid parameter: lpcGUID\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    if (ppobj == NULL) {
-       WARN("invalid parameter\n");
-       return E_INVALIDARG;
+    widn = waveInGetNumDevs();
+    if (!widn) {
+       WARN("no audio devices found\n");
+       return DSERR_NODRIVER;
     }
 
-    *ppobj = NULL;
+    /* 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;
+       }
+    }
 
-    if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) )
-       return DSOUND_CaptureCreate8((LPDIRECTSOUNDCAPTURE*)ppobj,pOuter);
+    if (found == FALSE) {
+       WARN("No device found matching given ID!\n");
+       return DSERR_NODRIVER;
+    }
 
-    WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
-    return E_NOINTERFACE;
+    if (DSOUND_capture[wid]) {
+        WARN("already in use\n");
+        return DSERR_ALLOCATED;
+    }
+
+    err = DirectSoundCaptureDevice_Create(&(device));
+    if (err != DS_OK) {
+        WARN("DirectSoundCaptureDevice_Create failed\n");
+        return err;
+    }
+
+    *ppDevice = device;
+    device->guid = devGUID;
+
+    /* 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;
+
+    /* 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;
+            }
+        }
+    }
+
+    return err;
 }
 
-static HRESULT WINAPI
-DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
+static HRESULT DirectSoundCaptureDevice_Create(
+    DirectSoundCaptureDevice ** ppDevice)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    FIXME("(%p)->(%d),stub!\n",This,dolock);
-    return S_OK;
+    DirectSoundCaptureDevice * device;
+    TRACE("(%p)\n", ppDevice);
+
+    /* Allocate memory */
+    device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice));
+
+    if (device == NULL) {
+       WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    device->ref = 1;
+    device->state = STATE_STOPPED;
+
+    InitializeCriticalSection( &(device->lock) );
+    device->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundCaptureDevice.lock");
+
+    *ppDevice = device;
+
+    return DS_OK;
 }
 
-static const IClassFactoryVtbl DSCCF_Vtbl =
+ULONG DirectSoundCaptureDevice_Release(
+    DirectSoundCaptureDevice * device)
 {
-    DSCCF_QueryInterface,
-    DSCCF_AddRef,
-    DSCCF_Release,
-    DSCCF_CreateInstance,
-    DSCCF_LockServer
-};
+    ULONG ref = InterlockedDecrement(&(device->ref));
+    TRACE("(%p) ref was %d\n", device, ref + 1);
+
+    if (!ref) {
+        TRACE("deleting object\n");
+        if (device->capture_buffer)
+            IDirectSoundCaptureBufferImpl_Release(
+               (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer);
+
+        if (device->driver) {
+            IDsCaptureDriver_Close(device->driver);
+            IDsCaptureDriver_Release(device->driver);
+        }
 
-IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 };
+        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;
+}
index 08f6e48..1f60f37 100644 (file)
@@ -17,7 +17,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
-#include "winreg.h"
+#include "winuser.h"
 #include "mmsystem.h"
 #include "winternl.h"
 #include "mmddk.h"
+#include "wingdi.h"
+#include "mmreg.h"
+#include "ks.h"
+#include "ksmedia.h"
 #include "wine/debug.h"
 #include "dsound.h"
 #include "dsdriver.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
-static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
+/*****************************************************************************
+ * IDirectSound COM components
+ */
+struct IDirectSound_IUnknown {
+    const IUnknownVtbl         *lpVtbl;
+    LONG                        ref;
+    LPDIRECTSOUND8              pds;
+};
+
+static HRESULT IDirectSound_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
+
+struct IDirectSound_IDirectSound {
+    const IDirectSoundVtbl     *lpVtbl;
+    LONG                        ref;
+    LPDIRECTSOUND8              pds;
+};
+
+static HRESULT IDirectSound_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
+
+/*****************************************************************************
+ * IDirectSound8 COM components
+ */
+struct IDirectSound8_IUnknown {
+    const IUnknownVtbl         *lpVtbl;
+    LONG                        ref;
+    LPDIRECTSOUND8              pds;
+};
+
+static HRESULT IDirectSound8_IUnknown_Create(LPDIRECTSOUND8 pds, LPUNKNOWN * ppunk);
 static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface);
+
+struct IDirectSound8_IDirectSound {
+    const IDirectSoundVtbl     *lpVtbl;
+    LONG                        ref;
+    LPDIRECTSOUND8              pds;
+};
+
+static HRESULT IDirectSound8_IDirectSound_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND * ppds);
 static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface);
+
+struct IDirectSound8_IDirectSound8 {
+    const IDirectSound8Vtbl    *lpVtbl;
+    LONG                        ref;
+    LPDIRECTSOUND8              pds;
+};
+
+static HRESULT IDirectSound8_IDirectSound8_Create(LPDIRECTSOUND8 pds, LPDIRECTSOUND8 * ppds);
 static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface);
 
-static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice);
-static ULONG DirectSoundDevice_Release(DirectSoundDevice * device);
+/*****************************************************************************
+ * IDirectSound implementation structure
+ */
+struct IDirectSoundImpl
+{
+    LONG                        ref;
+
+    DirectSoundDevice          *device;
+    LPUNKNOWN                   pUnknown;
+    LPDIRECTSOUND               pDS;
+    LPDIRECTSOUND8              pDS8;
+};
+
+static HRESULT IDirectSoundImpl_Create(LPDIRECTSOUND8 * ppds);
+
+static ULONG WINAPI IDirectSound_IUnknown_AddRef(LPUNKNOWN iface);
+static ULONG WINAPI IDirectSound_IDirectSound_AddRef(LPDIRECTSOUND iface);
 
-static const char * dumpCooperativeLevel(DWORD level)
+static HRESULT DirectSoundDevice_VerifyCertification(DirectSoundDevice * device, LPDWORD pdwCertified);
+
+const char * dumpCooperativeLevel(DWORD level)
 {
     static char unknown[32];
 #define LE(x) case x: return #x
@@ -58,7 +122,7 @@ static const char * dumpCooperativeLevel(DWORD level)
         LE(DSSCL_WRITEPRIMARY);
     }
 #undef LE
-    sprintf(unknown, "Unknown(%08lx)", level);
+    sprintf(unknown, "Unknown(%08x)", (UINT)level);
     return unknown;
 }
 
@@ -85,7 +149,7 @@ static void _dump_DSCAPS(DWORD xmask) {
 
     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
         if ((flags[i].mask & xmask) == flags[i].mask)
-            DPRINTF("%s ",flags[i].name);
+            TRACE("%s ",flags[i].name);
 }
 
 static void _dump_DSBCAPS(DWORD xmask) {
@@ -113,23 +177,13 @@ static void _dump_DSBCAPS(DWORD xmask) {
 
     for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
         if ((flags[i].mask & xmask) == flags[i].mask)
-            DPRINTF("%s ",flags[i].name);
+            TRACE("%s ",flags[i].name);
 }
 
 /*******************************************************************************
  *             IDirectSoundImpl_DirectSound
  */
-static HRESULT WINAPI IDirectSoundImpl_QueryInterface(
-    LPDIRECTSOUND8 iface,
-    REFIID riid,
-    LPVOID * ppobj)
-{
-    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppobj);
-    FIXME("shouldn't be called directly\n");
-    return E_NOINTERFACE;
-}
-
-static HRESULT WINAPI DSOUND_QueryInterface(
+static HRESULT DSOUND_QueryInterface(
     LPDIRECTSOUND8 iface,
     REFIID riid,
     LPVOID * ppobj)
@@ -173,7 +227,7 @@ static HRESULT WINAPI DSOUND_QueryInterface(
     return E_NOINTERFACE;
 }
 
-static HRESULT WINAPI DSOUND_QueryInterface8(
+static HRESULT DSOUND_QueryInterface8(
     LPDIRECTSOUND8 iface,
     REFIID riid,
     LPVOID * ppobj)
@@ -229,831 +283,565 @@ static HRESULT WINAPI DSOUND_QueryInterface8(
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI IDirectSoundImpl_AddRef(
+static ULONG IDirectSoundImpl_AddRef(
     LPDIRECTSOUND8 iface)
 {
     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
-static ULONG WINAPI IDirectSoundImpl_Release(
+static ULONG IDirectSoundImpl_Release(
     LPDIRECTSOUND8 iface)
 {
     IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
 
     if (!ref) {
         if (This->device)
             DirectSoundDevice_Release(This->device);
-
         HeapFree(GetProcessHeap(),0,This);
         TRACE("(%p) released\n", This);
     }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSoundImpl_CreateSoundBuffer(
-    LPDIRECTSOUND8 iface,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk)
+static HRESULT IDirectSoundImpl_Create(
+    LPDIRECTSOUND8 * ppDS)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
-    FIXME("shouldn't be called directly\n");
-    return DSERR_GENERIC;
+    IDirectSoundImpl* pDS;
+    TRACE("(%p)\n",ppDS);
+
+    /* Allocate memory */
+    pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
+    if (pDS == NULL) {
+        WARN("out of memory\n");
+        *ppDS = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pDS->ref    = 0;
+    pDS->device = NULL;
+
+    *ppDS = (LPDIRECTSOUND8)pDS;
+
+    return DS_OK;
 }
 
-static HRESULT WINAPI DSOUND_CreateSoundBuffer(
-    LPDIRECTSOUND8 iface,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk,
-    BOOL from8)
+/*******************************************************************************
+ *             IDirectSound_IUnknown
+ */
+static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
+    LPUNKNOWN iface,
+    REFIID riid,
+    LPVOID * ppobj)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    HRESULT hres = DS_OK;
-    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return DSOUND_QueryInterface(This->pds, riid, ppobj);
+}
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+static ULONG WINAPI IDirectSound_IUnknown_AddRef(
+    LPUNKNOWN iface)
+{
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
+static ULONG WINAPI IDirectSound_IUnknown_Release(
+    LPUNKNOWN iface)
+{
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
+        IDirectSoundImpl_Release(This->pds);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
     }
+    return ref;
+}
 
-    if (dsbd == NULL) {
-        WARN("invalid parameter: dsbd == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+static const IUnknownVtbl DirectSound_Unknown_Vtbl =
+{
+    IDirectSound_IUnknown_QueryInterface,
+    IDirectSound_IUnknown_AddRef,
+    IDirectSound_IUnknown_Release
+};
 
-    if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
-        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
-        WARN("invalid parameter: dsbd\n");
+static HRESULT IDirectSound_IUnknown_Create(
+    LPDIRECTSOUND8 pds,
+    LPUNKNOWN * ppunk)
+{
+    IDirectSound_IUnknown * pdsunk;
+    TRACE("(%p,%p)\n",pds,ppunk);
+
+    if (ppunk == NULL) {
+        ERR("invalid parameter: ppunk == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
+    if (pds == NULL) {
+        ERR("invalid parameter: pds == NULL\n");
+        *ppunk = NULL;
         return DSERR_INVALIDPARAM;
     }
 
-    if (TRACE_ON(dsound)) {
-        TRACE("(structsize=%ld)\n",dsbd->dwSize);
-        TRACE("(flags=0x%08lx:\n",dsbd->dwFlags);
-        _dump_DSBCAPS(dsbd->dwFlags);
-        DPRINTF(")\n");
-        TRACE("(bufferbytes=%ld)\n",dsbd->dwBufferBytes);
-        TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
+    pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
+    if (pdsunk == NULL) {
+        WARN("out of memory\n");
+        *ppunk = NULL;
+        return DSERR_OUTOFMEMORY;
     }
 
-    if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
-        if (dsbd->lpwfxFormat != NULL) {
-            WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
-                 "primary buffer\n");
-            return DSERR_INVALIDPARAM;
-        }
+    pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
+    pdsunk->ref = 0;
+    pdsunk->pds = pds;
 
-        if (This->device->primary) {
-            WARN("Primary Buffer already created\n");
-            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary));
-            *ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary);
-        } else {
-           This->device->dsbd = *dsbd;
-           hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->device->primary), &(This->device->dsbd));
-           if (This->device->primary) {
-               IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary));
-               *ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary);
-           } else
-               WARN("PrimaryBufferImpl_Create failed\n");
-        }
-    } else {
-        IDirectSoundBufferImpl * dsb;
+    IDirectSoundImpl_AddRef(pds);
+    *ppunk = (LPUNKNOWN)pdsunk;
 
-        if (dsbd->lpwfxFormat == NULL) {
-            WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
-                 "secondary buffer\n");
-            return DSERR_INVALIDPARAM;
-        }
+    return DS_OK;
+}
 
-        TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld,"
-              "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
-              dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
-              dsbd->lpwfxFormat->nSamplesPerSec,
-              dsbd->lpwfxFormat->nAvgBytesPerSec,
-              dsbd->lpwfxFormat->nBlockAlign,
-              dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
+/*******************************************************************************
+ *             IDirectSound_IDirectSound
+ */
+static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
+    LPDIRECTSOUND iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return DSOUND_QueryInterface(This->pds, riid, ppobj);
+}
 
-        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
-            WARN("invalid parameter: 3D buffer format must be mono\n");
-            return DSERR_INVALIDPARAM;
-        }
+static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
 
-        hres = IDirectSoundBufferImpl_Create(This, (IDirectSoundBufferImpl**)&dsb, dsbd);
-        if (dsb) {
-            hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
-            if (*ppdsb) {
-                dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
-                IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppdsb);
-            } else
-                WARN("SecondaryBufferImpl_Create failed\n");
-        } else
-           WARN("IDirectSoundBufferImpl_Create failed\n");
-   }
+static ULONG WINAPI IDirectSound_IDirectSound_Release(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        ((IDirectSoundImpl*)This->pds)->pDS = NULL;
+        IDirectSoundImpl_Release(This->pds);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
 
-   return hres;
+static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,FALSE);
 }
 
-static HRESULT WINAPI IDirectSoundImpl_GetCaps(
-    LPDIRECTSOUND8 iface,
+static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
+    LPDIRECTSOUND iface,
     LPDSCAPS lpDSCaps)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    DirectSoundDevice *device;
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
     TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
+}
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    device = This->device;
+static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
+}
 
-    if (device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
+    LPDIRECTSOUND iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
+}
 
-    if (lpDSCaps == NULL) {
-        WARN("invalid parameter: lpDSCaps = NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
+}
 
-    /* check if there is enough room */
-    if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
-        WARN("invalid parameter: lpDSCaps->dwSize = %ld < %d\n",
-             lpDSCaps->dwSize, sizeof(*lpDSCaps));
-        return DSERR_INVALIDPARAM;
-    }
-
-    lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
-    if (TRACE_ON(dsound)) {
-        TRACE("(flags=0x%08lx:\n",lpDSCaps->dwFlags);
-        _dump_DSCAPS(lpDSCaps->dwFlags);
-        DPRINTF(")\n");
-    }
-    lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
-    lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
-    lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
-    lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
-    lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
-    lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
-    lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
-    lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
-    lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
-    lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
-    lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
-    lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
-    lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
-    lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
-    lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
-    lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
-    lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
-    lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
-
-    /* driver doesn't have these */
-    lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
-    lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
-
-    return DS_OK;
+static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
 }
 
-static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
-    LPDIRECTSOUND8 iface,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
+static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    DWORD config)
 {
-    IDirectSoundBufferImpl* pdsb;
-    IDirectSoundBufferImpl* dsb;
-    HRESULT hres = DS_OK;
-    int size;
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
+}
 
-    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
+    LPDIRECTSOUND iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
+}
 
-    if (This == NULL) {
-        WARN("invalid parameter: This == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
+{
+    IDirectSound_IDirectSound_QueryInterface,
+    IDirectSound_IDirectSound_AddRef,
+    IDirectSound_IDirectSound_Release,
+    IDirectSound_IDirectSound_CreateSoundBuffer,
+    IDirectSound_IDirectSound_GetCaps,
+    IDirectSound_IDirectSound_DuplicateSoundBuffer,
+    IDirectSound_IDirectSound_SetCooperativeLevel,
+    IDirectSound_IDirectSound_Compact,
+    IDirectSound_IDirectSound_GetSpeakerConfig,
+    IDirectSound_IDirectSound_SetSpeakerConfig,
+    IDirectSound_IDirectSound_Initialize
+};
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+static HRESULT IDirectSound_IDirectSound_Create(
+    LPDIRECTSOUND8  pds,
+    LPDIRECTSOUND * ppds)
+{
+    IDirectSound_IDirectSound * pdsds;
+    TRACE("(%p,%p)\n",pds,ppds);
 
-    if (psb == NULL) {
-        WARN("invalid parameter: psb == NULL\n");
+    if (ppds == NULL) {
+        ERR("invalid parameter: ppds == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
+    if (pds == NULL) {
+        ERR("invalid parameter: pds == NULL\n");
+        *ppds = NULL;
         return DSERR_INVALIDPARAM;
     }
 
-    /* FIXME: hack to make sure we have a secondary buffer */
-    if ((IDirectSoundImpl *)((SecondaryBufferImpl *)psb)->dsb == This) {
-        WARN("trying to duplicate primary buffer\n");
-        *ppdsb = NULL;
-        return DSERR_INVALIDCALL;
-    }
-
-    pdsb = ((SecondaryBufferImpl *)psb)->dsb;
-
-    dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
-
-    if (dsb == NULL) {
+    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
+    if (pdsds == NULL) {
         WARN("out of memory\n");
-        *ppdsb = NULL;
+        *ppds = NULL;
         return DSERR_OUTOFMEMORY;
     }
 
-    CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));
-
-    if (pdsb->hwbuf) {
-        TRACE("duplicating hardware buffer\n");
-
-        hres = IDsDriver_DuplicateSoundBuffer(This->device->driver, pdsb->hwbuf, (LPVOID *)&dsb->hwbuf);
-        if (hres != DS_OK) {
-            TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to software buffer\n");
-            dsb->hwbuf = NULL;
-            /* allocate buffer */
-            if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
-                dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
-                if (dsb->buffer == NULL) {
-                    WARN("out of memory\n");
-                    HeapFree(GetProcessHeap(),0,dsb);
-                    *ppdsb = NULL;
-                    return DSERR_OUTOFMEMORY;
-                }
-
-                dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
-                if (dsb->buffer->memory == NULL) {
-                    WARN("out of memory\n");
-                    HeapFree(GetProcessHeap(),0,dsb->buffer);
-                    HeapFree(GetProcessHeap(),0,dsb);
-                    *ppdsb = NULL;
-                    return DSERR_OUTOFMEMORY;
-                }
-                dsb->buffer->ref = 1;
-
-                /* FIXME: copy buffer ? */
-            }
-        }
-    } else {
-        dsb->hwbuf = NULL;
-        dsb->buffer->ref++;
-    }
-
-    dsb->ref = 0;
-    dsb->state = STATE_STOPPED;
-    dsb->playpos = 0;
-    dsb->buf_mixpos = 0;
-    dsb->dsound = This;
-    dsb->ds3db = NULL;
-    dsb->iks = NULL; /* FIXME? */
-    dsb->dsb = NULL;
-
-    /* variable sized struct so calculate size based on format */
-    size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;
-
-    dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
-    if (dsb->pwfx == NULL) {
-            WARN("out of memory\n");
-            HeapFree(GetProcessHeap(),0,dsb->buffer);
-            HeapFree(GetProcessHeap(),0,dsb);
-            *ppdsb = NULL;
-            return DSERR_OUTOFMEMORY;
-    }
-
-    CopyMemory(dsb->pwfx, pdsb->pwfx, size);
-
-    InitializeCriticalSection(&(dsb->lock));
-    dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
-
-    /* register buffer */
-    hres = DSOUND_AddBuffer(This, dsb);
-    if (hres != DS_OK) {
-        IDirectSoundBuffer8_Release(psb);
-        dsb->lock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection(&(dsb->lock));
-        HeapFree(GetProcessHeap(),0,dsb->buffer);
-        HeapFree(GetProcessHeap(),0,dsb->pwfx);
-        HeapFree(GetProcessHeap(),0,dsb);
-        *ppdsb = 0;
-    } else {
-        hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
-        if (*ppdsb) {
-            dsb->dsb = (SecondaryBufferImpl*)*ppdsb;
-            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
-        } else
-            WARN("SecondaryBufferImpl_Create failed\n");
-    }
-
-    return hres;
-}
-
-static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel(
-    LPDIRECTSOUND8 iface,
-    HWND hwnd,
-    DWORD level)
-{
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
+    pdsds->ref = 0;
+    pdsds->pds = pds;
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    IDirectSoundImpl_AddRef(pds);
+    *ppds = (LPDIRECTSOUND)pdsds;
 
-    if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
-        WARN("level=%s not fully supported\n",
-             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
-    }
-    This->device->priolevel = level;
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundImpl_Compact(
-    LPDIRECTSOUND8 iface)
+/*******************************************************************************
+ *             IDirectSound8_IUnknown
+ */
+static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
+    LPUNKNOWN iface,
+    REFIID riid,
+    LPVOID * ppobj)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p)\n",This);
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
+}
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
+    LPUNKNOWN iface)
+{
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
 
-    if (This->device->priolevel != DSSCL_PRIORITY) {
-        WARN("incorrect priority level\n");
-        return DSERR_PRIOLEVELNEEDED;
+static ULONG WINAPI IDirectSound8_IUnknown_Release(
+    LPUNKNOWN iface)
+{
+    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        ((IDirectSoundImpl*)This->pds)->pUnknown = NULL;
+        IDirectSoundImpl_Release(This->pds);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
     }
-
-    return DS_OK;
+    return ref;
 }
 
-static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig(
-    LPDIRECTSOUND8 iface,
-    LPDWORD lpdwSpeakerConfig)
+static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p, %p)\n",This,lpdwSpeakerConfig);
+    IDirectSound8_IUnknown_QueryInterface,
+    IDirectSound8_IUnknown_AddRef,
+    IDirectSound8_IUnknown_Release
+};
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
+static HRESULT IDirectSound8_IUnknown_Create(
+    LPDIRECTSOUND8 pds,
+    LPUNKNOWN * ppunk)
+{
+    IDirectSound8_IUnknown * pdsunk;
+    TRACE("(%p,%p)\n",pds,ppunk);
+
+    if (ppunk == NULL) {
+        ERR("invalid parameter: ppunk == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    if (lpdwSpeakerConfig == NULL) {
-        WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
+    if (pds == NULL) {
+        ERR("invalid parameter: pds == NULL\n");
+        *ppunk = NULL;
         return DSERR_INVALIDPARAM;
     }
 
-    WARN("not fully functional\n");
-    *lpdwSpeakerConfig = This->device->speaker_config;
-    return DS_OK;
-}
+    pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
+    if (pdsunk == NULL) {
+        WARN("out of memory\n");
+        *ppunk = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
 
-static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig(
-    LPDIRECTSOUND8 iface,
-    DWORD config)
-{
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p,0x%08lx)\n",This,config);
+    pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
+    pdsunk->ref = 0;
+    pdsunk->pds = pds;
 
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    IDirectSoundImpl_AddRef(pds);
+    *ppunk = (LPUNKNOWN)pdsunk;
 
-    This->device->speaker_config = config;
-    WARN("not fully functional\n");
     return DS_OK;
 }
 
-static HRESULT WINAPI IDirectSoundImpl_Initialize(
-    LPDIRECTSOUND8 iface,
-    LPCGUID lpcGUID)
+/*******************************************************************************
+ *             IDirectSound8_IDirectSound
+ */
+static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
+    LPDIRECTSOUND iface,
+    REFIID riid,
+    LPVOID * ppobj)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    DirectSoundDevice *device = This->device;
-    HRESULT hr = DS_OK;
-    unsigned wod, wodn;
-    BOOLEAN found = FALSE;
-    GUID devGUID;
-    TRACE("(%p,%s)\n",This,debugstr_guid(lpcGUID));
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
+}
 
-    if (device != NULL) {
-        WARN("already initialized\n");
-        return DSERR_ALREADYINITIALIZED;
+static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSound8_IDirectSound_Release(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        ((IDirectSoundImpl*)This->pds)->pDS = NULL;
+        IDirectSoundImpl_Release(This->pds);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
     }
+    return ref;
+}
 
-    /* Default device? */
-    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
-        lpcGUID = &DSDEVID_DefaultPlayback;
-
-    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
-        WARN("invalid parameter: lpcGUID\n");
-        return DSERR_INVALIDPARAM;
-    }
-
-    /* Enumerate WINMM audio devices and find the one we want */
-    wodn = waveOutGetNumDevs();
-    if (!wodn) {
-        WARN("no driver\n");
-        return DSERR_NODRIVER;
-    }
-
-    for (wod=0; wod<wodn; wod++) {
-        if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
-            found = TRUE;
-            break;
-        }
-    }
-
-    if (found == FALSE) {
-        WARN("No device found matching given ID!\n");
-        return DSERR_NODRIVER;
-    }
-
-    if (DSOUND_renderer[wod]) {
-        if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
-            device = DSOUND_renderer[wod];
-            device->ref++;
-            This->device = device;
-            return DS_OK;
-        } else {
-            ERR("device GUID doesn't match\n");
-            hr = DSERR_GENERIC;
-            return hr;
-        }
-    } else {
-        hr = DirectSoundDevice_Create(&(device));
-        if (hr != DS_OK) {
-            WARN("DirectSoundDevice_Create failed\n");
-            return hr;
-        }
-    }
-
-    This->device = device;
-    device->guid = devGUID;
-
-    /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */
-    WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0);
-
-    /* Disable the direct sound driver to force emulation if requested. */
-    if (ds_hw_accel == DS_HW_ACCEL_EMULATION)
-        device->driver = NULL;
-
-    /* Get driver description */
-    if (device->driver) {
-        hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc));
-        if (hr != DS_OK) {
-            WARN("IDsDriver_GetDriverDesc failed\n");
-            return hr;
-        }
-    } else {
-        /* if no DirectSound interface available, use WINMM API instead */
-        device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT;
-    }
-
-    device->drvdesc.dnDevNode = wod;
-
-    /* If the driver requests being opened through MMSYSTEM
-     * (which is recommended by the DDK), it is supposed to happen
-     * before the DirectSound interface is opened */
-    if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
-    {
-        DWORD flags = CALLBACK_FUNCTION;
-
-        /* disable direct sound if requested */
-        if (ds_hw_accel != DS_HW_ACCEL_EMULATION)
-            flags |= WAVE_DIRECTSOUND;
-
-        hr = mmErr(waveOutOpen(&(device->hwo),
-                                device->drvdesc.dnDevNode, device->pwfx,
-                                (DWORD_PTR)DSOUND_callback, (DWORD)device,
-                                flags));
-        if (hr != DS_OK) {
-            WARN("waveOutOpen failed\n");
-            return hr;
-        }
-    }
-
-    if (device->driver) {
-        hr = IDsDriver_Open(device->driver);
-        if (hr != DS_OK) {
-            WARN("IDsDriver_Open failed\n");
-            return hr;
-        }
-
-        /* the driver is now open, so it's now allowed to call GetCaps */
-        hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
-        if (hr != DS_OK) {
-            WARN("IDsDriver_GetCaps failed\n");
-            return hr;
-        }
-    } else {
-        WAVEOUTCAPSA woc;
-        hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
-        if (hr != DS_OK) {
-            WARN("waveOutGetDevCaps failed\n");
-            return hr;
-        }
-        ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
-        if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
-            (woc.dwFormats & WAVE_FORMAT_2M08) ||
-            (woc.dwFormats & WAVE_FORMAT_4M08) ||
-            (woc.dwFormats & WAVE_FORMAT_48M08) ||
-            (woc.dwFormats & WAVE_FORMAT_96M08)) {
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
-        }
-        if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
-            (woc.dwFormats & WAVE_FORMAT_2M16) ||
-            (woc.dwFormats & WAVE_FORMAT_4M16) ||
-            (woc.dwFormats & WAVE_FORMAT_48M16) ||
-            (woc.dwFormats & WAVE_FORMAT_96M16)) {
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
-        }
-        if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
-            (woc.dwFormats & WAVE_FORMAT_2S08) ||
-            (woc.dwFormats & WAVE_FORMAT_4S08) ||
-            (woc.dwFormats & WAVE_FORMAT_48S08) ||
-            (woc.dwFormats & WAVE_FORMAT_96S08)) {
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-        }
-        if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
-            (woc.dwFormats & WAVE_FORMAT_2S16) ||
-            (woc.dwFormats & WAVE_FORMAT_4S16) ||
-            (woc.dwFormats & WAVE_FORMAT_48S16) ||
-            (woc.dwFormats & WAVE_FORMAT_96S16)) {
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
-            device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-        }
-        if (ds_emuldriver)
-            device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
-        device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
-        device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
-        device->drvcaps.dwPrimaryBuffers = 1;
-    }
-
-    hr = DSOUND_PrimaryCreate(device);
-    if (hr == DS_OK) {
-        DSOUND_renderer[device->drvdesc.dnDevNode] = device;
-        timeBeginPeriod(DS_TIME_RES);
-        DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer,
-            (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
-    } else {
-        WARN("DSOUND_PrimaryCreate failed\n");
-    }
-
-    return hr;
+static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
 }
 
-static HRESULT WINAPI IDirectSoundImpl_VerifyCertification(
-    LPDIRECTSOUND8 iface,
-    LPDWORD pdwCertified)
+static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
+    LPDIRECTSOUND iface,
+    LPDSCAPS lpDSCaps)
 {
-    IDirectSoundImpl *This = (IDirectSoundImpl *)iface;
-    TRACE("(%p, %p)\n",This,pdwCertified);
-
-    if (This->device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
-
-    if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
-        *pdwCertified = DS_CERTIFIED;
-    else
-        *pdwCertified = DS_UNCERTIFIED;
-    return DS_OK;
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
 }
 
-static const IDirectSound8Vtbl IDirectSoundImpl_Vtbl =
-{
-    IDirectSoundImpl_QueryInterface,
-    IDirectSoundImpl_AddRef,
-    IDirectSoundImpl_Release,
-    IDirectSoundImpl_CreateSoundBuffer,
-    IDirectSoundImpl_GetCaps,
-    IDirectSoundImpl_DuplicateSoundBuffer,
-    IDirectSoundImpl_SetCooperativeLevel,
-    IDirectSoundImpl_Compact,
-    IDirectSoundImpl_GetSpeakerConfig,
-    IDirectSoundImpl_SetSpeakerConfig,
-    IDirectSoundImpl_Initialize,
-    IDirectSoundImpl_VerifyCertification
-};
-
-static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
+static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
 {
-    DirectSoundDevice * device;
-    TRACE("(%p)\n", ppDevice);
-
-    /* Allocate memory */
-    device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
-    if (device == NULL) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
-    }
-
-    device->ref            = 1;
-    device->driver         = NULL;
-    device->priolevel      = DSSCL_NORMAL;
-    device->fraglen        = 0;
-    device->hwbuf          = NULL;
-    device->buffer         = NULL;
-    device->buflen         = 0;
-    device->writelead      = 0;
-    device->state          = STATE_STOPPED;
-    device->nrofbuffers    = 0;
-    device->buffers        = NULL;
-    device->primary        = NULL;
-    device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
-    device->tmp_buffer     = NULL;
-    device->tmp_buffer_len = 0;
-
-    /* 3D listener initial parameters */
-    device->listener       = NULL;
-    device->ds3dl.dwSize   = sizeof(DS3DLISTENER);
-    device->ds3dl.vPosition.x = 0.0;
-    device->ds3dl.vPosition.y = 0.0;
-    device->ds3dl.vPosition.z = 0.0;
-    device->ds3dl.vVelocity.x = 0.0;
-    device->ds3dl.vVelocity.y = 0.0;
-    device->ds3dl.vVelocity.z = 0.0;
-    device->ds3dl.vOrientFront.x = 0.0;
-    device->ds3dl.vOrientFront.y = 0.0;
-    device->ds3dl.vOrientFront.z = 1.0;
-    device->ds3dl.vOrientTop.x = 0.0;
-    device->ds3dl.vOrientTop.y = 1.0;
-    device->ds3dl.vOrientTop.z = 0.0;
-    device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
-    device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
-    device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
-
-    device->prebuf         = ds_snd_queue_max;
-    device->guid           = GUID_NULL;
-
-    /* Set default wave format (may need it for waveOutOpen) */
-    device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
-    if (device->pwfx == NULL) {
-        WARN("out of memory\n");
-        HeapFree(GetProcessHeap(),0,device);
-        return DSERR_OUTOFMEMORY;
-    }
-
-    /* We rely on the sound driver to return the actual sound format of
-     * the device if it does not support 22050x8x2 and is given the
-     * WAVE_DIRECTSOUND flag.
-     */
-    device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
-    device->pwfx->nSamplesPerSec = 22050;
-    device->pwfx->wBitsPerSample = 8;
-    device->pwfx->nChannels = 2;
-    device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
-    device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
-    device->pwfx->cbSize = 0;
-
-    InitializeCriticalSection(&(device->mixlock));
-    device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUND_mixlock";
-
-    RtlInitializeResource(&(device->buffer_list_lock));
-
-   *ppDevice = device;
-
-    return DS_OK;
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
 }
 
-static ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
+static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
+    LPDIRECTSOUND iface,
+    HWND hwnd,
+    DWORD level)
 {
-    int i;
-    HRESULT hr;
-    TRACE("(%p) ref was %lu\n", device, device->ref);
-
-    device->ref--;
-    if (device->ref == 0) {
-        timeKillEvent(device->timerID);
-        timeEndPeriod(DS_TIME_RES);
-        /* wait for timer to expire */
-        Sleep(DS_TIME_RES+1);
-
-        /* The sleep above should have allowed the timer process to expire
-         * but try to grab the lock just in case. Can't hold lock because
-         * IDirectSoundBufferImpl_Destroy also grabs the lock */
-        RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
-        RtlReleaseResource(&(device->buffer_list_lock));
-
-        /* It is allowed to release this object even when buffers are playing */
-        if (device->buffers) {
-            WARN("%d secondary buffers not released\n", device->nrofbuffers);
-            for( i=0;i<device->nrofbuffers;i++)
-                IDirectSoundBufferImpl_Destroy(device->buffers[i]);
-        }
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
+}
 
-        if (device->primary) {
-            WARN("primary buffer not released\n");
-            IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
-        }
+static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
+    LPDIRECTSOUND iface)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
+}
 
-        hr = DSOUND_PrimaryDestroy(device);
-        if (hr != DS_OK)
-            WARN("DSOUND_PrimaryDestroy failed\n");
+static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
+}
 
-        if (device->driver)
-            IDsDriver_Close(device->driver);
+static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    DWORD config)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
+}
 
-        if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
-            waveOutClose(device->hwo);
+static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
+    LPDIRECTSOUND iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
+}
 
-        if (device->driver)
-            IDsDriver_Release(device->driver);
+static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
+{
+    IDirectSound8_IDirectSound_QueryInterface,
+    IDirectSound8_IDirectSound_AddRef,
+    IDirectSound8_IDirectSound_Release,
+    IDirectSound8_IDirectSound_CreateSoundBuffer,
+    IDirectSound8_IDirectSound_GetCaps,
+    IDirectSound8_IDirectSound_DuplicateSoundBuffer,
+    IDirectSound8_IDirectSound_SetCooperativeLevel,
+    IDirectSound8_IDirectSound_Compact,
+    IDirectSound8_IDirectSound_GetSpeakerConfig,
+    IDirectSound8_IDirectSound_SetSpeakerConfig,
+    IDirectSound8_IDirectSound_Initialize
+};
 
-        DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
+static HRESULT IDirectSound8_IDirectSound_Create(
+    LPDIRECTSOUND8 pds,
+    LPDIRECTSOUND * ppds)
+{
+    IDirectSound8_IDirectSound * pdsds;
+    TRACE("(%p,%p)\n",pds,ppds);
 
-       HeapFree(GetProcessHeap(),0,device->tmp_buffer);
-       HeapFree(GetProcessHeap(),0,device->buffer);
-        RtlDeleteResource(&device->buffer_list_lock);
-        device->mixlock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection(&device->mixlock);
-        HeapFree(GetProcessHeap(),0,device);
-        TRACE("(%p) released\n", device);
+    if (ppds == NULL) {
+        ERR("invalid parameter: ppds == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
-    return device->ref;
-}
 
-HRESULT WINAPI IDirectSoundImpl_Create(
-    LPDIRECTSOUND8 * ppDS)
-{
-    IDirectSoundImpl* pDS;
-    TRACE("(%p)\n",ppDS);
+    if (pds == NULL) {
+        ERR("invalid parameter: pds == NULL\n");
+        *ppds = NULL;
+        return DSERR_INVALIDPARAM;
+    }
 
-    /* Allocate memory */
-    pDS = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundImpl));
-    if (pDS == NULL) {
+    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
+    if (pdsds == NULL) {
         WARN("out of memory\n");
-        *ppDS = NULL;
+        *ppds = NULL;
         return DSERR_OUTOFMEMORY;
     }
 
-    pDS->lpVtbl = &IDirectSoundImpl_Vtbl;
-    pDS->ref    = 0;
-    pDS->device = NULL;
+    pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
+    pdsds->ref = 0;
+    pdsds->pds = pds;
 
-    *ppDS = (LPDIRECTSOUND8)pDS;
+    IDirectSoundImpl_AddRef(pds);
+    *ppds = (LPDIRECTSOUND)pdsds;
 
     return DS_OK;
 }
 
 /*******************************************************************************
- *             IDirectSound_IUnknown
+ *             IDirectSound8_IDirectSound8
  */
-static HRESULT WINAPI IDirectSound_IUnknown_QueryInterface(
-    LPUNKNOWN iface,
+static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
+    LPDIRECTSOUND8 iface,
     REFIID riid,
     LPVOID * ppobj)
 {
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-    return DSOUND_QueryInterface(This->pds, riid, ppobj);
+    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
 }
 
-static ULONG WINAPI IDirectSound_IUnknown_AddRef(
-    LPUNKNOWN iface)
+static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
+    LPDIRECTSOUND8 iface)
 {
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
-static ULONG WINAPI IDirectSound_IUnknown_Release(
-    LPUNKNOWN iface)
+static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
+    LPDIRECTSOUND8 iface)
 {
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
     if (!ref) {
+        ((IDirectSoundImpl*)This->pds)->pDS8 = NULL;
         IDirectSoundImpl_Release(This->pds);
         HeapFree(GetProcessHeap(), 0, This);
         TRACE("(%p) released\n", This);
@@ -1061,812 +849,978 @@ static ULONG WINAPI IDirectSound_IUnknown_Release(
     return ref;
 }
 
-static const IUnknownVtbl DirectSound_Unknown_Vtbl =
+static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
 {
-    IDirectSound_IUnknown_QueryInterface,
-    IDirectSound_IUnknown_AddRef,
-    IDirectSound_IUnknown_Release
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,dsbd,ppdsb,lpunk,TRUE);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
+    LPDIRECTSOUND8 iface,
+    LPDSCAPS lpDSCaps)
+{
+    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(((IDirectSoundImpl *)This->pds)->device, lpDSCaps);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(((IDirectSoundImpl *)This->pds)->device,psb,ppdsb);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
+    LPDIRECTSOUND8 iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(((IDirectSoundImpl *)This->pds)->device, hwnd, level);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(((IDirectSoundImpl *)This->pds)->device);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,lpdwSpeakerConfig);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    DWORD config)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(((IDirectSoundImpl *)This->pds)->device,config);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
+    LPDIRECTSOUND8 iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&((IDirectSoundImpl *)This->pds)->device,lpcGuid);
+}
+
+static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
+    LPDIRECTSOUND8 iface,
+    LPDWORD pdwCertified)
+{
+    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
+    TRACE("(%p, %p)\n", This, pdwCertified);
+    return DirectSoundDevice_VerifyCertification(((IDirectSoundImpl *)This->pds)->device,pdwCertified);
+}
+
+static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
+{
+    IDirectSound8_IDirectSound8_QueryInterface,
+    IDirectSound8_IDirectSound8_AddRef,
+    IDirectSound8_IDirectSound8_Release,
+    IDirectSound8_IDirectSound8_CreateSoundBuffer,
+    IDirectSound8_IDirectSound8_GetCaps,
+    IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
+    IDirectSound8_IDirectSound8_SetCooperativeLevel,
+    IDirectSound8_IDirectSound8_Compact,
+    IDirectSound8_IDirectSound8_GetSpeakerConfig,
+    IDirectSound8_IDirectSound8_SetSpeakerConfig,
+    IDirectSound8_IDirectSound8_Initialize,
+    IDirectSound8_IDirectSound8_VerifyCertification
 };
 
-HRESULT WINAPI IDirectSound_IUnknown_Create(
+static HRESULT IDirectSound8_IDirectSound8_Create(
     LPDIRECTSOUND8 pds,
-    LPUNKNOWN * ppunk)
+    LPDIRECTSOUND8 * ppds)
+{
+    IDirectSound8_IDirectSound8 * pdsds;
+    TRACE("(%p,%p)\n",pds,ppds);
+
+    if (ppds == NULL) {
+        ERR("invalid parameter: ppds == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (pds == NULL) {
+        ERR("invalid parameter: pds == NULL\n");
+        *ppds = NULL;
+        return DSERR_INVALIDPARAM;
+    }
+
+    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
+    if (pdsds == NULL) {
+        WARN("out of memory\n");
+        *ppds = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
+    pdsds->ref = 0;
+    pdsds->pds = pds;
+
+    IDirectSoundImpl_AddRef(pds);
+    *ppds = (LPDIRECTSOUND8)pdsds;
+
+    return DS_OK;
+}
+
+HRESULT DSOUND_Create(
+    REFIID riid,
+    LPDIRECTSOUND *ppDS)
+{
+    LPDIRECTSOUND8 pDS;
+    HRESULT hr;
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
+
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSound)) {
+        *ppDS = 0;
+        return E_NOINTERFACE;
+    }
+
+    /* Get dsound configuration */
+    setup_dsound_options();
+
+    hr = IDirectSoundImpl_Create(&pDS);
+    if (hr == DS_OK) {
+        hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
+        if (*ppDS)
+            IDirectSound_IDirectSound_AddRef(*ppDS);
+        else {
+            WARN("IDirectSound_IDirectSound_Create failed\n");
+            IDirectSound8_Release(pDS);
+        }
+    } else {
+        WARN("IDirectSoundImpl_Create failed\n");
+        *ppDS = 0;
+    }
+
+    return hr;
+}
+
+/*******************************************************************************
+ *             DirectSoundCreate (DSOUND.1)
+ *
+ *  Creates and initializes a DirectSound interface.
+ *
+ *  PARAMS
+ *     lpcGUID   [I] Address of the GUID that identifies the sound device.
+ *     ppDS      [O] Address of a variable to receive the interface pointer.
+ *     pUnkOuter [I] Must be NULL.
+ *
+ *  RETURNS
+ *     Success: DS_OK
+ *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
+ *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
+ */
+HRESULT WINAPI DirectSoundCreate(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUND *ppDS,
+    IUnknown *pUnkOuter)
 {
-    IDirectSound_IUnknown * pdsunk;
-    TRACE("(%p,%p)\n",pds,ppunk);
+    HRESULT hr;
+    LPDIRECTSOUND pDS;
 
-    if (ppunk == NULL) {
-        ERR("invalid parameter: ppunk == NULL\n");
+    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
+
+    if (ppDS == NULL) {
+        WARN("invalid parameter: ppDS == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (pds == NULL) {
-        ERR("invalid parameter: pds == NULL\n");
-        *ppunk = NULL;
+    if (pUnkOuter != NULL) {
+        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDS = 0;
         return DSERR_INVALIDPARAM;
     }
 
-    pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
-    if (pdsunk == NULL) {
-        WARN("out of memory\n");
-        *ppunk = NULL;
-        return DSERR_OUTOFMEMORY;
+    hr = DSOUND_Create(&IID_IDirectSound, &pDS);
+    if (hr == DS_OK) {
+        hr = IDirectSound_Initialize(pDS, lpcGUID);
+        if (hr != DS_OK) {
+            if (hr != DSERR_ALREADYINITIALIZED) {
+                IDirectSound_Release(pDS);
+                pDS = 0;
+            } else
+                hr = DS_OK;
+        }
     }
 
-    pdsunk->lpVtbl = &DirectSound_Unknown_Vtbl;
-    pdsunk->ref = 0;
-    pdsunk->pds = pds;
-
-    IDirectSoundImpl_AddRef(pds);
-    *ppunk = (LPUNKNOWN)pdsunk;
+    *ppDS = pDS;
 
-    return DS_OK;
+    return hr;
 }
 
-/*******************************************************************************
- *             IDirectSound_IDirectSound
- */
-static HRESULT WINAPI IDirectSound_IDirectSound_QueryInterface(
-    LPDIRECTSOUND iface,
+HRESULT DSOUND_Create8(
     REFIID riid,
-    LPVOID * ppobj)
+    LPDIRECTSOUND8 *ppDS)
 {
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-    return DSOUND_QueryInterface(This->pds, riid, ppobj);
-}
+    LPDIRECTSOUND8 pDS;
+    HRESULT hr;
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDS);
 
-static ULONG WINAPI IDirectSound_IDirectSound_AddRef(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSound) &&
+        !IsEqualIID(riid, &IID_IDirectSound8)) {
+        *ppDS = 0;
+        return E_NOINTERFACE;
+    }
 
-static ULONG WINAPI IDirectSound_IDirectSound_Release(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    if (!ref) {
-        IDirectSoundImpl_Release(This->pds);
-        HeapFree(GetProcessHeap(), 0, This);
-        TRACE("(%p) released\n", This);
+    /* Get dsound configuration */
+    setup_dsound_options();
+
+    hr = IDirectSoundImpl_Create(&pDS);
+    if (hr == DS_OK) {
+        hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
+        if (*ppDS)
+            IDirectSound8_IDirectSound8_AddRef(*ppDS);
+        else {
+            WARN("IDirectSound8_IDirectSound8_Create failed\n");
+            IDirectSound8_Release(pDS);
+        }
+    } else {
+        WARN("IDirectSoundImpl_Create failed\n");
+        *ppDS = 0;
     }
-    return ref;
-}
 
-static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer(
-    LPDIRECTSOUND iface,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
-    return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,FALSE);
+    return hr;
 }
 
-static HRESULT WINAPI IDirectSound_IDirectSound_GetCaps(
-    LPDIRECTSOUND iface,
-    LPDSCAPS lpDSCaps)
+/*******************************************************************************
+ *        DirectSoundCreate8 (DSOUND.11)
+ *
+ *  Creates and initializes a DirectSound8 interface.
+ *
+ *  PARAMS
+ *     lpcGUID   [I] Address of the GUID that identifies the sound device.
+ *     ppDS      [O] Address of a variable to receive the interface pointer.
+ *     pUnkOuter [I] Must be NULL.
+ *
+ *  RETURNS
+ *     Success: DS_OK
+ *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
+ *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
+ */
+HRESULT WINAPI DirectSoundCreate8(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUND8 *ppDS,
+    IUnknown *pUnkOuter)
 {
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,%p)\n",This,lpDSCaps);
-    return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
-}
+    HRESULT hr;
+    LPDIRECTSOUND8 pDS;
 
-static HRESULT WINAPI IDirectSound_IDirectSound_DuplicateSoundBuffer(
-    LPDIRECTSOUND iface,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
-    return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
-}
+    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
 
-static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel(
-    LPDIRECTSOUND iface,
-    HWND hwnd,
-    DWORD level)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
-    return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
-}
+    if (ppDS == NULL) {
+        WARN("invalid parameter: ppDS == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound_IDirectSound_Compact(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p)\n", This);
-    return IDirectSoundImpl_Compact(This->pds);
-}
+    if (pUnkOuter != NULL) {
+        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDS = 0;
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound_IDirectSound_GetSpeakerConfig(
-    LPDIRECTSOUND iface,
-    LPDWORD lpdwSpeakerConfig)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
-    return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
-}
+    hr = DSOUND_Create8(&IID_IDirectSound8, &pDS);
+    if (hr == DS_OK) {
+        hr = IDirectSound8_Initialize(pDS, lpcGUID);
+        if (hr != DS_OK) {
+            if (hr != DSERR_ALREADYINITIALIZED) {
+                IDirectSound8_Release(pDS);
+                pDS = 0;
+            } else
+                hr = DS_OK;
+        }
+    }
 
-static HRESULT WINAPI IDirectSound_IDirectSound_SetSpeakerConfig(
-    LPDIRECTSOUND iface,
-    DWORD config)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p,0x%08lx)\n",This,config);
-    return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
-}
+    *ppDS = pDS;
 
-static HRESULT WINAPI IDirectSound_IDirectSound_Initialize(
-    LPDIRECTSOUND iface,
-    LPCGUID lpcGuid)
-{
-    IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface;
-    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
-    return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
+    return hr;
 }
 
-static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl =
-{
-    IDirectSound_IDirectSound_QueryInterface,
-    IDirectSound_IDirectSound_AddRef,
-    IDirectSound_IDirectSound_Release,
-    IDirectSound_IDirectSound_CreateSoundBuffer,
-    IDirectSound_IDirectSound_GetCaps,
-    IDirectSound_IDirectSound_DuplicateSoundBuffer,
-    IDirectSound_IDirectSound_SetCooperativeLevel,
-    IDirectSound_IDirectSound_Compact,
-    IDirectSound_IDirectSound_GetSpeakerConfig,
-    IDirectSound_IDirectSound_SetSpeakerConfig,
-    IDirectSound_IDirectSound_Initialize
-};
-
-HRESULT WINAPI IDirectSound_IDirectSound_Create(
-    LPDIRECTSOUND8  pds,
-    LPDIRECTSOUND * ppds)
+/*******************************************************************************
+ *        DirectSoundDevice
+ */
+static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
 {
-    IDirectSound_IDirectSound * pdsds;
-    TRACE("(%p,%p)\n",pds,ppds);
+    DirectSoundDevice * device;
+    TRACE("(%p)\n", ppDevice);
 
-    if (ppds == NULL) {
-        ERR("invalid parameter: ppds == NULL\n");
-        return DSERR_INVALIDPARAM;
+    /* Allocate memory */
+    device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
+    if (device == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
     }
 
-    if (pds == NULL) {
-        ERR("invalid parameter: pds == NULL\n");
-        *ppds = NULL;
-        return DSERR_INVALIDPARAM;
-    }
+    device->ref            = 1;
+    device->priolevel      = DSSCL_NORMAL;
+    device->state          = STATE_STOPPED;
+    device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
 
-    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
-    if (pdsds == NULL) {
+    /* 3D listener initial parameters */
+    device->ds3dl.dwSize   = sizeof(DS3DLISTENER);
+    device->ds3dl.vPosition.x = 0.0;
+    device->ds3dl.vPosition.y = 0.0;
+    device->ds3dl.vPosition.z = 0.0;
+    device->ds3dl.vVelocity.x = 0.0;
+    device->ds3dl.vVelocity.y = 0.0;
+    device->ds3dl.vVelocity.z = 0.0;
+    device->ds3dl.vOrientFront.x = 0.0;
+    device->ds3dl.vOrientFront.y = 0.0;
+    device->ds3dl.vOrientFront.z = 1.0;
+    device->ds3dl.vOrientTop.x = 0.0;
+    device->ds3dl.vOrientTop.y = 1.0;
+    device->ds3dl.vOrientTop.z = 0.0;
+    device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR;
+    device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
+    device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
+
+    device->prebuf = ds_snd_queue_max;
+    device->guid = GUID_NULL;
+
+    /* Set default wave format (may need it for waveOutOpen) */
+    device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX));
+    if (device->pwfx == NULL) {
         WARN("out of memory\n");
-        *ppds = NULL;
+        HeapFree(GetProcessHeap(),0,device);
         return DSERR_OUTOFMEMORY;
     }
 
-    pdsds->lpVtbl = &DirectSound_DirectSound_Vtbl;
-    pdsds->ref = 0;
-    pdsds->pds = pds;
+    /* We rely on the sound driver to return the actual sound format of
+     * the device if it does not support 22050x8x2 and is given the
+     * WAVE_DIRECTSOUND flag.
+     */
+    device->pwfx->wFormatTag = WAVE_FORMAT_PCM;
+    device->pwfx->nSamplesPerSec = ds_default_sample_rate;
+    device->pwfx->wBitsPerSample = ds_default_bits_per_sample;
+    device->pwfx->nChannels = 2;
+    device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8;
+    device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign;
+    device->pwfx->cbSize = 0;
 
-    IDirectSoundImpl_AddRef(pds);
-    *ppds = (LPDIRECTSOUND)pdsds;
+    InitializeCriticalSection(&(device->mixlock));
+    device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
 
-    return DS_OK;
-}
+    RtlInitializeResource(&(device->buffer_list_lock));
 
-/*******************************************************************************
- *             IDirectSound8_IUnknown
- */
-static HRESULT WINAPI IDirectSound8_IUnknown_QueryInterface(
-    LPUNKNOWN iface,
-    REFIID riid,
-    LPVOID * ppobj)
-{
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
-}
+   *ppDevice = device;
 
-static ULONG WINAPI IDirectSound8_IUnknown_AddRef(
-    LPUNKNOWN iface)
-{
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
+    return DS_OK;
 }
 
-static ULONG WINAPI IDirectSound8_IUnknown_Release(
-    LPUNKNOWN iface)
+static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
 {
-    IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    if (!ref) {
-        IDirectSoundImpl_Release(This->pds);
-        HeapFree(GetProcessHeap(), 0, This);
-        TRACE("(%p) released\n", This);
-    }
+    ULONG ref = InterlockedIncrement(&(device->ref));
+    TRACE("(%p) ref was %d\n", device, ref - 1);
     return ref;
 }
 
-static const IUnknownVtbl DirectSound8_Unknown_Vtbl =
-{
-    IDirectSound8_IUnknown_QueryInterface,
-    IDirectSound8_IUnknown_AddRef,
-    IDirectSound8_IUnknown_Release
-};
-
-HRESULT WINAPI IDirectSound8_IUnknown_Create(
-    LPDIRECTSOUND8 pds,
-    LPUNKNOWN * ppunk)
+ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
 {
-    IDirectSound8_IUnknown * pdsunk;
-    TRACE("(%p,%p)\n",pds,ppunk);
+    HRESULT hr;
+    ULONG ref = InterlockedDecrement(&(device->ref));
+    TRACE("(%p) ref was %u\n", device, ref + 1);
+    if (!ref) {
+        int i;
+        timeKillEvent(device->timerID);
+        timeEndPeriod(DS_TIME_RES);
 
-    if (ppunk == NULL) {
-        ERR("invalid parameter: ppunk == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+        /* The kill event should have allowed the timer process to expire
+         * but try to grab the lock just in case. Can't hold lock because
+         * IDirectSoundBufferImpl_Destroy also grabs the lock */
+        RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE);
+        RtlReleaseResource(&(device->buffer_list_lock));
 
-    if (pds == NULL) {
-        ERR("invalid parameter: pds == NULL\n");
-        *ppunk = NULL;
-        return DSERR_INVALIDPARAM;
-    }
+        /* It is allowed to release this object even when buffers are playing */
+        if (device->buffers) {
+            WARN("%d secondary buffers not released\n", device->nrofbuffers);
+            for( i=0;i<device->nrofbuffers;i++)
+                IDirectSoundBufferImpl_Destroy(device->buffers[i]);
+        }
 
-    pdsunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsunk));
-    if (pdsunk == NULL) {
-        WARN("out of memory\n");
-        *ppunk = NULL;
-        return DSERR_OUTOFMEMORY;
-    }
+        if (device->primary) {
+            WARN("primary buffer not released\n");
+            IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary);
+        }
 
-    pdsunk->lpVtbl = &DirectSound8_Unknown_Vtbl;
-    pdsunk->ref = 0;
-    pdsunk->pds = pds;
+        hr = DSOUND_PrimaryDestroy(device);
+        if (hr != DS_OK)
+            WARN("DSOUND_PrimaryDestroy failed\n");
 
-    IDirectSoundImpl_AddRef(pds);
-    *ppunk = (LPUNKNOWN)pdsunk;
+        if (device->driver)
+            IDsDriver_Close(device->driver);
 
-    return DS_OK;
-}
+        if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN)
+            waveOutClose(device->hwo);
 
-/*******************************************************************************
- *             IDirectSound8_IDirectSound
- */
-static HRESULT WINAPI IDirectSound8_IDirectSound_QueryInterface(
-    LPDIRECTSOUND iface,
-    REFIID riid,
-    LPVOID * ppobj)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
-}
+        if (device->driver)
+            IDsDriver_Release(device->driver);
 
-static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
+        DSOUND_renderer[device->drvdesc.dnDevNode] = NULL;
 
-static ULONG WINAPI IDirectSound8_IDirectSound_Release(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    if (!ref) {
-        IDirectSoundImpl_Release(This->pds);
-        HeapFree(GetProcessHeap(), 0, This);
-        TRACE("(%p) released\n", This);
+        HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
+        HeapFree(GetProcessHeap(), 0, device->mix_buffer);
+        if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
+            HeapFree(GetProcessHeap(), 0, device->buffer);
+        RtlDeleteResource(&device->buffer_list_lock);
+        device->mixlock.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&device->mixlock);
+        HeapFree(GetProcessHeap(),0,device);
+        TRACE("(%p) released\n", device);
     }
     return ref;
 }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer(
-    LPDIRECTSOUND iface,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
-    return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,TRUE);
-}
-
-static HRESULT WINAPI IDirectSound8_IDirectSound_GetCaps(
-    LPDIRECTSOUND iface,
+HRESULT DirectSoundDevice_GetCaps(
+    DirectSoundDevice * device,
     LPDSCAPS lpDSCaps)
 {
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%p)\n",This,lpDSCaps);
-    return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
-}
+    TRACE("(%p,%p)\n",device,lpDSCaps);
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_DuplicateSoundBuffer(
-    LPDIRECTSOUND iface,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
-    return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
-}
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel(
-    LPDIRECTSOUND iface,
-    HWND hwnd,
-    DWORD level)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
-    return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
-}
+    if (lpDSCaps == NULL) {
+        WARN("invalid parameter: lpDSCaps = NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_Compact(
-    LPDIRECTSOUND iface)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p)\n", This);
-    return IDirectSoundImpl_Compact(This->pds);
-}
+    /* check if there is enough room */
+    if (lpDSCaps->dwSize < sizeof(*lpDSCaps)) {
+        WARN("invalid parameter: lpDSCaps->dwSize = %d\n", lpDSCaps->dwSize);
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_GetSpeakerConfig(
-    LPDIRECTSOUND iface,
-    LPDWORD lpdwSpeakerConfig)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
-    return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
-}
+    lpDSCaps->dwFlags                           = device->drvcaps.dwFlags;
+    if (TRACE_ON(dsound)) {
+        TRACE("(flags=0x%08x:\n",lpDSCaps->dwFlags);
+        _dump_DSCAPS(lpDSCaps->dwFlags);
+        TRACE(")\n");
+    }
+    lpDSCaps->dwMinSecondarySampleRate          = device->drvcaps.dwMinSecondarySampleRate;
+    lpDSCaps->dwMaxSecondarySampleRate          = device->drvcaps.dwMaxSecondarySampleRate;
+    lpDSCaps->dwPrimaryBuffers                  = device->drvcaps.dwPrimaryBuffers;
+    lpDSCaps->dwMaxHwMixingAllBuffers           = device->drvcaps.dwMaxHwMixingAllBuffers;
+    lpDSCaps->dwMaxHwMixingStaticBuffers        = device->drvcaps.dwMaxHwMixingStaticBuffers;
+    lpDSCaps->dwMaxHwMixingStreamingBuffers     = device->drvcaps.dwMaxHwMixingStreamingBuffers;
+    lpDSCaps->dwFreeHwMixingAllBuffers          = device->drvcaps.dwFreeHwMixingAllBuffers;
+    lpDSCaps->dwFreeHwMixingStaticBuffers       = device->drvcaps.dwFreeHwMixingStaticBuffers;
+    lpDSCaps->dwFreeHwMixingStreamingBuffers    = device->drvcaps.dwFreeHwMixingStreamingBuffers;
+    lpDSCaps->dwMaxHw3DAllBuffers               = device->drvcaps.dwMaxHw3DAllBuffers;
+    lpDSCaps->dwMaxHw3DStaticBuffers            = device->drvcaps.dwMaxHw3DStaticBuffers;
+    lpDSCaps->dwMaxHw3DStreamingBuffers         = device->drvcaps.dwMaxHw3DStreamingBuffers;
+    lpDSCaps->dwFreeHw3DAllBuffers              = device->drvcaps.dwFreeHw3DAllBuffers;
+    lpDSCaps->dwFreeHw3DStaticBuffers           = device->drvcaps.dwFreeHw3DStaticBuffers;
+    lpDSCaps->dwFreeHw3DStreamingBuffers        = device->drvcaps.dwFreeHw3DStreamingBuffers;
+    lpDSCaps->dwTotalHwMemBytes                 = device->drvcaps.dwTotalHwMemBytes;
+    lpDSCaps->dwFreeHwMemBytes                  = device->drvcaps.dwFreeHwMemBytes;
+    lpDSCaps->dwMaxContigFreeHwMemBytes         = device->drvcaps.dwMaxContigFreeHwMemBytes;
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_SetSpeakerConfig(
-    LPDIRECTSOUND iface,
-    DWORD config)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,0x%08lx)\n",This,config);
-    return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
-}
+    /* driver doesn't have these */
+    lpDSCaps->dwUnlockTransferRateHwBuffers     = 4096; /* But we have none... */
+    lpDSCaps->dwPlayCpuOverheadSwBuffers        = 1;    /* 1% */
 
-static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize(
-    LPDIRECTSOUND iface,
-    LPCGUID lpcGuid)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
-    return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
+    return DS_OK;
 }
 
-static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl =
+HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
 {
-    IDirectSound8_IDirectSound_QueryInterface,
-    IDirectSound8_IDirectSound_AddRef,
-    IDirectSound8_IDirectSound_Release,
-    IDirectSound8_IDirectSound_CreateSoundBuffer,
-    IDirectSound8_IDirectSound_GetCaps,
-    IDirectSound8_IDirectSound_DuplicateSoundBuffer,
-    IDirectSound8_IDirectSound_SetCooperativeLevel,
-    IDirectSound8_IDirectSound_Compact,
-    IDirectSound8_IDirectSound_GetSpeakerConfig,
-    IDirectSound8_IDirectSound_SetSpeakerConfig,
-    IDirectSound8_IDirectSound_Initialize
-};
+    HRESULT hr = DS_OK;
+    unsigned wod, wodn;
+    BOOLEAN found = FALSE;
+    GUID devGUID;
+    DirectSoundDevice * device = *ppDevice;
+    TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
+
+    if (*ppDevice != NULL) {
+        WARN("already initialized\n");
+        return DSERR_ALREADYINITIALIZED;
+    }
 
-HRESULT WINAPI IDirectSound8_IDirectSound_Create(
-    LPDIRECTSOUND8 pds,
-    LPDIRECTSOUND * ppds)
-{
-    IDirectSound8_IDirectSound * pdsds;
-    TRACE("(%p,%p)\n",pds,ppds);
+    /* Default device? */
+    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
+        lpcGUID = &DSDEVID_DefaultPlayback;
 
-    if (ppds == NULL) {
-        ERR("invalid parameter: ppds == NULL\n");
+    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
+        WARN("invalid parameter: lpcGUID\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (pds == NULL) {
-        ERR("invalid parameter: pds == NULL\n");
-        *ppds = NULL;
-        return DSERR_INVALIDPARAM;
+    /* Enumerate WINMM audio devices and find the one we want */
+    wodn = waveOutGetNumDevs();
+    if (!wodn) {
+        WARN("no driver\n");
+        return DSERR_NODRIVER;
     }
 
-    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
-    if (pdsds == NULL) {
-        WARN("out of memory\n");
-        *ppds = NULL;
-        return DSERR_OUTOFMEMORY;
+    for (wod=0; wod<wodn; wod++) {
+        if (IsEqualGUID( &devGUID, &DSOUND_renderer_guids[wod])) {
+            found = TRUE;
+            break;
+        }
     }
 
-    pdsds->lpVtbl = &DirectSound8_DirectSound_Vtbl;
-    pdsds->ref = 0;
-    pdsds->pds = pds;
+    if (found == FALSE) {
+        WARN("No device found matching given ID!\n");
+        return DSERR_NODRIVER;
+    }
 
-    IDirectSoundImpl_AddRef(pds);
-    *ppds = (LPDIRECTSOUND)pdsds;
+    if (DSOUND_renderer[wod]) {
+        if (IsEqualGUID(&devGUID, &DSOUND_renderer[wod]->guid)) {
+            device = DSOUND_renderer[wod];
+            DirectSoundDevice_AddRef(device);
+            *ppDevice = device;
+            return DS_OK;
+        } else {
+            ERR("device GUID doesn't match\n");
+            hr = DSERR_GENERIC;
+            return hr;
+        }
+    } else {
+        hr = DirectSoundDevice_Create(&device);
+        if (hr != DS_OK) {
+            WARN("DirectSoundDevice_Create failed\n");
+            return hr;
+        }
+    }
 
-    return DS_OK;
-}
+    *ppDevice = device;
+    device->guid = devGUID;
+    device->driver = NULL;
 
-/*******************************************************************************
- *             IDirectSound8_IDirectSound8
- */
-static HRESULT WINAPI IDirectSound8_IDirectSound8_QueryInterface(
-    LPDIRECTSOUND8 iface,
-    REFIID riid,
-    LPVOID * ppobj)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
-    return DSOUND_QueryInterface8(This->pds, riid, ppobj);
-}
+    device->drvdesc.dnDevNode = wod;
+    hr = DSOUND_ReopenDevice(device, FALSE);
+    if (FAILED(hr))
+    {
+        WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
+        return hr;
+    }
 
-static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(
-    LPDIRECTSOUND8 iface)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
+    if (device->driver) {
+        /* the driver is now open, so it's now allowed to call GetCaps */
+        hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps));
+        if (hr != DS_OK) {
+            WARN("IDsDriver_GetCaps failed\n");
+            return hr;
+        }
+    } else {
+        WAVEOUTCAPSA woc;
+        hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc)));
+        if (hr != DS_OK) {
+            WARN("waveOutGetDevCaps failed\n");
+            return hr;
+        }
+        ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
+        if ((woc.dwFormats & WAVE_FORMAT_1M08) ||
+            (woc.dwFormats & WAVE_FORMAT_2M08) ||
+            (woc.dwFormats & WAVE_FORMAT_4M08) ||
+            (woc.dwFormats & WAVE_FORMAT_48M08) ||
+            (woc.dwFormats & WAVE_FORMAT_96M08)) {
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
+        }
+        if ((woc.dwFormats & WAVE_FORMAT_1M16) ||
+            (woc.dwFormats & WAVE_FORMAT_2M16) ||
+            (woc.dwFormats & WAVE_FORMAT_4M16) ||
+            (woc.dwFormats & WAVE_FORMAT_48M16) ||
+            (woc.dwFormats & WAVE_FORMAT_96M16)) {
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO;
+        }
+        if ((woc.dwFormats & WAVE_FORMAT_1S08) ||
+            (woc.dwFormats & WAVE_FORMAT_2S08) ||
+            (woc.dwFormats & WAVE_FORMAT_4S08) ||
+            (woc.dwFormats & WAVE_FORMAT_48S08) ||
+            (woc.dwFormats & WAVE_FORMAT_96S08)) {
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT;
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
+        }
+        if ((woc.dwFormats & WAVE_FORMAT_1S16) ||
+            (woc.dwFormats & WAVE_FORMAT_2S16) ||
+            (woc.dwFormats & WAVE_FORMAT_4S16) ||
+            (woc.dwFormats & WAVE_FORMAT_48S16) ||
+            (woc.dwFormats & WAVE_FORMAT_96S16)) {
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT;
+            device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO;
+        }
+        if (ds_emuldriver)
+            device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER;
+        device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
+        device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
+        ZeroMemory(&device->volpan, sizeof(device->volpan));
+    }
 
-static ULONG WINAPI IDirectSound8_IDirectSound8_Release(
-    LPDIRECTSOUND8 iface)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    if (!ref) {
-        IDirectSoundImpl_Release(This->pds);
-        HeapFree(GetProcessHeap(), 0, This);
-        TRACE("(%p) released\n", This);
+    hr = DSOUND_PrimaryCreate(device);
+    if (hr == DS_OK) {
+        UINT triggertime = DS_TIME_DEL, res = DS_TIME_RES, id;
+        TIMECAPS time;
+
+        DSOUND_renderer[device->drvdesc.dnDevNode] = device;
+        timeGetDevCaps(&time, sizeof(TIMECAPS));
+        TRACE("Minimum timer resolution: %u, max timer: %u\n", time.wPeriodMin, time.wPeriodMax);
+        if (triggertime < time.wPeriodMin)
+            triggertime = time.wPeriodMin;
+        if (res < time.wPeriodMin)
+            res = time.wPeriodMin;
+        if (timeBeginPeriod(res) == TIMERR_NOCANDO)
+            WARN("Could not set minimum resolution, don't expect sound\n");
+        id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
+        if (!id)
+        {
+            WARN("Timer not created! Retrying without TIME_KILL_SYNCHRONOUS\n");
+            id = timeSetEvent(triggertime, res, DSOUND_timer, (DWORD_PTR)device, TIME_PERIODIC);
+            if (!id) ERR("Could not create timer, sound playback will not occur\n");
+        }
+        DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = id;
+    } else {
+        WARN("DSOUND_PrimaryCreate failed\n");
     }
-    return ref;
+
+    return hr;
 }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer(
-    LPDIRECTSOUND8 iface,
+HRESULT DirectSoundDevice_CreateSoundBuffer(
+    DirectSoundDevice * device,
     LPCDSBUFFERDESC dsbd,
     LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk)
+    LPUNKNOWN lpunk,
+    BOOL from8)
 {
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
-    return DSOUND_CreateSoundBuffer(This->pds,dsbd,ppdsb,lpunk,TRUE);
-}
+    HRESULT hres = DS_OK;
+    TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_GetCaps(
-    LPDIRECTSOUND8 iface,
-    LPDSCAPS lpDSCaps)
-{
-    IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface;
-    TRACE("(%p,%p)\n",This,lpDSCaps);
-    return IDirectSoundImpl_GetCaps(This->pds, lpDSCaps);
-}
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_DuplicateSoundBuffer(
-    LPDIRECTSOUND8 iface,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
-    return IDirectSoundImpl_DuplicateSoundBuffer(This->pds,psb,ppdsb);
-}
+    if (dsbd == NULL) {
+        WARN("invalid parameter: dsbd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel(
-    LPDIRECTSOUND8 iface,
-    HWND hwnd,
-    DWORD level)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
-    return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level);
-}
+    if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
+        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
+        WARN("invalid parameter: dsbd\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_Compact(
-    LPDIRECTSOUND8 iface)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p)\n", This);
-    return IDirectSoundImpl_Compact(This->pds);
-}
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+    *ppdsb = NULL;
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_GetSpeakerConfig(
-    LPDIRECTSOUND8 iface,
-    LPDWORD lpdwSpeakerConfig)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
-    return IDirectSoundImpl_GetSpeakerConfig(This->pds,lpdwSpeakerConfig);
-}
+    if (TRACE_ON(dsound)) {
+        TRACE("(structsize=%d)\n",dsbd->dwSize);
+        TRACE("(flags=0x%08x:\n",dsbd->dwFlags);
+        _dump_DSBCAPS(dsbd->dwFlags);
+        TRACE(")\n");
+        TRACE("(bufferbytes=%d)\n",dsbd->dwBufferBytes);
+        TRACE("(lpwfxFormat=%p)\n",dsbd->lpwfxFormat);
+    }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_SetSpeakerConfig(
-    LPDIRECTSOUND8 iface,
-    DWORD config)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p,0x%08lx)\n",This,config);
-    return IDirectSoundImpl_SetSpeakerConfig(This->pds,config);
-}
+    if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
+        if (dsbd->lpwfxFormat != NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
+                 "primary buffer\n");
+            return DSERR_INVALIDPARAM;
+        }
+
+        if (device->primary) {
+            WARN("Primary Buffer already created\n");
+            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
+            *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
+        } else {
+           device->dsbd = *dsbd;
+           device->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
+           if (device->hwbuf)
+               device->dsbd.dwFlags |= DSBCAPS_LOCHARDWARE;
+           else device->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
+           hres = PrimaryBufferImpl_Create(device, &(device->primary), &(device->dsbd));
+           if (device->primary) {
+               IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
+               *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
+           } else
+               WARN("PrimaryBufferImpl_Create failed\n");
+        }
+    } else {
+        IDirectSoundBufferImpl * dsb;
+        WAVEFORMATEXTENSIBLE *pwfxe;
+
+        if (dsbd->lpwfxFormat == NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
+                 "secondary buffer\n");
+            return DSERR_INVALIDPARAM;
+        }
+        pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
+
+        if (pwfxe->Format.wBitsPerSample != 16 && pwfxe->Format.wBitsPerSample != 8 && pwfxe->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+        {
+            WARN("wBitsPerSample=%d needs a WAVEFORMATEXTENSIBLE\n", dsbd->lpwfxFormat->wBitsPerSample);
+            return DSERR_CONTROLUNAVAIL;
+        }
+        if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+        {
+            if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
+            {
+                WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
+                return DSERR_INVALIDPARAM;
+            }
+
+            if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
+            {
+                WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
+                return DSERR_CONTROLUNAVAIL;
+            }
+
+            if (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
+            {
+                if (!IsEqualGUID(&pwfxe->SubFormat, &GUID_NULL))
+                    FIXME("SubFormat %s not supported right now.\n", debugstr_guid(&pwfxe->SubFormat));
+                return DSERR_INVALIDPARAM;
+            }
+            if (pwfxe->Samples.wValidBitsPerSample > dsbd->lpwfxFormat->wBitsPerSample)
+            {
+                WARN("Samples.wValidBitsPerSample(%d) > Format.wBitsPerSample (%d)\n", pwfxe->Samples.wValidBitsPerSample, pwfxe->Format.wBitsPerSample);
+                return DSERR_INVALIDPARAM;
+            }
+            if (pwfxe->Samples.wValidBitsPerSample && pwfxe->Samples.wValidBitsPerSample < dsbd->lpwfxFormat->wBitsPerSample)
+            {
+                FIXME("Non-packed formats not supported right now: %d/%d\n", pwfxe->Samples.wValidBitsPerSample, dsbd->lpwfxFormat->wBitsPerSample);
+                return DSERR_CONTROLUNAVAIL;
+            }
+        }
+
+        TRACE("(formattag=0x%04x,chans=%d,samplerate=%d,"
+              "bytespersec=%d,blockalign=%d,bitspersamp=%d,cbSize=%d)\n",
+              dsbd->lpwfxFormat->wFormatTag, dsbd->lpwfxFormat->nChannels,
+              dsbd->lpwfxFormat->nSamplesPerSec,
+              dsbd->lpwfxFormat->nAvgBytesPerSec,
+              dsbd->lpwfxFormat->nBlockAlign,
+              dsbd->lpwfxFormat->wBitsPerSample, dsbd->lpwfxFormat->cbSize);
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_Initialize(
-    LPDIRECTSOUND8 iface,
-    LPCGUID lpcGuid)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
-    return IDirectSoundImpl_Initialize(This->pds,lpcGuid);
-}
+        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
+            WARN("invalid parameter: 3D buffer format must be mono\n");
+            return DSERR_INVALIDPARAM;
+        }
 
-static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification(
-    LPDIRECTSOUND8 iface,
-    LPDWORD pdwCertified)
-{
-    IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface;
-    TRACE("(%p, %p)\n", This, pdwCertified);
-    return IDirectSoundImpl_VerifyCertification(This->pds,pdwCertified);
+        hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
+        if (dsb) {
+            hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
+            if (*ppdsb) {
+                dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
+                IDirectSoundBuffer_AddRef(*ppdsb);
+            } else
+                WARN("SecondaryBufferImpl_Create failed\n");
+        } else
+           WARN("IDirectSoundBufferImpl_Create failed\n");
+   }
+
+   return hres;
 }
 
-static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl =
+HRESULT DirectSoundDevice_DuplicateSoundBuffer(
+    DirectSoundDevice * device,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
 {
-    IDirectSound8_IDirectSound8_QueryInterface,
-    IDirectSound8_IDirectSound8_AddRef,
-    IDirectSound8_IDirectSound8_Release,
-    IDirectSound8_IDirectSound8_CreateSoundBuffer,
-    IDirectSound8_IDirectSound8_GetCaps,
-    IDirectSound8_IDirectSound8_DuplicateSoundBuffer,
-    IDirectSound8_IDirectSound8_SetCooperativeLevel,
-    IDirectSound8_IDirectSound8_Compact,
-    IDirectSound8_IDirectSound8_GetSpeakerConfig,
-    IDirectSound8_IDirectSound8_SetSpeakerConfig,
-    IDirectSound8_IDirectSound8_Initialize,
-    IDirectSound8_IDirectSound8_VerifyCertification
-};
+    HRESULT hres = DS_OK;
+    IDirectSoundBufferImpl* dsb;
+    TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
 
-HRESULT WINAPI IDirectSound8_IDirectSound8_Create(
-    LPDIRECTSOUND8 pds,
-    LPDIRECTSOUND8 * ppds)
-{
-    IDirectSound8_IDirectSound8 * pdsds;
-    TRACE("(%p,%p)\n",pds,ppds);
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    if (ppds == NULL) {
-        ERR("invalid parameter: ppds == NULL\n");
+    if (psb == NULL) {
+        WARN("invalid parameter: psb == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (pds == NULL) {
-        ERR("invalid parameter: pds == NULL\n");
-        *ppds = NULL;
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    pdsds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsds));
-    if (pdsds == NULL) {
-        WARN("out of memory\n");
-        *ppds = NULL;
-        return DSERR_OUTOFMEMORY;
+    /* make sure we have a secondary buffer */
+    if ((PrimaryBufferImpl *)psb == device->primary) {
+        WARN("trying to duplicate primary buffer\n");
+        *ppdsb = NULL;
+        return DSERR_INVALIDCALL;
     }
 
-    pdsds->lpVtbl = &DirectSound8_DirectSound8_Vtbl;
-    pdsds->ref = 0;
-    pdsds->pds = pds;
+    /* duplicate the actual buffer implementation */
+    hres = IDirectSoundBufferImpl_Duplicate(device, &dsb,
+                                           ((SecondaryBufferImpl *)psb)->dsb);
 
-    IDirectSoundImpl_AddRef(pds);
-    *ppds = (LPDIRECTSOUND8)pdsds;
+    if (hres == DS_OK) {
+        /* create a new secondary buffer using the new implementation */
+        hres = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl**)ppdsb);
+        if (*ppdsb) {
+            dsb->secondary = (SecondaryBufferImpl*)*ppdsb;
+            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)*ppdsb);
+        } else {
+            WARN("SecondaryBufferImpl_Create failed\n");
+            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
+            IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)dsb);
+        }
+    }
 
-    return DS_OK;
+    return hres;
 }
 
-HRESULT WINAPI DSOUND_Create(
-    LPDIRECTSOUND *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_SetCooperativeLevel(
+    DirectSoundDevice * device,
+    HWND hwnd,
+    DWORD level)
 {
-    LPDIRECTSOUND8 pDS;
-    HRESULT hr;
-    TRACE("(%p,%p)\n",ppDS,pUnkOuter);
+    TRACE("(%p,%p,%s)\n",device,hwnd,dumpCooperativeLevel(level));
 
-    /* Get dsound configuration */
-    setup_dsound_options();
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    hr = IDirectSoundImpl_Create(&pDS);
-    if (hr == DS_OK) {
-        hr = IDirectSound_IDirectSound_Create(pDS, ppDS);
-        if (*ppDS)
-            IDirectSound_IDirectSound_AddRef(*ppDS);
-        else {
-            WARN("IDirectSound_IDirectSound_Create failed\n");
-            IDirectSound8_Release(pDS);
-        }
-    } else {
-        WARN("IDirectSoundImpl_Create failed\n");
-        *ppDS = 0;
+    if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) {
+        WARN("level=%s not fully supported\n",
+             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
     }
 
-    return hr;
+    device->priolevel = level;
+    return DS_OK;
 }
 
-/*******************************************************************************
- *             DirectSoundCreate (DSOUND.1)
- *
- *  Creates and initializes a DirectSound interface.
- *
- *  PARAMS
- *     lpcGUID   [I] Address of the GUID that identifies the sound device.
- *     ppDS      [O] Address of a variable to receive the interface pointer.
- *     pUnkOuter [I] Must be NULL.
- *
- *  RETURNS
- *     Success: DS_OK
- *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
- *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
- */
-HRESULT WINAPI DirectSoundCreate(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_Compact(
+    DirectSoundDevice * device)
 {
-    HRESULT hr;
-    LPDIRECTSOUND pDS;
-
-    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
-
-    if (ppDS == NULL) {
-        WARN("invalid parameter: ppDS == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    TRACE("(%p)\n", device);
 
-    if (pUnkOuter != NULL) {
-        WARN("invalid parameter: pUnkOuter != NULL\n");
-        *ppDS = 0;
-        return DSERR_INVALIDPARAM;
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
 
-    hr = DSOUND_Create(&pDS, pUnkOuter);
-    if (hr == DS_OK) {
-        hr = IDirectSound_Initialize(pDS, lpcGUID);
-        if (hr != DS_OK) {
-            if (hr != DSERR_ALREADYINITIALIZED) {
-                IDirectSound_Release(pDS);
-                pDS = 0;
-            } else
-                hr = DS_OK;
-        }
+    if (device->priolevel < DSSCL_PRIORITY) {
+        WARN("incorrect priority level\n");
+        return DSERR_PRIOLEVELNEEDED;
     }
 
-    *ppDS = pDS;
-
-    return hr;
+    return DS_OK;
 }
 
-HRESULT WINAPI DSOUND_Create8(
-    LPDIRECTSOUND8 *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_GetSpeakerConfig(
+    DirectSoundDevice * device,
+    LPDWORD lpdwSpeakerConfig)
 {
-    LPDIRECTSOUND8 pDS;
-    HRESULT hr;
-    TRACE("(%p,%p)\n",ppDS,pUnkOuter);
+    TRACE("(%p, %p)\n", device, lpdwSpeakerConfig);
 
-    /* Get dsound configuration */
-    setup_dsound_options();
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    hr = IDirectSoundImpl_Create(&pDS);
-    if (hr == DS_OK) {
-        hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS);
-        if (*ppDS)
-            IDirectSound8_IDirectSound8_AddRef(*ppDS);
-        else {
-            WARN("IDirectSound8_IDirectSound8_Create failed\n");
-            IDirectSound8_Release(pDS);
-        }
-    } else {
-        WARN("IDirectSoundImpl_Create failed\n");
-        *ppDS = 0;
+    if (lpdwSpeakerConfig == NULL) {
+        WARN("invalid parameter: lpdwSpeakerConfig == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    return hr;
+    WARN("not fully functional\n");
+    *lpdwSpeakerConfig = device->speaker_config;
+    return DS_OK;
 }
 
-/*******************************************************************************
- *        DirectSoundCreate8 (DSOUND.11)
- *
- *  Creates and initializes a DirectSound8 interface.
- *
- *  PARAMS
- *     lpcGUID   [I] Address of the GUID that identifies the sound device.
- *     ppDS      [O] Address of a variable to receive the interface pointer.
- *     pUnkOuter [I] Must be NULL.
- *
- *  RETURNS
- *     Success: DS_OK
- *     Failure: DSERR_ALLOCATED, DSERR_INVALIDPARAM, DSERR_NOAGGREGATION,
- *              DSERR_NODRIVER, DSERR_OUTOFMEMORY
- */
-HRESULT WINAPI DirectSoundCreate8(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND8 *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_SetSpeakerConfig(
+    DirectSoundDevice * device,
+    DWORD config)
 {
-    HRESULT hr;
-    LPDIRECTSOUND8 pDS;
-
-    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
+    TRACE("(%p,0x%08x)\n",device,config);
 
-    if (ppDS == NULL) {
-        WARN("invalid parameter: ppDS == NULL\n");
-        return DSERR_INVALIDPARAM;
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
 
-    if (pUnkOuter != NULL) {
-        WARN("invalid parameter: pUnkOuter != NULL\n");
-        *ppDS = 0;
-        return DSERR_INVALIDPARAM;
-    }
+    device->speaker_config = config;
+    WARN("not fully functional\n");
+    return DS_OK;
+}
 
-    hr = DSOUND_Create8(&pDS, pUnkOuter);
-    if (hr == DS_OK) {
-        hr = IDirectSound8_Initialize(pDS, lpcGUID);
-        if (hr != DS_OK) {
-            if (hr != DSERR_ALREADYINITIALIZED) {
-                IDirectSound8_Release(pDS);
-                pDS = 0;
-            } else
-                hr = DS_OK;
-        }
+static HRESULT DirectSoundDevice_VerifyCertification(
+    DirectSoundDevice * device,
+    LPDWORD pdwCertified)
+{
+    TRACE("(%p, %p)\n",device,pdwCertified);
+
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
 
-    *ppDS = pDS;
+    if (device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
+        *pdwCertified = DS_CERTIFIED;
+    else
+        *pdwCertified = DS_UNCERTIFIED;
 
-    return hr;
+    return DS_OK;
 }
 
 /*
  * Add secondary buffer to buffer list.
  * Gets exclusive access to buffer for writing.
  */
-HRESULT DSOUND_AddBuffer(
-    IDirectSoundImpl * pDS,
+HRESULT DirectSoundDevice_AddBuffer(
+    DirectSoundDevice * device,
     IDirectSoundBufferImpl * pDSB)
 {
     IDirectSoundBufferImpl **newbuffers;
     HRESULT hr = DS_OK;
 
-    TRACE("(%p, %p)\n", pDS, pDSB);
+    TRACE("(%p, %p)\n", device, pDSB);
 
-    RtlAcquireResourceExclusive(&(pDS->device->buffer_list_lock), TRUE);
+    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 
-    if (pDS->device->buffers)
-        newbuffers = HeapReAlloc(GetProcessHeap(),0,pDS->device->buffers,sizeof(IDirectSoundBufferImpl*)*(pDS->device->nrofbuffers+1));
+    if (device->buffers)
+        newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
     else
-        newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(pDS->device->nrofbuffers+1));
+        newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
 
     if (newbuffers) {
-        pDS->device->buffers = newbuffers;
-        pDS->device->buffers[pDS->device->nrofbuffers] = pDSB;
-        pDS->device->nrofbuffers++;
-        TRACE("buffer count is now %d\n", pDS->device->nrofbuffers);
+        device->buffers = newbuffers;
+        device->buffers[device->nrofbuffers] = pDSB;
+        device->nrofbuffers++;
+        TRACE("buffer count is now %d\n", device->nrofbuffers);
     } else {
-        ERR("out of memory for buffer list! Current buffer count is %d\n", pDS->device->nrofbuffers);
+        ERR("out of memory for buffer list! Current buffer count is %d\n", device->nrofbuffers);
         hr = DSERR_OUTOFMEMORY;
     }
 
-    RtlReleaseResource(&(pDS->device->buffer_list_lock));
+    RtlReleaseResource(&(device->buffer_list_lock));
 
     return hr;
 }
@@ -1875,35 +1829,35 @@ HRESULT DSOUND_AddBuffer(
  * Remove secondary buffer from buffer list.
  * Gets exclusive access to buffer for writing.
  */
-HRESULT DSOUND_RemoveBuffer(
-    IDirectSoundImpl * pDS,
+HRESULT DirectSoundDevice_RemoveBuffer(
+    DirectSoundDevice * device,
     IDirectSoundBufferImpl * pDSB)
 {
     int i;
     HRESULT hr = DS_OK;
 
-    TRACE("(%p, %p)\n", pDS, pDSB);
+    TRACE("(%p, %p)\n", device, pDSB);
 
-    RtlAcquireResourceExclusive(&(pDS->device->buffer_list_lock), TRUE);
+    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 
-    for (i = 0; i < pDS->device->nrofbuffers; i++)
-        if (pDS->device->buffers[i] == pDSB)
+    for (i = 0; i < device->nrofbuffers; i++)
+        if (device->buffers[i] == pDSB)
             break;
 
-    if (i < pDS->device->nrofbuffers) {
+    if (i < device->nrofbuffers) {
         /* Put the last buffer of the list in the (now empty) position */
-        pDS->device->buffers[i] = pDS->device->buffers[pDS->device->nrofbuffers - 1];
-        pDS->device->nrofbuffers--;
-        pDS->device->buffers = HeapReAlloc(GetProcessHeap(),0,pDS->device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*pDS->device->nrofbuffers);
-        TRACE("buffer count is now %d\n", pDS->device->nrofbuffers);
+        device->buffers[i] = device->buffers[device->nrofbuffers - 1];
+        device->nrofbuffers--;
+        device->buffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*device->nrofbuffers);
+        TRACE("buffer count is now %d\n", device->nrofbuffers);
     }
 
-    if (pDS->device->nrofbuffers == 0) {
-        HeapFree(GetProcessHeap(),0,pDS->device->buffers);
-        pDS->device->buffers = NULL;
+    if (device->nrofbuffers == 0) {
+        HeapFree(GetProcessHeap(),0,device->buffers);
+        device->buffers = NULL;
     }
 
-    RtlReleaseResource(&(pDS->device->buffer_list_lock));
+    RtlReleaseResource(&(device->buffer_list_lock));
 
     return hr;
 }
index 6123c42..c76e412 100644 (file)
@@ -18,6 +18,7 @@
        <file>buffer.c</file>
        <file>capture.c</file>
        <file>dsound.c</file>
+       <file>dsound_convert.c</file>
        <file>dsound_main.c</file>
        <file>duplex.c</file>
        <file>mixer.c</file>
        <file>propset.c</file>
        <file>regsvr.c</file>
        <file>sound3d.c</file>
-       <directory name="dxroslayer">
-               <file>dxrosdrv_querydsounddesc.c</file>
-               <file>dxrosdrv_querydsoundiface.c</file>
-               <file>dxroslayer.c</file>
-               <file>getguidfromstring.c</file>
-       </directory>
 </module>
diff --git a/reactos/dll/directx/dsound/dsound_convert.c b/reactos/dll/directx/dsound/dsound_convert.c
new file mode 100644 (file)
index 0000000..0a6e474
--- /dev/null
@@ -0,0 +1,435 @@
+/* DirectSound format conversion and mixing routines
+ *
+ * Copyright 2007 Maarten Lankhorst
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* 8 bits is unsigned, the rest is signed.
+ * First I tried to reuse existing stuff from alsa-lib, after that
+ * didn't work, I gave up and just went for individual hacks.
+ *
+ * 24 bit is expensive to do, due to unaligned access.
+ * In dlls/winex11.drv/dib_convert.c convert_888_to_0888_asis there is a way
+ * around it, but I'm happy current code works, maybe something for later.
+ *
+ * The ^ 0x80 flips the signed bit, this is the conversion from
+ * signed (-128.. 0.. 127) to unsigned (0...255)
+ * This is only temporary: All 8 bit data should be converted to signed.
+ * then when fed to the sound card, it should be converted to unsigned again.
+ *
+ * Sound is LITTLE endian
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+#include "windef.h"
+#include "winbase.h"
+#include "mmsystem.h"
+#include "winternl.h"
+#include "wine/debug.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "dsound_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dsound);
+
+#ifdef WORDS_BIGENDIAN
+#define le16(x) RtlUshortByteSwap((x))
+#define le32(x) RtlUlongByteSwap((x))
+#else
+#define le16(x) (x)
+#define le32(x) (x)
+#endif
+
+static inline void src_advance(const void **src, UINT stride, INT *count, UINT *freqAcc, UINT adj)
+{
+    *freqAcc += adj;
+    if (*freqAcc >= (1 << DSOUND_FREQSHIFT))
+    {
+        ULONG adv = (*freqAcc >> DSOUND_FREQSHIFT);
+        *freqAcc &= (1 << DSOUND_FREQSHIFT) - 1;
+        *(const char **)src += adv * stride;
+        *count -= adv;
+    }
+}
+
+static void convert_8_to_8 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        *(BYTE *)dst = *(const BYTE *)src;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_8_to_16 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        WORD dest = *(const BYTE *)src, *dest16 = dst;
+        *dest16 = le16(dest * 257 - 32768);
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_8_to_24 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        BYTE dest = *(const BYTE *)src;
+        BYTE *dest24 = dst;
+        dest24[0] = dest;
+        dest24[1] = dest;
+        dest24[2] = dest - 0x80;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_8_to_32 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        DWORD dest = *(const BYTE *)src, *dest32 = dst;
+        *dest32 = le32(dest * 16843009 - 2147483648U);
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_16_to_8 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        BYTE *dst8 = dst;
+        *dst8 = (le16(*(const WORD *)src)) / 256;
+        *dst8 -= 0x80;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_16_to_16 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        *(WORD *)dst = *(const WORD *)src;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_16_to_24 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        WORD dest = le16(*(const WORD *)src);
+        BYTE *dest24 = dst;
+
+        dest24[0] = dest / 256;
+        dest24[1] = dest;
+        dest24[2] = dest / 256;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_16_to_32 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        DWORD dest = *(const WORD *)src, *dest32 = dst;
+        *dest32 = dest * 65537;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_24_to_8 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        BYTE *dst8 = dst;
+        *dst8 = ((const BYTE *)src)[2];
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_24_to_16 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        WORD *dest16 = dst;
+        const BYTE *source = src;
+        *dest16 = le16(source[2] * 256 + source[1]);
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_24_to_24 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        BYTE *dest24 = dst;
+        const BYTE *src24 = src;
+
+        dest24[0] = src24[0];
+        dest24[1] = src24[1];
+        dest24[2] = src24[2];
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_24_to_32 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        DWORD *dest32 = dst;
+        const BYTE *source = src;
+        *dest32 = le32(source[2] * 16777217 + source[1] * 65536 + source[0] * 256);
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_32_to_8 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        BYTE *dst8 = dst;
+        *dst8 = (le32(*(const DWORD *)src) / 16777216);
+        *dst8 -= 0x80;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_32_to_16 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        WORD *dest16 = dst;
+        *dest16 = le16(le32(*(const DWORD *)src) / 65536);
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_32_to_24 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        DWORD dest = le32(*(const DWORD *)src);
+        BYTE *dest24 = dst;
+
+        dest24[0] = dest / 256;
+        dest24[1] = dest / 65536;
+        dest24[2] = dest / 16777216;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+static void convert_32_to_32 (const void *src, void *dst, UINT src_stride,
+        UINT dst_stride, INT count, UINT freqAcc, UINT adj)
+{
+    while (count > 0)
+    {
+        DWORD *dest = dst;
+        *dest = *(const DWORD *)src;
+
+        dst = (char *)dst + dst_stride;
+        src_advance(&src, src_stride, &count, &freqAcc, adj);
+    }
+}
+
+const bitsconvertfunc convertbpp[4][4] = {
+    { convert_8_to_8, convert_8_to_16, convert_8_to_24, convert_8_to_32 },
+    { convert_16_to_8, convert_16_to_16, convert_16_to_24, convert_16_to_32 },
+    { convert_24_to_8, convert_24_to_16, convert_24_to_24, convert_24_to_32 },
+    { convert_32_to_8, convert_32_to_16, convert_32_to_24, convert_32_to_32 },
+};
+
+static void mix8(signed char *src, INT *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    while (len--)
+        /* 8-bit WAV is unsigned, it's here converted to signed, normalize function will convert it back again */
+        *(dst++) += (signed char)((BYTE)*(src++) - (BYTE)0x80);
+}
+
+static void mix16(SHORT *src, INT *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 2;
+    while (len--)
+    {
+        *dst += le16(*src);
+        ++dst; ++src;
+    }
+}
+
+static void mix24(BYTE *src, INT *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 3;
+    while (len--)
+    {
+        DWORD field;
+        field = ((DWORD)src[2] << 16) + ((DWORD)src[1] << 8) + (DWORD)src[0];
+        if (src[2] & 0x80)
+            field |= 0xFF000000U;
+        *(dst++) += field;
+        ++src;
+    }
+}
+
+static void mix32(INT *src, LONGLONG *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 4;
+    while (len--)
+        *(dst++) += le32(*(src++));
+}
+
+const mixfunc mixfunctions[4] = {
+    (mixfunc)mix8,
+    (mixfunc)mix16,
+    (mixfunc)mix24,
+    (mixfunc)mix32
+};
+
+static void norm8(INT *src, signed char *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    while (len--)
+    {
+        *dst = (*src) + 0x80;
+        if (*src < -0x80)
+            *dst = 0;
+        else if (*src > 0x7f)
+            *dst = 0xff;
+        ++dst;
+        ++src;
+    }
+}
+
+static void norm16(INT *src, SHORT *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 2;
+    while (len--)
+    {
+        *dst = le16(*src);
+        if (*src <= -0x8000)
+            *dst = le16(0x8000);
+        else if (*src > 0x7fff)
+            *dst = le16(0x7fff);
+        ++dst;
+        ++src;
+    }
+}
+
+static void norm24(INT *src, BYTE *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 3;
+    while (len--)
+    {
+        if (*src <= -0x800000)
+        {
+            dst[0] = 0;
+            dst[1] = 0;
+            dst[2] = 0x80;
+        }
+        else if (*src > 0x7fffff)
+        {
+            dst[0] = 0xff;
+            dst[1] = 0xff;
+            dst[2] = 0x7f;
+        }
+        else
+        {
+            dst[0] = *src;
+            dst[1] = *src >> 8;
+            dst[2] = *src >> 16;
+        }
+        ++dst;
+        ++src;
+    }
+}
+
+static void norm32(LONGLONG *src, INT *dst, unsigned len)
+{
+    TRACE("%p - %p %d\n", src, dst, len);
+    len /= 4;
+    while (len--)
+    {
+        *dst = le32(*src);
+        if (*src <= -(LONGLONG)0x80000000)
+            *dst = le32(0x80000000);
+        else if (*src > 0x7fffffff)
+            *dst = le32(0x7fffffff);
+        ++dst;
+        ++src;
+    }
+}
+
+const normfunc normfunctions[4] = {
+    (normfunc)norm8,
+    (normfunc)norm16,
+    (normfunc)norm24,
+    (normfunc)norm32,
+};
index f8b763f..44897bc 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
  * Most thread locking is complete. There may be a few race
  * conditions still lurking.
  *
- * Tested with a Soundblaster clone, a Gravis UltraSound Classic,
- * and a Turtle Beach Tropez+.
- *
  * TODO:
  *     Implement SetCooperativeLevel properly (need to address focus issues)
  *     Implement DirectSound3DBuffers (stubs in place)
@@ -32,8 +28,8 @@
  *      Add critical section locking inside Release and AddRef methods
  *      Handle static buffers - put those in hardware, non-static not in hardware
  *      Hardware DuplicateSoundBuffer
- *      Proper volume calculation, and setting volume in HEL primary buffer
- *      Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN
+ *      Proper volume calculation for 3d buffers
+ *      Remove DS_HEL_FRAGS and use mixer fragment length for it
  */
 
 #include <stdarg.h>
@@ -43,6 +39,7 @@
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "winnls.h"
 #include "winreg.h"
 #include "mmsystem.h"
 #include "mmddk.h"
 #include "wine/debug.h"
 #include "dsound.h"
+#include "dsconf.h"
+#include "ks.h"
+#include "initguid.h"
+#include "ksmedia.h"
 #include "dsdriver.h"
+
 #include "dsound_private.h"
-#include "dsconf.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-/* these are eligible for tuning... they must be high on slow machines... */
-/* some stuff may get more responsive with lower values though... */
-#define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept
-                               emulated dsound devices. set to 0 ! */
-#define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers
-                        * (keep this close or equal to DS_HEL_QUEUE for best results) */
-#define DS_HEL_QUEUE  5 /* HEL only: number of waveOut fragments ahead to queue to driver
-                        * (this will affect HEL sound reliability and latency) */
-
-#define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */
-#define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */
-
 DirectSoundDevice*     DSOUND_renderer[MAXWAVEDRIVERS];
 GUID                    DSOUND_renderer_guids[MAXWAVEDRIVERS];
 GUID                    DSOUND_capture_guids[MAXWAVEDRIVERS];
@@ -99,20 +88,23 @@ HRESULT mmErr(UINT err)
        }
 }
 
-int ds_emuldriver = DS_EMULDRIVER;
-int ds_hel_margin = DS_HEL_MARGIN;
-int ds_hel_queue = DS_HEL_QUEUE;
-int ds_snd_queue_max = DS_SND_QUEUE_MAX;
-int ds_snd_queue_min = DS_SND_QUEUE_MIN;
+/* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */
+int ds_emuldriver = 0;
+int ds_hel_buflen = 32768 * 2;
+int ds_snd_queue_max = 10;
+int ds_snd_queue_min = 6;
+int ds_snd_shadow_maxsize = 2;
 int ds_hw_accel = DS_HW_ACCEL_FULL;
-int ds_default_playback = 0;
-int ds_default_capture = 0;
+int ds_default_sample_rate = 44100;
+int ds_default_bits_per_sample = 16;
+static int ds_default_playback;
+static int ds_default_capture;
 
 /*
  * Get a config key from either the app-specific or the default config
  */
 
-inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
+static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
                                     char *buffer, DWORD size )
 {
     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
@@ -147,7 +139,7 @@ void setup_dsound_options(void)
             if ((p = strrchr( appname, '/' ))) appname = p + 1;
             if ((p = strrchr( appname, '\\' ))) appname = p + 1;
             strcat( appname, "\\DirectSound" );
-            TRACE("appname = [%s] \n",appname);
+            TRACE("appname = [%s]\n", appname);
             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
             RegCloseKey( tmpkey );
         }
@@ -158,11 +150,8 @@ void setup_dsound_options(void)
     if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH ))
         ds_emuldriver = strcmp(buffer, "N");
 
-    if (!get_config_key( hkey, appkey, "HELmargin", buffer, MAX_PATH ))
-        ds_hel_margin = atoi(buffer);
-
-    if (!get_config_key( hkey, appkey, "HELqueue", buffer, MAX_PATH ))
-        ds_hel_queue = atoi(buffer);
+    if (!get_config_key( hkey, appkey, "HelBuflen", buffer, MAX_PATH ))
+        ds_hel_buflen = atoi(buffer);
 
     if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
         ds_snd_queue_max = atoi(buffer);
@@ -180,42 +169,43 @@ void setup_dsound_options(void)
        else if (strcmp(buffer, "Emulation") == 0)
            ds_hw_accel = DS_HW_ACCEL_EMULATION;
     }
-       FIXME("dsound is hardcoded to software emulation until we fix it in ros\n");
-    ds_hw_accel = DS_HW_ACCEL_EMULATION;
 
     if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH ))
-           ds_default_playback = atoi(buffer);
+        ds_default_playback = atoi(buffer);
+
+    if (!get_config_key( hkey, appkey, "MaxShadowSize", buffer, MAX_PATH ))
+        ds_snd_shadow_maxsize = atoi(buffer);
 
     if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH ))
-           ds_default_capture = atoi(buffer);
+        ds_default_capture = atoi(buffer);
+
+    if (!get_config_key( hkey, appkey, "DefaultSampleRate", buffer, MAX_PATH ))
+        ds_default_sample_rate = atoi(buffer);
+
+    if (!get_config_key( hkey, appkey, "DefaultBitsPerSample", buffer, MAX_PATH ))
+        ds_default_bits_per_sample = atoi(buffer);
 
     if (appkey) RegCloseKey( appkey );
     if (hkey) RegCloseKey( hkey );
 
-    if (ds_emuldriver != DS_EMULDRIVER )
-       WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver, DS_EMULDRIVER);
-    if (ds_hel_margin != DS_HEL_MARGIN )
-       WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin, DS_HEL_MARGIN );
-    if (ds_hel_queue != DS_HEL_QUEUE )
-       WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE );
-    if (ds_snd_queue_max != DS_SND_QUEUE_MAX)
-       WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX);
-    if (ds_snd_queue_min != DS_SND_QUEUE_MIN)
-       WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN);
-    if (ds_hw_accel != DS_HW_ACCEL_FULL)
-       WARN("ds_hw_accel = %s (default=Full)\n",
-           ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
-           ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" :
-           ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" :
-           ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" :
-           "Unknown");
-    if (ds_default_playback != 0)
-       WARN("ds_default_playback = %d (default=0)\n",ds_default_playback);
-    if (ds_default_capture != 0)
-       WARN("ds_default_capture = %d (default=0)\n",ds_default_playback);
+    TRACE("ds_emuldriver = %d\n", ds_emuldriver);
+    TRACE("ds_hel_buflen = %d\n", ds_hel_buflen);
+    TRACE("ds_snd_queue_max = %d\n", ds_snd_queue_max);
+    TRACE("ds_snd_queue_min = %d\n", ds_snd_queue_min);
+    TRACE("ds_hw_accel = %s\n",
+        ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" :
+        ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" :
+        ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" :
+        ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" :
+        "Unknown");
+    TRACE("ds_default_playback = %d\n", ds_default_playback);
+    TRACE("ds_default_capture = %d\n", ds_default_playback);
+    TRACE("ds_default_sample_rate = %d\n", ds_default_sample_rate);
+    TRACE("ds_default_bits_per_sample = %d\n", ds_default_bits_per_sample);
+    TRACE("ds_snd_shadow_maxsize = %d\n", ds_snd_shadow_maxsize);
 }
 
-const char * get_device_id(LPCGUID pGuid)
+static const char * get_device_id(LPCGUID pGuid)
 {
     if (IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid))
         return "DSDEVID_DefaultPlayback";
@@ -264,19 +254,19 @@ HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest)
 
     if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) ||
         IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) {
-       CopyMemory(pGuidDest, &DSOUND_renderer_guids[ds_default_playback], sizeof(GUID));
+       *pGuidDest = DSOUND_renderer_guids[ds_default_playback];
         TRACE("returns %s\n", get_device_id(pGuidDest));
        return DS_OK;
     }
 
     if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) ||
         IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) {
-       CopyMemory(pGuidDest, &DSOUND_capture_guids[ds_default_capture], sizeof(GUID));
+       *pGuidDest = DSOUND_capture_guids[ds_default_capture];
         TRACE("returns %s\n", get_device_id(pGuidDest));
        return DS_OK;
     }
 
-    CopyMemory(pGuidDest, pGuidSrc, sizeof(GUID));
+    *pGuidDest = *pGuidSrc;
     TRACE("returns %s\n", get_device_id(pGuidDest));
 
     return DS_OK;
@@ -318,11 +308,11 @@ HRESULT WINAPI DirectSoundEnumerateA(
        if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
            for (wod = 0; wod < devs; ++wod) {
                 if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod]) ) {
-                    err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+                    err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
                     if (err == DS_OK) {
                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
-                              "Primary Sound Driver",desc.szDrvname,lpContext);
-                        if (lpDSEnumCallback(NULL, "Primary Sound Driver", desc.szDrvname, lpContext) == FALSE)
+                              "Primary Sound Driver","",lpContext);
+                        if (lpDSEnumCallback(NULL, "Primary Sound Driver", "", lpContext) == FALSE)
                             return DS_OK;
                    }
                }
@@ -331,7 +321,7 @@ HRESULT WINAPI DirectSoundEnumerateA(
     }
 
     for (wod = 0; wod < devs; ++wod) {
-       err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+        err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
        if (err == DS_OK) {
             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
                   debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext);
@@ -377,17 +367,16 @@ HRESULT WINAPI DirectSoundEnumerateW(
     devs = waveOutGetNumDevs();
     if (devs > 0) {
        if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) {
+            static const WCHAR empty[] = { 0 };
            for (wod = 0; wod < devs; ++wod) {
                 if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) {
-                    err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+                    err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
                     if (err == DS_OK) {
                         TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n",
                               "Primary Sound Driver",desc.szDrvname,lpContext);
                         MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1,
                                              wDesc, sizeof(wDesc)/sizeof(WCHAR) );
-                        MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1,
-                                             wName, sizeof(wName)/sizeof(WCHAR) );
-                        if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE)
+                        if (lpDSEnumCallback(NULL, wDesc, empty, lpContext) == FALSE)
                             return DS_OK;
                    }
                }
@@ -396,7 +385,7 @@ HRESULT WINAPI DirectSoundEnumerateW(
     }
 
     for (wod = 0; wod < devs; ++wod) {
-       err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
+        err = mmErr(waveOutMessage(UlongToHandle(wod),DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0));
        if (err == DS_OK) {
             TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n",
                   debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext);
@@ -415,19 +404,38 @@ HRESULT WINAPI DirectSoundEnumerateW(
  * DirectSound ClassFactory
  */
 
-static HRESULT WINAPI
-DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+typedef  HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
+typedef struct {
+    const IClassFactoryVtbl *lpVtbl;
+    LONG ref;
+    REFCLSID rclsid;
+    FnCreateInstance pfnCreateInstance;
+} IClassFactoryImpl;
 
-       FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
-       return E_NOINTERFACE;
+static HRESULT WINAPI
+DSCF_QueryInterface(LPCLASSFACTORY iface, REFIID riid, LPVOID *ppobj)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj);
+    if (ppobj == NULL)
+        return E_POINTER;
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IClassFactory))
+    {
+        *ppobj = iface;
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+    *ppobj = NULL;
+    return E_NOINTERFACE;
 }
 
 static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface)
 {
     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
     ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
     return ref;
 }
 
@@ -435,120 +443,55 @@ static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface)
 {
     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
+    TRACE("(%p) ref was %d\n", This, ref + 1);
     /* static class, won't be freed */
     return ref;
 }
 
 static HRESULT WINAPI DSCF_CreateInstance(
-       LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
-) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-       TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
-
-       if (pOuter)
-               return CLASS_E_NOAGGREGATION;
-
-       if (ppobj == NULL) {
-               WARN("invalid parameter\n");
-               return DSERR_INVALIDPARAM;
-       }
-
-       *ppobj = NULL;
-
-       if ( IsEqualIID( &IID_IDirectSound, riid ) )
-               return DSOUND_Create((LPDIRECTSOUND*)ppobj,pOuter);
-
-       if ( IsEqualIID( &IID_IDirectSound8, riid ) )
-               return DSOUND_Create8((LPDIRECTSOUND8*)ppobj,pOuter);
-
-       WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
-       return E_NOINTERFACE;
-}
-
-static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-       FIXME("(%p)->(%d),stub!\n",This,dolock);
-       return S_OK;
-}
-
-static const IClassFactoryVtbl DSCF_Vtbl = {
-       DSCF_QueryInterface,
-       DSCF_AddRef,
-       DSCF_Release,
-       DSCF_CreateInstance,
-       DSCF_LockServer
-};
-
-static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 };
-
-/*******************************************************************************
- * DirectSoundPrivate ClassFactory
- */
-
-static HRESULT WINAPI
-DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-
-       FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
-       return E_NOINTERFACE;
-}
-
-static ULONG WINAPI DSPCF_AddRef(LPCLASSFACTORY iface)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
-}
-
-static ULONG WINAPI DSPCF_Release(LPCLASSFACTORY iface)
+    LPCLASSFACTORY iface,
+    LPUNKNOWN pOuter,
+    REFIID riid,
+    LPVOID *ppobj)
 {
     IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref + 1);
-    /* static class, won't be freed */
-    return ref;
-}
-
-static HRESULT WINAPI
-DSPCF_CreateInstance(
-       LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
-) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-       TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
-
-       if (ppobj == NULL) {
-               WARN("invalid parameter\n");
-               return DSERR_INVALIDPARAM;
-       }
-
-       *ppobj = NULL;
+    TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj);
 
-       if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
-               return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl**)ppobj);
-       }
+    if (pOuter)
+        return CLASS_E_NOAGGREGATION;
 
-       WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
-       return E_NOINTERFACE;
+    if (ppobj == NULL) {
+        WARN("invalid parameter\n");
+        return DSERR_INVALIDPARAM;
+    }
+    *ppobj = NULL;
+    return This->pfnCreateInstance(riid, ppobj);
 }
-
-static HRESULT WINAPI
-DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
-       IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-       FIXME("(%p)->(%d),stub!\n",This,dolock);
-       return S_OK;
+static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
+{
+    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    FIXME("(%p, %d) stub!\n", This, dolock);
+    return S_OK;
 }
 
-static const IClassFactoryVtbl DSPCF_Vtbl = {
-       DSPCF_QueryInterface,
-       DSPCF_AddRef,
-       DSPCF_Release,
-       DSPCF_CreateInstance,
-       DSPCF_LockServer
+static const IClassFactoryVtbl DSCF_Vtbl = {
+    DSCF_QueryInterface,
+    DSCF_AddRef,
+    DSCF_Release,
+    DSCF_CreateInstance,
+    DSCF_LockServer
 };
 
-static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 };
+static IClassFactoryImpl DSOUND_CF[] = {
+    { &DSCF_Vtbl, 1, &CLSID_DirectSound, (FnCreateInstance)DSOUND_Create },
+    { &DSCF_Vtbl, 1, &CLSID_DirectSound8, (FnCreateInstance)DSOUND_Create8 },
+    { &DSCF_Vtbl, 1, &CLSID_DirectSoundCapture, (FnCreateInstance)DSOUND_CaptureCreate },
+    { &DSCF_Vtbl, 1, &CLSID_DirectSoundCapture8, (FnCreateInstance)DSOUND_CaptureCreate8 },
+    { &DSCF_Vtbl, 1, &CLSID_DirectSoundFullDuplex, (FnCreateInstance)DSOUND_FullDuplexCreate },
+    { &DSCF_Vtbl, 1, &CLSID_DirectSoundPrivate, (FnCreateInstance)IKsPrivatePropertySetImpl_Create },
+    { NULL, 0, NULL, NULL }
+};
 
 /*******************************************************************************
  * DllGetClassObject [DSOUND.@]
@@ -569,62 +512,33 @@ static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 };
  */
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 {
-    TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+    int i = 0;
+    TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
 
     if (ppv == NULL) {
-       WARN("invalid parameter\n");
-       return E_INVALIDARG;
+        WARN("invalid parameter\n");
+        return E_INVALIDARG;
     }
 
     *ppv = NULL;
 
-    if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) ||
-        IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) {
-       if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
-           *ppv = (LPVOID)&DSOUND_CF;
-           IClassFactory_AddRef((IClassFactory*)*ppv);
-           return S_OK;
-       }
-       WARN("(%s,%s,%p): no interface found.\n",
-           debugstr_guid(rclsid), debugstr_guid(riid), ppv);
-       return S_FALSE;
+    if (!IsEqualIID(riid, &IID_IClassFactory) &&
+        !IsEqualIID(riid, &IID_IUnknown)) {
+        WARN("no interface for %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
     }
 
-    if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) ||
-        IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) {
-       if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
-           *ppv = (LPVOID)&DSOUND_CAPTURE_CF;
-           IClassFactory_AddRef((IClassFactory*)*ppv);
-           return S_OK;
-       }
-       WARN("(%s,%s,%p): no interface found.\n",
-           debugstr_guid(rclsid), debugstr_guid(riid), ppv);
-       return S_FALSE;
-    }
-
-    if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) {
-       if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
-           *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF;
-           IClassFactory_AddRef((IClassFactory*)*ppv);
-           return S_OK;
-       }
-       WARN("(%s,%s,%p): no interface found.\n",
-           debugstr_guid(rclsid), debugstr_guid(riid), ppv);
-       return S_FALSE;
-    }
-
-    if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) {
-       if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) {
-           *ppv = (LPVOID)&DSOUND_PRIVATE_CF;
-           IClassFactory_AddRef((IClassFactory*)*ppv);
-           return S_OK;
-       }
-       WARN("(%s,%s,%p): no interface found.\n",
-           debugstr_guid(rclsid), debugstr_guid(riid), ppv);
-       return S_FALSE;
+    while (NULL != DSOUND_CF[i].rclsid) {
+        if (IsEqualGUID(rclsid, DSOUND_CF[i].rclsid)) {
+            DSCF_AddRef((IClassFactory*) &DSOUND_CF[i]);
+            *ppv = &DSOUND_CF[i];
+            return S_OK;
+        }
+        i++;
     }
 
-    WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+    WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid),
+         debugstr_guid(riid), ppv);
     return CLASS_E_CLASSNOTAVAILABLE;
 }
 
@@ -655,7 +569,7 @@ HRESULT WINAPI DllCanUnloadNow(void)
 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
     int i;
-    TRACE("(%p %ld %p)\n", hInstDLL, fdwReason, lpvReserved);
+    TRACE("(%p %d %p)\n", hInstDLL, fdwReason, lpvReserved);
 
     switch (fdwReason) {
     case DLL_PROCESS_ATTACH:
@@ -666,16 +580,13 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
             INIT_GUID(DSOUND_renderer_guids[i], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
             INIT_GUID(DSOUND_capture_guids[i],  0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i);
         }
+        DisableThreadLibraryCalls(hInstDLL);
+        /* Increase refcount on dsound by 1 */
+        GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstDLL, &hInstDLL);
         break;
     case DLL_PROCESS_DETACH:
         TRACE("DLL_PROCESS_DETACH\n");
         break;
-    case DLL_THREAD_ATTACH:
-        TRACE("DLL_THREAD_ATTACH\n");
-        break;
-    case DLL_THREAD_DETACH:
-        TRACE("DLL_THREAD_DETACH\n");
-        break;
     default:
         TRACE("UNKNOWN REASON\n");
         break;
index 8772e09..221433f 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "dxroslayer/dxros_layer.h"
-
 /* Linux does not support better timing than 10ms */
-#define DS_TIME_RES 10  /* Resolution of multimedia timer */
+#define DS_TIME_RES 2  /* Resolution of multimedia timer */
 #define DS_TIME_DEL 10  /* Delay of multimedia timer callback, and duration of HEL fragment */
 
-#define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer
-                        * (changing this won't help you) */
+#include "wine/list.h"
 
-/* wine spec */
-#include "dxroslayer/dxros_layer.h"
 /* direct sound hardware acceleration levels */
 #define DS_HW_ACCEL_FULL        0      /* default on Windows 98 */
 #define DS_HW_ACCEL_STANDARD    1      /* default on Windows 2000 */
 #define DS_HW_ACCEL_EMULATION   3
 
 extern int ds_emuldriver;
-extern int ds_hel_margin;
-extern int ds_hel_queue;
+extern int ds_hel_buflen;
 extern int ds_snd_queue_max;
 extern int ds_snd_queue_min;
+extern int ds_snd_shadow_maxsize;
 extern int ds_hw_accel;
-extern int ds_default_playback;
-extern int ds_default_capture;
+extern int ds_default_sample_rate;
+extern int ds_default_bits_per_sample;
 
 /*****************************************************************************
  * Predeclare the interface implementation structures
@@ -58,6 +53,10 @@ typedef struct IDirectSoundBufferImpl        IDirectSoundBufferImpl;
 typedef struct IDirectSoundCaptureImpl       IDirectSoundCaptureImpl;
 typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl;
 typedef struct IDirectSoundFullDuplexImpl    IDirectSoundFullDuplexImpl;
+typedef struct IDirectSoundFullDuplex_IUnknown IDirectSoundFullDuplex_IUnknown;
+typedef struct IDirectSoundFullDuplex_IDirectSound IDirectSoundFullDuplex_IDirectSound;
+typedef struct IDirectSoundFullDuplex_IDirectSound8 IDirectSoundFullDuplex_IDirectSound8;
+typedef struct IDirectSoundFullDuplex_IDirectSoundCapture IDirectSoundFullDuplex_IDirectSoundCapture;
 typedef struct IDirectSoundNotifyImpl        IDirectSoundNotifyImpl;
 typedef struct IDirectSoundCaptureNotifyImpl IDirectSoundCaptureNotifyImpl;
 typedef struct IDirectSound3DListenerImpl    IDirectSound3DListenerImpl;
@@ -66,25 +65,20 @@ typedef struct IKsBufferPropertySetImpl      IKsBufferPropertySetImpl;
 typedef struct IKsPrivatePropertySetImpl     IKsPrivatePropertySetImpl;
 typedef struct PrimaryBufferImpl             PrimaryBufferImpl;
 typedef struct SecondaryBufferImpl           SecondaryBufferImpl;
-typedef struct IClassFactoryImpl             IClassFactoryImpl;
 typedef struct DirectSoundDevice             DirectSoundDevice;
 typedef struct DirectSoundCaptureDevice      DirectSoundCaptureDevice;
 
+/* dsound_convert.h */
+typedef void (*bitsconvertfunc)(const void *, void *, UINT, UINT, INT, UINT, UINT);
+extern const bitsconvertfunc convertbpp[4][4];
+typedef void (*mixfunc)(const void *, void *, unsigned);
+extern const mixfunc mixfunctions[4];
+typedef void (*normfunc)(const void *, void *, unsigned);
+extern const normfunc normfunctions[4];
+
 /*****************************************************************************
- * IDirectSound implementation structure
+ * IDirectSoundDevice implementation structure
  */
-struct IDirectSoundImpl
-{
-    /* IUnknown fields */
-    const IDirectSound8Vtbl    *lpVtbl;
-    LONG                        ref;
-
-    DirectSoundDevice          *device;
-    LPUNKNOWN                   pUnknown;
-    LPDIRECTSOUND               pDS;
-    LPDIRECTSOUND8              pDS8;
-};
-
 struct DirectSoundDevice
 {
     LONG                        ref;
@@ -96,13 +90,12 @@ struct DirectSoundDevice
     DWORD                       priolevel;
     PWAVEFORMATEX               pwfx;
     HWAVEOUT                    hwo;
-    LPWAVEHDR                   pwave[DS_HEL_FRAGS];
-    UINT                        timerID, pwplay, pwwrite, pwqueue, prebuf, precount;
+    LPWAVEHDR                   pwave;
+    UINT                        timerID, pwplay, pwqueue, prebuf, helfrags;
     DWORD                       fraglen;
     PIDSDRIVERBUFFER            hwbuf;
     LPBYTE                      buffer;
     DWORD                       writelead, buflen, state, playpos, mixpos;
-    BOOL                        need_remix;
     int                         nrofbuffers;
     IDirectSoundBufferImpl**    buffers;
     RTL_RWLOCK                  buffer_list_lock;
@@ -110,8 +103,13 @@ struct DirectSoundDevice
     PrimaryBufferImpl*          primary;
     DSBUFFERDESC                dsbd;
     DWORD                       speaker_config;
-    LPBYTE                      tmp_buffer;
-    DWORD                       tmp_buffer_len;
+    LPBYTE                      tmp_buffer, mix_buffer;
+    DWORD                       tmp_buffer_len, mix_buffer_len;
+
+    DSVOLUMEPAN                 volpan;
+
+    mixfunc mixfunction;
+    normfunc normfunction;
 
     /* DirectSound3DListener fields */
     IDirectSound3DListenerImpl*        listener;
@@ -124,74 +122,41 @@ typedef struct BufferMemory
 {
     LONG                        ref;
     LPBYTE                      memory;
+    struct list buffers;
 } BufferMemory;
 
-HRESULT WINAPI IDirectSoundImpl_Create(
-    LPDIRECTSOUND8 * ppds);
-
-HRESULT WINAPI DSOUND_Create(
-    LPDIRECTSOUND *ppDS,
-    IUnknown *pUnkOuter);
-
-HRESULT WINAPI DSOUND_Create8(
-    LPDIRECTSOUND8 *ppDS,
-    IUnknown *pUnkOuter);
-
-/*****************************************************************************
- * IDirectSound COM components
- */
-struct IDirectSound_IUnknown {
-    const IUnknownVtbl         *lpVtbl;
-    LONG                        ref;
-    LPDIRECTSOUND8              pds;
-};
-
-HRESULT WINAPI IDirectSound_IUnknown_Create(
-    LPDIRECTSOUND8 pds,
-    LPUNKNOWN * ppunk);
-
-struct IDirectSound_IDirectSound {
-    const IDirectSoundVtbl     *lpVtbl;
-    LONG                        ref;
-    LPDIRECTSOUND8              pds;
-};
-
-HRESULT WINAPI IDirectSound_IDirectSound_Create(
-    LPDIRECTSOUND8 pds,
-    LPDIRECTSOUND * ppds);
-
-/*****************************************************************************
- * IDirectSound8 COM components
- */
-struct IDirectSound8_IUnknown {
-    const IUnknownVtbl         *lpVtbl;
-    LONG                        ref;
-    LPDIRECTSOUND8              pds;
-};
-
-HRESULT WINAPI IDirectSound8_IUnknown_Create(
-    LPDIRECTSOUND8 pds,
-    LPUNKNOWN * ppunk);
-
-struct IDirectSound8_IDirectSound {
-    const IDirectSoundVtbl     *lpVtbl;
-    LONG                        ref;
-    LPDIRECTSOUND8              pds;
-};
-
-HRESULT WINAPI IDirectSound8_IDirectSound_Create(
-    LPDIRECTSOUND8 pds,
-    LPDIRECTSOUND * ppds);
-
-struct IDirectSound8_IDirectSound8 {
-    const IDirectSound8Vtbl    *lpVtbl;
-    LONG                        ref;
-    LPDIRECTSOUND8              pds;
-};
-
-HRESULT WINAPI IDirectSound8_IDirectSound8_Create(
-    LPDIRECTSOUND8 pds,
-    LPDIRECTSOUND8 * ppds);
+ULONG DirectSoundDevice_Release(DirectSoundDevice * device);
+HRESULT DirectSoundDevice_Initialize(
+    DirectSoundDevice ** ppDevice,
+    LPCGUID lpcGUID);
+HRESULT DirectSoundDevice_AddBuffer(
+    DirectSoundDevice * device,
+    IDirectSoundBufferImpl * pDSB);
+HRESULT DirectSoundDevice_RemoveBuffer(
+    DirectSoundDevice * device,
+    IDirectSoundBufferImpl * pDSB);
+HRESULT DirectSoundDevice_GetCaps(DirectSoundDevice * device, LPDSCAPS lpDSCaps);
+HRESULT DirectSoundDevice_CreateSoundBuffer(
+    DirectSoundDevice * device,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk,
+    BOOL from8);
+HRESULT DirectSoundDevice_DuplicateSoundBuffer(
+    DirectSoundDevice * device,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb);
+HRESULT DirectSoundDevice_SetCooperativeLevel(
+    DirectSoundDevice * devcie,
+    HWND hwnd,
+    DWORD level);
+HRESULT DirectSoundDevice_Compact(DirectSoundDevice * device);
+HRESULT DirectSoundDevice_GetSpeakerConfig(
+    DirectSoundDevice * device,
+    LPDWORD lpdwSpeakerConfig);
+HRESULT DirectSoundDevice_SetSpeakerConfig(
+    DirectSoundDevice * device,
+    DWORD config);
 
 /*****************************************************************************
  * IDirectSoundBuffer implementation structure
@@ -203,24 +168,23 @@ struct IDirectSoundBufferImpl
     const IDirectSoundBuffer8Vtbl *lpVtbl;
     LONG                        ref;
     /* IDirectSoundBufferImpl fields */
-    SecondaryBufferImpl*        dsb;
-    IDirectSoundImpl*           dsound;
-    CRITICAL_SECTION            lock;
+    SecondaryBufferImpl*        secondary;
+    DirectSoundDevice*          device;
+    RTL_RWLOCK                  lock;
     PIDSDRIVERBUFFER            hwbuf;
     PWAVEFORMATEX               pwfx;
     BufferMemory*               buffer;
+    LPBYTE                      tmp_buffer;
     DWORD                       playflags,state,leadin;
-    DWORD                       playpos,startpos,writelead,buflen;
+    DWORD                       writelead,buflen;
     DWORD                       nAvgBytesPerSec;
-    DWORD                       freq;
-    DSVOLUMEPAN                 volpan, cvolpan;
+    DWORD                       freq, tmp_buffer_len, max_buffer_len;
+    DSVOLUMEPAN                 volpan;
     DSBUFFERDESC                dsbd;
     /* used for frequency conversion (PerfectPitch) */
-    ULONG                       freqAdjust, freqAcc;
-    /* used for intelligent (well, sort of) prebuffering */
-    DWORD                       probably_valid_to, last_playpos;
-    DWORD                       primary_mixpos, buf_mixpos;
-    BOOL                        need_remix;
+    ULONG                       freqneeded, freqAdjust, freqAcc, freqAccNext, resampleinmixer;
+    /* used for mixing */
+    DWORD                       primary_mixpos, buf_mixpos, sec_mixpos;
 
     /* IDirectSoundNotifyImpl fields */
     IDirectSoundNotifyImpl*     notify;
@@ -236,13 +200,19 @@ struct IDirectSoundBufferImpl
 
     /* IKsPropertySet fields */
     IKsBufferPropertySetImpl*   iks;
+    bitsconvertfunc convert;
+    struct list entry;
 };
 
-HRESULT WINAPI IDirectSoundBufferImpl_Create(
-    IDirectSoundImpl *ds,
-    IDirectSoundBufferImpl **pdsb,
+HRESULT IDirectSoundBufferImpl_Create(
+    DirectSoundDevice *device,
+    IDirectSoundBufferImpl **ppdsb,
     LPCDSBUFFERDESC dsbd);
-HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
+HRESULT IDirectSoundBufferImpl_Destroy(
+    IDirectSoundBufferImpl *pdsb);
+HRESULT IDirectSoundBufferImpl_Duplicate(
+    DirectSoundDevice *device,
+    IDirectSoundBufferImpl **ppdsb,
     IDirectSoundBufferImpl *pdsb);
 
 /*****************************************************************************
@@ -255,39 +225,28 @@ struct SecondaryBufferImpl
     IDirectSoundBufferImpl*     dsb;
 };
 
-HRESULT WINAPI SecondaryBufferImpl_Create(
+HRESULT SecondaryBufferImpl_Create(
     IDirectSoundBufferImpl *dsb,
     SecondaryBufferImpl **pdsb);
-HRESULT WINAPI SecondaryBufferImpl_Destroy(
-    SecondaryBufferImpl *pdsb);
 
 /*****************************************************************************
  * PrimaryBuffer implementation structure
  */
 struct PrimaryBufferImpl
 {
-    const IDirectSoundBuffer8Vtbl *lpVtbl;
+    const IDirectSoundBufferVtbl *lpVtbl;
     LONG                        ref;
-    IDirectSoundImpl*           dsound;
+    DirectSoundDevice*          device;
 };
 
-HRESULT WINAPI PrimaryBufferImpl_Create(
-    IDirectSoundImpl *ds,
-    PrimaryBufferImpl **pdsb,
+HRESULT PrimaryBufferImpl_Create(
+    DirectSoundDevice * device,
+    PrimaryBufferImpl **ppdsb,
     LPCDSBUFFERDESC dsbd);
 
 /*****************************************************************************
- * IDirectSoundCapture implementation structure
+ * DirectSoundCaptureDevice implementation structure
  */
-struct IDirectSoundCaptureImpl
-{
-    /* IUnknown fields */
-    const IDirectSoundCaptureVtbl     *lpVtbl;
-    LONG                               ref;
-
-    DirectSoundCaptureDevice          *device;
-};
-
 struct DirectSoundCaptureDevice
 {
     /* IDirectSoundCaptureImpl fields */
@@ -306,7 +265,6 @@ struct DirectSoundCaptureDevice
     /* more stuff */
     LPBYTE                             buffer;
     DWORD                              buflen;
-    DWORD                              read_position;
 
     PWAVEFORMATEX                      pwfx;
 
@@ -318,16 +276,11 @@ struct DirectSoundCaptureDevice
     CRITICAL_SECTION                   lock;
 };
 
-HRESULT WINAPI IDirectSoundCaptureImpl_Create(
-    LPDIRECTSOUNDCAPTURE8 * ppds);
-
-HRESULT WINAPI DSOUND_CaptureCreate(
-    LPDIRECTSOUNDCAPTURE *ppDSC,
-    IUnknown *pUnkOuter);
-
-HRESULT WINAPI DSOUND_CaptureCreate8(
-    LPDIRECTSOUNDCAPTURE8 *ppDSC8,
-    IUnknown *pUnkOuter);
+HRESULT DirectSoundCaptureDevice_Initialize(
+    DirectSoundCaptureDevice ** ppDevice,
+    LPCGUID lpcGUID);
+ULONG DirectSoundCaptureDevice_Release(
+    DirectSoundCaptureDevice * device);
 
 /*****************************************************************************
  * IDirectSoundCaptureBuffer implementation structure
@@ -339,7 +292,7 @@ struct IDirectSoundCaptureBufferImpl
     LONG                                ref;
 
     /* IDirectSoundCaptureBufferImpl fields */
-    IDirectSoundCaptureImpl*            dsound;
+    DirectSoundCaptureDevice*           device;
     /* FIXME: don't need this */
     LPDSCBUFFERDESC                     pdscbd;
     DWORD                               flags;
@@ -351,6 +304,11 @@ struct IDirectSoundCaptureBufferImpl
     PIDSDRIVERNOTIFY                    hwnotify;
 };
 
+HRESULT IDirectSoundCaptureBufferImpl_Create(
+    DirectSoundCaptureDevice *device,
+    IDirectSoundCaptureBufferImpl ** ppobj,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc);
+
 /*****************************************************************************
  * IDirectSoundFullDuplex implementation structure
  */
@@ -358,43 +316,44 @@ struct IDirectSoundFullDuplexImpl
 {
     /* IUnknown fields */
     const IDirectSoundFullDuplexVtbl *lpVtbl;
-    LONG                        ref;
+    LONG                              ref;
 
     /* IDirectSoundFullDuplexImpl fields */
-    CRITICAL_SECTION            lock;
+    DirectSoundDevice                *renderer_device;
+    DirectSoundCaptureDevice         *capture_device;
+
+    LPUNKNOWN                         pUnknown;
+    LPDIRECTSOUND                     pDS;
+    LPDIRECTSOUND8                    pDS8;
+    LPDIRECTSOUNDCAPTURE              pDSC;
 };
 
 /*****************************************************************************
- * IDirectSoundNotify implementation structure
+ * IDirectSoundFullDuplex COM components
  */
-struct IDirectSoundNotifyImpl
-{
-    /* IUnknown fields */
-    const IDirectSoundNotifyVtbl *lpVtbl;
+struct IDirectSoundFullDuplex_IUnknown {
+    const IUnknownVtbl         *lpVtbl;
     LONG                        ref;
-    IDirectSoundBufferImpl*     dsb;
+    IDirectSoundFullDuplexImpl *pdsfd;
 };
 
-HRESULT WINAPI IDirectSoundNotifyImpl_Create(
-    IDirectSoundBufferImpl *dsb,
-    IDirectSoundNotifyImpl **pdsn);
-HRESULT WINAPI IDirectSoundNotifyImpl_Destroy(
-    IDirectSoundNotifyImpl *pdsn);
+struct IDirectSoundFullDuplex_IDirectSound {
+    const IDirectSoundVtbl     *lpVtbl;
+    LONG                        ref;
+    IDirectSoundFullDuplexImpl *pdsfd;
+};
 
-/*****************************************************************************
- * IDirectSoundCaptureNotify implementation structure
- */
-struct IDirectSoundCaptureNotifyImpl
-{
-    /* IUnknown fields */
-    const IDirectSoundNotifyVtbl       *lpVtbl;
-    LONG                                ref;
-    IDirectSoundCaptureBufferImpl*      dscb;
+struct IDirectSoundFullDuplex_IDirectSound8 {
+    const IDirectSound8Vtbl    *lpVtbl;
+    LONG                        ref;
+    IDirectSoundFullDuplexImpl *pdsfd;
 };
 
-HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create(
-    IDirectSoundCaptureBufferImpl *dscb,
-    IDirectSoundCaptureNotifyImpl ** pdscn);
+struct IDirectSoundFullDuplex_IDirectSoundCapture {
+    const IDirectSoundCaptureVtbl *lpVtbl;
+    LONG                           ref;
+    IDirectSoundFullDuplexImpl    *pdsfd;
+};
 
 /*****************************************************************************
  *  IDirectSound3DListener implementation structure
@@ -405,11 +364,11 @@ struct IDirectSound3DListenerImpl
     const IDirectSound3DListenerVtbl *lpVtbl;
     LONG                        ref;
     /* IDirectSound3DListenerImpl fields */
-    IDirectSoundImpl*           dsound;
+    DirectSoundDevice*          device;
 };
 
-HRESULT WINAPI IDirectSound3DListenerImpl_Create(
-    PrimaryBufferImpl *pb,
+HRESULT IDirectSound3DListenerImpl_Create(
+    DirectSoundDevice           *device,
     IDirectSound3DListenerImpl **pdsl);
 
 /*****************************************************************************
@@ -424,10 +383,10 @@ struct IKsBufferPropertySetImpl
     IDirectSoundBufferImpl*    dsb;
 };
 
-HRESULT WINAPI IKsBufferPropertySetImpl_Create(
+HRESULT IKsBufferPropertySetImpl_Create(
     IDirectSoundBufferImpl *dsb,
     IKsBufferPropertySetImpl **piks);
-HRESULT WINAPI IKsBufferPropertySetImpl_Destroy(
+HRESULT IKsBufferPropertySetImpl_Destroy(
     IKsBufferPropertySetImpl *piks);
 
 /*****************************************************************************
@@ -440,7 +399,8 @@ struct IKsPrivatePropertySetImpl
     LONG                       ref;
 };
 
-HRESULT WINAPI IKsPrivatePropertySetImpl_Create(
+HRESULT IKsPrivatePropertySetImpl_Create(
+    REFIID riid,
     IKsPrivatePropertySetImpl **piks);
 
 /*****************************************************************************
@@ -455,67 +415,74 @@ struct IDirectSound3DBufferImpl
     IDirectSoundBufferImpl*     dsb;
 };
 
-HRESULT WINAPI IDirectSound3DBufferImpl_Create(
+HRESULT IDirectSound3DBufferImpl_Create(
     IDirectSoundBufferImpl *dsb,
     IDirectSound3DBufferImpl **pds3db);
-HRESULT WINAPI IDirectSound3DBufferImpl_Destroy(
+HRESULT IDirectSound3DBufferImpl_Destroy(
     IDirectSound3DBufferImpl *pds3db);
 
 /*******************************************************************************
- * DirectSound ClassFactory implementation structure
  */
-struct IClassFactoryImpl
-{
-    /* IUnknown fields */
-    const IClassFactoryVtbl    *lpVtbl;
-    LONG                        ref;
-};
-
-extern IClassFactoryImpl DSOUND_CAPTURE_CF;
-extern IClassFactoryImpl DSOUND_FULLDUPLEX_CF;
-
-void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
-void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
-void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb);
 
 /* dsound.c */
 
-HRESULT DSOUND_AddBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB);
-HRESULT DSOUND_RemoveBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB);
+HRESULT DSOUND_Create(REFIID riid, LPDIRECTSOUND *ppDS);
+HRESULT DSOUND_Create8(REFIID riid, LPDIRECTSOUND8 *ppDS);
 
 /* primary.c */
 
+DWORD DSOUND_fraglen(DWORD nSamplesPerSec, DWORD nBlockAlign);
 HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device);
 HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos);
+HRESULT DSOUND_PrimarySetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex, BOOL forced);
+HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave);
 
-/* buffer.c */
-
-DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite);
+/* duplex.c */
+HRESULT DSOUND_FullDuplexCreate(REFIID riid, LPDIRECTSOUNDFULLDUPLEX* ppDSFD);
 
 /* mixer.c */
+DWORD DSOUND_bufpos_to_mixpos(const DirectSoundDevice* device, DWORD pos);
+void DSOUND_CheckEvent(const IDirectSoundBufferImpl *dsb, DWORD playpos, int len);
+void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan);
+void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan);
+void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb);
+void DSOUND_MixToTemporary(const IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mixlen, BOOL inmixer);
+DWORD DSOUND_secpos_to_bufpos(const IDirectSoundBufferImpl *dsb, DWORD secpos, DWORD secmixpos, DWORD* overshot);
 
-void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len);
-void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb);
-void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos);
-void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq);
-void DSOUND_PerformMix(DirectSoundDevice *device);
-void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
-void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2);
+void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
+void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
 
 /* sound3d.c */
 
 void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb);
 
+/* capture.c */
+HRESULT DSOUND_CaptureCreate(REFIID riid, LPDIRECTSOUNDCAPTURE *ppDSC);
+HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8);
+HRESULT WINAPI IDirectSoundCaptureImpl_CreateCaptureBuffer(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc,
+    LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
+    LPUNKNOWN pUnk);
+HRESULT WINAPI IDirectSoundCaptureImpl_GetCaps(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPDSCCAPS lpDSCCaps);
+HRESULT WINAPI IDirectSoundCaptureImpl_Initialize(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID);
+
 #define STATE_STOPPED   0
 #define STATE_STARTING  1
 #define STATE_PLAYING   2
 #define STATE_CAPTURING 2
 #define STATE_STOPPING  3
 
-#define DSOUND_FREQSHIFT (14)
+#define DSOUND_FREQSHIFT (20)
 
 extern DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS];
 extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
@@ -523,6 +490,6 @@ extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS];
 extern DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS];
 extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS];
 
-extern HRESULT mmErr(UINT err);
-extern void setup_dsound_options(void);
-extern const char * get_device_id(LPCGUID pGuid);
+HRESULT mmErr(UINT err);
+void setup_dsound_options(void);
+const char * dumpCooperativeLevel(DWORD level);
index 8c732c5..1fe6bbc 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
- * TODO:
- *     Implement DirectSoundFullDuplex support.
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "mmsystem.h"
 #include "mmddk.h"
-#include "winreg.h"
 #include "winternl.h"
-#include "winnls.h"
 #include "wine/debug.h"
 #include "dsound.h"
 #include "dsdriver.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(
-    LPDIRECTSOUNDFULLDUPLEX iface,
-    LPCGUID pCaptureGuid,
-    LPCGUID pRendererGuid,
-    LPCDSCBUFFERDESC lpDscBufferDesc,
-    LPCDSBUFFERDESC lpDsBufferDesc,
-    HWND hWnd,
-    DWORD dwLevel,
-    LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
-    LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 );
+/*******************************************************************************
+ * IUnknown
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IUnknown_QueryInterface(
+    LPUNKNOWN iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
 
-static const IDirectSoundFullDuplexVtbl dsfdvt;
+static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_AddRef(
+    LPUNKNOWN iface)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
 
-/***************************************************************************
- * DirectSoundFullDuplexCreate [DSOUND.10]
- *
- * Create and initialize a DirectSoundFullDuplex interface.
- *
- * PARAMS
- *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
- *    pcGuidRenderDevice  [I] Address of sound render device GUID.
- *    pcDSCBufferDesc     [I] Address of capture buffer description.
- *    pcDSBufferDesc      [I] Address of  render buffer description.
- *    hWnd                [I] Handle to application window.
- *    dwLevel             [I] Cooperative level.
- *    ppDSFD              [O] Address where full duplex interface returned.
- *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
- *    ppDSBuffer8         [0] Address where render buffer interface returned.
- *    pUnkOuter           [I] Must be NULL.
- *
- * RETURNS
- *    Success: DS_OK
- *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
- *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
+static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_Release(
+    LPUNKNOWN iface)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pUnknown);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static const IUnknownVtbl DirectSoundFullDuplex_Unknown_Vtbl =
+{
+    IDirectSoundFullDuplex_IUnknown_QueryInterface,
+    IDirectSoundFullDuplex_IUnknown_AddRef,
+    IDirectSoundFullDuplex_IUnknown_Release
+};
+
+static HRESULT IDirectSoundFullDuplex_IUnknown_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPUNKNOWN * ppunk)
+{
+    IDirectSoundFullDuplex_IUnknown * pdsfdunk;
+    TRACE("(%p,%p)\n",pdsfd,ppunk);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppunk == NULL) {
+        ERR("invalid parameter: ppunk == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    pdsfdunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdunk));
+    if (pdsfdunk == NULL) {
+        WARN("out of memory\n");
+        *ppunk = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfdunk->lpVtbl = &DirectSoundFullDuplex_Unknown_Vtbl;
+    pdsfdunk->ref = 0;
+    pdsfdunk->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppunk = (LPUNKNOWN)pdsfdunk;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSound
  */
-HRESULT WINAPI
-DirectSoundFullDuplexCreate(
-    LPCGUID pcGuidCaptureDevice,
-    LPCGUID pcGuidRenderDevice,
-    LPCDSCBUFFERDESC pcDSCBufferDesc,
-    LPCDSBUFFERDESC pcDSBufferDesc,
-    HWND hWnd,
-    DWORD dwLevel,
-    LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
-    LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
-    LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
-    LPUNKNOWN pUnkOuter)
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_QueryInterface(
+    LPDIRECTSOUND iface,
+    REFIID riid,
+    LPVOID * ppobj)
 {
-    IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
-    TRACE("(%s,%s,%p,%p,%p,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice),
-       debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
-       hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
 
-    if ( pUnkOuter ) {
-       WARN("pUnkOuter != 0\n");
-        return DSERR_NOAGGREGATION;
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound_AddRef(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound_Release(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pDS);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_CreateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk,FALSE);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_GetCaps(
+    LPDIRECTSOUND iface,
+    LPDSCAPS lpDSCaps)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_DuplicateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_SetCooperativeLevel(
+    LPDIRECTSOUND iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_Compact(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(This->pdsfd->renderer_device);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_GetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_SetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    DWORD config)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(This->pdsfd->renderer_device,config);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_Initialize(
+    LPDIRECTSOUND iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&This->pdsfd->renderer_device,lpcGuid);
+}
+
+static const IDirectSoundVtbl DirectSoundFullDuplex_DirectSound_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSound_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSound_AddRef,
+    IDirectSoundFullDuplex_IDirectSound_Release,
+    IDirectSoundFullDuplex_IDirectSound_CreateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound_GetCaps,
+    IDirectSoundFullDuplex_IDirectSound_DuplicateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound_SetCooperativeLevel,
+    IDirectSoundFullDuplex_IDirectSound_Compact,
+    IDirectSoundFullDuplex_IDirectSound_GetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound_SetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound_Initialize
+};
+
+static HRESULT IDirectSoundFullDuplex_IDirectSound_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUND * ppds)
+{
+    IDirectSoundFullDuplex_IDirectSound * pdsfdds;
+    TRACE("(%p,%p)\n",pdsfd,ppds);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppds == NULL) {
+        ERR("invalid parameter: ppds == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
+        WARN("not initialized\n");
+        *ppds = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfdds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds));
+    if (pdsfdds == NULL) {
+        WARN("out of memory\n");
+        *ppds = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfdds->lpVtbl = &DirectSoundFullDuplex_DirectSound_Vtbl;
+    pdsfdds->ref = 0;
+    pdsfdds->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppds = (LPDIRECTSOUND)pdsfdds;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSound8
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_QueryInterface(
+    LPDIRECTSOUND8 iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_AddRef(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_Release(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pDS8);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk,TRUE);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetCaps(
+    LPDIRECTSOUND8 iface,
+    LPDSCAPS lpDSCaps)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel(
+    LPDIRECTSOUND8 iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Compact(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(This->pdsfd->renderer_device);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    DWORD config)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(This->pdsfd->renderer_device,config);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Initialize(
+    LPDIRECTSOUND8 iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&This->pdsfd->renderer_device,lpcGuid);
+}
+
+static const IDirectSound8Vtbl DirectSoundFullDuplex_DirectSound8_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSound8_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSound8_AddRef,
+    IDirectSoundFullDuplex_IDirectSound8_Release,
+    IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound8_GetCaps,
+    IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel,
+    IDirectSoundFullDuplex_IDirectSound8_Compact,
+    IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound8_Initialize
+};
+
+static HRESULT IDirectSoundFullDuplex_IDirectSound8_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUND8 * ppds8)
+{
+    IDirectSoundFullDuplex_IDirectSound8 * pdsfdds8;
+    TRACE("(%p,%p)\n",pdsfd,ppds8);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppds8 == NULL) {
+        ERR("invalid parameter: ppds8 == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
+        WARN("not initialized\n");
+        *ppds8 = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfdds8 = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds8));
+    if (pdsfdds8 == NULL) {
+        WARN("out of memory\n");
+        *ppds8 = NULL;
+        return DSERR_OUTOFMEMORY;
     }
 
-    *ippDSFD = HeapAlloc(GetProcessHeap(),
-       HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
+    pdsfdds8->lpVtbl = &DirectSoundFullDuplex_DirectSound8_Vtbl;
+    pdsfdds8->ref = 0;
+    pdsfdds8->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppds8 = (LPDIRECTSOUND8)pdsfdds8;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSoundCapture
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface(
+    LPDIRECTSOUNDCAPTURE iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(
+    LPDIRECTSOUNDCAPTURE iface)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Release(
+    LPDIRECTSOUNDCAPTURE iface)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSoundCapture_Release(This->pdsfd->pDSC);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc,
+    LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
+    LPUNKNOWN pUnk)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
+    return IDirectSoundCaptureImpl_CreateCaptureBuffer(This->pdsfd->pDSC,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
+}
 
-    if (*ippDSFD == NULL) {
-       WARN("out of memory\n");
-       return DSERR_OUTOFMEMORY;
-    } else {
-       HRESULT hres;
-        IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD;
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPDSCCAPS lpDSCCaps)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCCaps);
+    return IDirectSoundCaptureImpl_GetCaps(This->pdsfd->pDSC, lpDSCCaps);
+}
 
-        This->ref = 1;
-        This->lpVtbl = &dsfdvt;
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Initialize(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGUID));
+    return IDirectSoundCaptureImpl_Initialize(This->pdsfd->pDSC,lpcGUID);
+}
 
-        InitializeCriticalSection( &(This->lock) );
-        This->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSDUPLEX_lock";
+static const IDirectSoundCaptureVtbl DirectSoundFullDuplex_DirectSoundCapture_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSoundCapture_AddRef,
+    IDirectSoundFullDuplex_IDirectSoundCapture_Release,
+    IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer,
+    IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps,
+    IDirectSoundFullDuplex_IDirectSoundCapture_Initialize
+};
 
-        hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
-                                                      pcGuidCaptureDevice, pcGuidRenderDevice,
-                                                      pcDSCBufferDesc, pcDSBufferDesc,
-                                                      hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
-       if (hres != DS_OK)
-           WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
-       return hres;
+static HRESULT IDirectSoundFullDuplex_IDirectSoundCapture_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUNDCAPTURE8 * ppdsc8)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture * pdsfddsc;
+    TRACE("(%p,%p)\n",pdsfd,ppdsc8);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
+
+    if (ppdsc8 == NULL) {
+        ERR("invalid parameter: ppdsc8 == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->capture_device == NULL) {
+        WARN("not initialized\n");
+        *ppdsc8 = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfddsc = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfddsc));
+    if (pdsfddsc == NULL) {
+        WARN("out of memory\n");
+        *ppdsc8 = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfddsc->lpVtbl = &DirectSoundFullDuplex_DirectSoundCapture_Vtbl;
+    pdsfddsc->ref = 0;
+    pdsfddsc->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppdsc8 = (LPDIRECTSOUNDCAPTURE)pdsfddsc;
+
+    return DS_OK;
+}
+
+/***************************************************************************
+ * IDirectSoundFullDuplexImpl
+ */
+static ULONG WINAPI
+IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
+{
+    IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
 }
 
 static HRESULT WINAPI
@@ -141,16 +584,62 @@ IDirectSoundFullDuplexImpl_QueryInterface(
     }
 
     *ppobj = NULL;
-    return E_NOINTERFACE;
-}
 
-static ULONG WINAPI
-IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
-{
-    IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        if (!This->pUnknown) {
+            IDirectSoundFullDuplex_IUnknown_Create(iface, &This->pUnknown);
+            if (!This->pUnknown) {
+                WARN("IDirectSoundFullDuplex_IUnknown_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IUnknown_AddRef(This->pUnknown);
+        *ppobj = This->pUnknown;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
+        IDirectSoundFullDuplexImpl_AddRef(iface);
+        *ppobj = This;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSound)) {
+        if (!This->pDS) {
+            IDirectSoundFullDuplex_IDirectSound_Create(iface, &This->pDS);
+            if (!This->pDS) {
+                WARN("IDirectSoundFullDuplex_IDirectSound_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSound_AddRef(This->pDS);
+        *ppobj = This->pDS;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
+        if (!This->pDS8) {
+            IDirectSoundFullDuplex_IDirectSound8_Create(iface, &This->pDS8);
+            if (!This->pDS8) {
+                WARN("IDirectSoundFullDuplex_IDirectSound8_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSound8_AddRef(This->pDS8);
+        *ppobj = This->pDS8;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
+        if (!This->pDSC) {
+            IDirectSoundFullDuplex_IDirectSoundCapture_Create(iface, &This->pDSC);
+            if (!This->pDSC) {
+                WARN("IDirectSoundFullDuplex_IDirectSoundCapture_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(This->pDSC);
+        *ppobj = This->pDSC;
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
 }
 
 static ULONG WINAPI
@@ -158,11 +647,13 @@ IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
 {
     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
 
     if (!ref) {
-        This->lock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection( &(This->lock) );
+        if (This->capture_device)<