[1/2] dsound: Reorder the interfaces to remove the need for forward declarations.

Francois Gouget fgouget at free.fr
Mon Jan 5 12:45:31 CST 2015


---
 dlls/dsound/dsound.c         | 1525 +++++++++++++++++++++---------------------
 dlls/dsound/dsound_private.h |   14 -
 2 files changed, 763 insertions(+), 776 deletions(-)

diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index 986168b..e73fb51 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -118,987 +118,988 @@ static void _dump_DSBCAPS(DWORD xmask) {
             TRACE("%s ",flags[i].name);
 }
 
-static void directsound_destroy(IDirectSoundImpl *This)
-{
-    if (This->device)
-        DirectSoundDevice_Release(This->device);
-    HeapFree(GetProcessHeap(),0,This);
-    TRACE("(%p) released\n", This);
-}
-
 /*******************************************************************************
- *      IUnknown Implementation for DirectSound
+ *        DirectSoundDevice
  */
-static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
+static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
 {
-    return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
-}
+    DirectSoundDevice * device;
+    TRACE("(%p)\n", ppDevice);
 
-static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
-{
-    IDirectSoundImpl *This = impl_from_IUnknown(iface);
+    /* Allocate memory */
+    device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice));
+    if (device == NULL) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
 
-    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
+    device->ref            = 1;
+    device->priolevel      = DSSCL_NORMAL;
+    device->state          = STATE_STOPPED;
+    device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
 
-    if (!ppv) {
-        WARN("invalid parameter\n");
-        return E_INVALIDARG;
-    }
-    *ppv = 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;
 
-    if (IsEqualIID(riid, &IID_IUnknown))
-        *ppv = &This->IUnknown_inner;
-    else if (IsEqualIID(riid, &IID_IDirectSound) ||
-            (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
-        *ppv = &This->IDirectSound8_iface;
-    else {
-        WARN("unknown IID %s\n", debugstr_guid(riid));
-        return E_NOINTERFACE;
+    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(WAVEFORMATEXTENSIBLE));
+    device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE));
+    if (!device->pwfx || !device->primary_pwfx) {
+        WARN("out of memory\n");
+        HeapFree(GetProcessHeap(),0,device->primary_pwfx);
+        HeapFree(GetProcessHeap(),0,device->pwfx);
+        HeapFree(GetProcessHeap(),0,device);
+        return DSERR_OUTOFMEMORY;
     }
 
-    IUnknown_AddRef((IUnknown*)*ppv);
-    return S_OK;
-}
+    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;
+    memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
 
-static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
-{
-    IDirectSoundImpl *This = impl_from_IUnknown(iface);
-    ULONG ref = InterlockedIncrement(&This->ref);
+    InitializeCriticalSection(&(device->mixlock));
+    device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
 
-    TRACE("(%p) ref=%d\n", This, ref);
+    RtlInitializeResource(&(device->buffer_list_lock));
 
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
+   *ppDevice = device;
 
-    return ref;
+    return DS_OK;
 }
 
-static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
+static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
 {
-    IDirectSoundImpl *This = impl_from_IUnknown(iface);
-    ULONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%d\n", This, ref);
-
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        directsound_destroy(This);
-
+    ULONG ref = InterlockedIncrement(&(device->ref));
+    TRACE("(%p) ref was %d\n", device, ref - 1);
     return ref;
 }
 
-static const IUnknownVtbl unk_vtbl =
+ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
 {
-    IUnknownImpl_QueryInterface,
-    IUnknownImpl_AddRef,
-    IUnknownImpl_Release
-};
+    HRESULT hr;
+    ULONG ref = InterlockedDecrement(&(device->ref));
+    TRACE("(%p) ref was %u\n", device, ref + 1);
+    if (!ref) {
+        int i;
 
-/*******************************************************************************
- *      IDirectSound and IDirectSound8 Implementation
- */
-static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
-{
-    return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
-}
+        SetEvent(device->sleepev);
+        if (device->thread) {
+            WaitForSingleObject(device->thread, INFINITE);
+            CloseHandle(device->thread);
+        }
+        CloseHandle(device->sleepev);
 
-static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
-        void **ppv)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
-    return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
-}
+        EnterCriticalSection(&DSOUND_renderers_lock);
+        list_remove(&device->entry);
+        LeaveCriticalSection(&DSOUND_renderers_lock);
 
-static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    ULONG ref = InterlockedIncrement(&This->refds);
+        /* 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++)
+                secondarybuffer_destroy(device->buffers[i]);
+        }
 
-    TRACE("(%p) refds=%d\n", This, ref);
+        hr = DSOUND_PrimaryDestroy(device);
+        if (hr != DS_OK)
+            WARN("DSOUND_PrimaryDestroy failed\n");
 
-    if(ref == 1)
-        InterlockedIncrement(&This->numIfaces);
+        if(device->client)
+            IAudioClient_Release(device->client);
+        if(device->render)
+            IAudioRenderClient_Release(device->render);
+        if(device->clock)
+            IAudioClock_Release(device->clock);
+        if(device->volume)
+            IAudioStreamVolume_Release(device->volume);
 
+        HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
+        HeapFree(GetProcessHeap(), 0, device->mix_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);
+    }
     return ref;
 }
 
-static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
+BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
+        DWORD depth, WORD channels)
 {
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    ULONG ref = InterlockedDecrement(&(This->refds));
-
-    TRACE("(%p) refds=%d\n", This, ref);
+    WAVEFORMATEX fmt, *junk;
+    HRESULT hr;
 
-    if (!ref && !InterlockedDecrement(&This->numIfaces))
-        directsound_destroy(This);
+    fmt.wFormatTag = WAVE_FORMAT_PCM;
+    fmt.nChannels = channels;
+    fmt.nSamplesPerSec = rate;
+    fmt.wBitsPerSample = depth;
+    fmt.nBlockAlign = (channels * depth) / 8;
+    fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
+    fmt.cbSize = 0;
 
-    return ref;
-}
+    hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
+    if(SUCCEEDED(hr))
+        CoTaskMemFree(junk);
 
-static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
-        const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
-    return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
+    return hr == S_OK;
 }
 
-static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
+HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
 {
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    HRESULT hr = DS_OK;
+    GUID devGUID;
+    DirectSoundDevice *device;
+    IMMDevice *mmdevice;
 
-    TRACE("(%p, %p)\n", This, dscaps);
+    TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
+    if (*ppDevice != NULL) {
+        WARN("already initialized\n");
+        return DSERR_ALREADYINITIALIZED;
     }
-    if (!dscaps) {
-        WARN("invalid parameter: dscaps = NULL\n");
+
+    /* Default device? */
+    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
+        lpcGUID = &DSDEVID_DefaultPlayback;
+
+    if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
+            IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
+        return DSERR_NODRIVER;
+
+    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
+        WARN("invalid parameter: lpcGUID\n");
         return DSERR_INVALIDPARAM;
     }
-    if (dscaps->dwSize < sizeof(*dscaps)) {
-        WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
-        return DSERR_INVALIDPARAM;
+
+    hr = get_mmdevice(eRender, &devGUID, &mmdevice);
+    if(FAILED(hr))
+        return hr;
+
+    EnterCriticalSection(&DSOUND_renderers_lock);
+
+    LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
+        if(IsEqualGUID(&device->guid, &devGUID)){
+            IMMDevice_Release(mmdevice);
+            DirectSoundDevice_AddRef(device);
+            *ppDevice = device;
+            LeaveCriticalSection(&DSOUND_renderers_lock);
+            return DS_OK;
+        }
     }
 
-    dscaps->dwFlags                        = This->device->drvcaps.dwFlags;
-    dscaps->dwMinSecondarySampleRate       = This->device->drvcaps.dwMinSecondarySampleRate;
-    dscaps->dwMaxSecondarySampleRate       = This->device->drvcaps.dwMaxSecondarySampleRate;
-    dscaps->dwPrimaryBuffers               = This->device->drvcaps.dwPrimaryBuffers;
-    dscaps->dwMaxHwMixingAllBuffers        = This->device->drvcaps.dwMaxHwMixingAllBuffers;
-    dscaps->dwMaxHwMixingStaticBuffers     = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
-    dscaps->dwMaxHwMixingStreamingBuffers  = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
-    dscaps->dwFreeHwMixingAllBuffers       = This->device->drvcaps.dwFreeHwMixingAllBuffers;
-    dscaps->dwFreeHwMixingStaticBuffers    = This->device->drvcaps.dwFreeHwMixingStaticBuffers;
-    dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers;
-    dscaps->dwMaxHw3DAllBuffers            = This->device->drvcaps.dwMaxHw3DAllBuffers;
-    dscaps->dwMaxHw3DStaticBuffers         = This->device->drvcaps.dwMaxHw3DStaticBuffers;
-    dscaps->dwMaxHw3DStreamingBuffers      = This->device->drvcaps.dwMaxHw3DStreamingBuffers;
-    dscaps->dwFreeHw3DAllBuffers           = This->device->drvcaps.dwFreeHw3DAllBuffers;
-    dscaps->dwFreeHw3DStaticBuffers        = This->device->drvcaps.dwFreeHw3DStaticBuffers;
-    dscaps->dwFreeHw3DStreamingBuffers     = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
-    dscaps->dwTotalHwMemBytes              = This->device->drvcaps.dwTotalHwMemBytes;
-    dscaps->dwFreeHwMemBytes               = This->device->drvcaps.dwFreeHwMemBytes;
-    dscaps->dwMaxContigFreeHwMemBytes      = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
-    dscaps->dwUnlockTransferRateHwBuffers  = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
-    dscaps->dwPlayCpuOverheadSwBuffers     = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
+    hr = DirectSoundDevice_Create(&device);
+    if(FAILED(hr)){
+        WARN("DirectSoundDevice_Create failed\n");
+        IMMDevice_Release(mmdevice);
+        LeaveCriticalSection(&DSOUND_renderers_lock);
+        return hr;
+    }
 
-    if (TRACE_ON(dsound)) {
-        TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
-        _dump_DSCAPS(dscaps->dwFlags);
-        TRACE(")\n");
+    device->mmdevice = mmdevice;
+    device->guid = devGUID;
+    device->sleepev = CreateEventW(0, 0, 0, 0);
+
+    hr = DSOUND_ReopenDevice(device, FALSE);
+    if (FAILED(hr))
+    {
+        HeapFree(GetProcessHeap(), 0, device);
+        LeaveCriticalSection(&DSOUND_renderers_lock);
+        IMMDevice_Release(mmdevice);
+        WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
+        return hr;
     }
 
-    return DS_OK;
-}
+    ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
 
-static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
-        IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
-    return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
-}
+    if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
+            DSOUND_check_supported(device->client, 22050, 8, 1) ||
+            DSOUND_check_supported(device->client, 44100, 8, 1) ||
+            DSOUND_check_supported(device->client, 48000, 8, 1) ||
+            DSOUND_check_supported(device->client, 96000, 8, 1))
+        device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
 
-static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
-        DWORD level)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    DirectSoundDevice *device = This->device;
-    DWORD oldlevel;
-    HRESULT hr = S_OK;
+    if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
+            DSOUND_check_supported(device->client, 22050, 16, 1) ||
+            DSOUND_check_supported(device->client, 44100, 16, 1) ||
+            DSOUND_check_supported(device->client, 48000, 16, 1) ||
+            DSOUND_check_supported(device->client, 96000, 16, 1))
+        device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
 
-    TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
+    if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
+            DSOUND_check_supported(device->client, 22050, 8, 2) ||
+            DSOUND_check_supported(device->client, 44100, 8, 2) ||
+            DSOUND_check_supported(device->client, 48000, 8, 2) ||
+            DSOUND_check_supported(device->client, 96000, 8, 2))
+        device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
 
-    if (!device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
+            DSOUND_check_supported(device->client, 22050, 16, 2) ||
+            DSOUND_check_supported(device->client, 44100, 16, 2) ||
+            DSOUND_check_supported(device->client, 48000, 16, 2) ||
+            DSOUND_check_supported(device->client, 96000, 16, 2))
+        device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
 
-    if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
-        WARN("level=%s not fully supported\n",
-             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
-    }
+    /* the dsound mixer supports all of the following */
+    device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
+    device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
+    device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
 
-    RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
-    EnterCriticalSection(&device->mixlock);
-    oldlevel = device->priolevel;
-    device->priolevel = level;
-    if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
-        hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
-        if (FAILED(hr))
-            device->priolevel = oldlevel;
-        else
-            DSOUND_PrimaryOpen(device);
-    }
-    LeaveCriticalSection(&device->mixlock);
-    RtlReleaseResource(&device->buffer_list_lock);
-    return hr;
-}
+    device->drvcaps.dwPrimaryBuffers = 1;
+    device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
+    device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
+    device->drvcaps.dwMaxHwMixingAllBuffers = 1;
+    device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
+    device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
 
-static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    ZeroMemory(&device->volpan, sizeof(device->volpan));
 
-    TRACE("(%p)\n", This);
+    hr = DSOUND_PrimaryCreate(device);
+    if (hr == DS_OK) {
+        device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
+        SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
+    } else
+        WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    *ppDevice = device;
+    list_add_tail(&DSOUND_renderers, &device->entry);
 
-    if (This->device->priolevel < DSSCL_PRIORITY) {
-        WARN("incorrect priority level\n");
-        return DSERR_PRIOLEVELNEEDED;
-    }
-    return DS_OK;
+    LeaveCriticalSection(&DSOUND_renderers_lock);
+
+    return hr;
 }
 
-static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
+HRESULT DirectSoundDevice_CreateSoundBuffer(
+    DirectSoundDevice * device,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk,
+    BOOL from8)
 {
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-
-    TRACE("(%p, %p)\n", This, config);
+    HRESULT hres = DS_OK;
+    TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
 
-    if (!This->device) {
+    if (device == NULL) {
         WARN("not initialized\n");
         return DSERR_UNINITIALIZED;
     }
-    if (!config) {
-        WARN("invalid parameter: config == NULL\n");
+
+    if (dsbd == NULL) {
+        WARN("invalid parameter: dsbd == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    WARN("not fully functional\n");
-    *config = This->device->speaker_config;
-    return DS_OK;
-}
+    if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
+        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
+        WARN("invalid parameter: dsbd\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+    *ppdsb = NULL;
 
-    TRACE("(%p,0x%08x)\n", This, config);
+    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);
+    }
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
+    if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
+            !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
+        TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
+        return E_NOTIMPL;
     }
 
-    This->device->speaker_config = config;
-    WARN("not fully functional\n");
-    return DS_OK;
-}
+    if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
+        if (dsbd->lpwfxFormat != NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
+                 "primary buffer\n");
+            return DSERR_INVALIDPARAM;
+        }
 
-static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
-    return DirectSoundDevice_Initialize(&This->device, lpcGuid);
-}
+        if (device->primary) {
+            WARN("Primary Buffer already created\n");
+            IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(device->primary));
+            *ppdsb = (LPDIRECTSOUNDBUFFER)(device->primary);
+        } else {
+            hres = primarybuffer_create(device, &device->primary, dsbd);
+            if (device->primary) {
+                *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
+                device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
+                device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
+            } else
+                WARN("primarybuffer_create() failed\n");
+        }
+    } else {
+        IDirectSoundBufferImpl * dsb;
+        WAVEFORMATEXTENSIBLE *pwfxe;
 
-static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+        if (dsbd->lpwfxFormat == NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
+                 "secondary buffer\n");
+            return DSERR_INVALIDPARAM;
+        }
+        pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
 
-    TRACE("(%p, %p)\n", This, certified);
+        if (pwfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+        {
+            /* check if cbSize is at least 22 bytes */
+            if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
+            {
+                WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
+                return DSERR_INVALIDPARAM;
+            }
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+            /* cbSize should be 22 bytes, with one possible exception */
+            if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
+                !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
+                pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
+            {
+                WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
+                return DSERR_CONTROLUNAVAIL;
+            }
 
-    if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
-        *certified = DS_CERTIFIED;
-    else
-        *certified = DS_UNCERTIFIED;
+            if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
+            {
+                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;
+            }
+        }
 
-    return DS_OK;
-}
+        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 const IDirectSound8Vtbl ds8_vtbl =
-{
-    IDirectSound8Impl_QueryInterface,
-    IDirectSound8Impl_AddRef,
-    IDirectSound8Impl_Release,
-    IDirectSound8Impl_CreateSoundBuffer,
-    IDirectSound8Impl_GetCaps,
-    IDirectSound8Impl_DuplicateSoundBuffer,
-    IDirectSound8Impl_SetCooperativeLevel,
-    IDirectSound8Impl_Compact,
-    IDirectSound8Impl_GetSpeakerConfig,
-    IDirectSound8Impl_SetSpeakerConfig,
-    IDirectSound8Impl_Initialize,
-    IDirectSound8Impl_VerifyCertification
-};
+        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
+            WARN("invalid parameter: 3D buffer format must be mono\n");
+            return DSERR_INVALIDPARAM;
+        }
 
-HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
+        hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
+        if (dsb)
+            *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
+        else
+            WARN("IDirectSoundBufferImpl_Create failed\n");
+   }
+
+   return hres;
+}
+
+HRESULT DirectSoundDevice_DuplicateSoundBuffer(
+    DirectSoundDevice * device,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
 {
-    IDirectSoundImpl *obj;
-    HRESULT hr;
+    HRESULT hres = DS_OK;
+    IDirectSoundBufferImpl* dsb;
+    TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
 
-    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    *ppv = NULL;
-    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
-    if (!obj) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
+    if (psb == NULL) {
+        WARN("invalid parameter: psb == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    setup_dsound_options();
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-    obj->IUnknown_inner.lpVtbl = &unk_vtbl;
-    obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
-    obj->ref = 1;
-    obj->refds = 0;
-    obj->numIfaces = 1;
-    obj->device = NULL;
-    obj->has_ds8 = has_ds8;
+    /* make sure we have a secondary buffer */
+    if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
+        WARN("trying to duplicate primary buffer\n");
+        *ppdsb = NULL;
+        return DSERR_INVALIDCALL;
+    }
 
-    /* COM aggregation supported only internally */
-    if (outer_unk)
-        obj->outer_unk = outer_unk;
+    /* duplicate the actual buffer implementation */
+    hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
+    if (hres == DS_OK)
+        *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
     else
-        obj->outer_unk = &obj->IUnknown_inner;
-
-    hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
-    IUnknown_Release(&obj->IUnknown_inner);
-
-    return hr;
-}
-
-HRESULT DSOUND_Create(REFIID riid, void **ppv)
-{
-    return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
-}
+        WARN("IDirectSoundBufferImpl_Duplicate failed\n");
 
-HRESULT DSOUND_Create8(REFIID riid, void **ppv)
-{
-    return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
+    return hres;
 }
 
-/*******************************************************************************
- *		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
+/*
+ * Add secondary buffer to buffer list.
+ * Gets exclusive access to buffer for writing.
  */
-HRESULT WINAPI DirectSoundCreate(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_AddBuffer(
+    DirectSoundDevice * device,
+    IDirectSoundBufferImpl * pDSB)
 {
-    HRESULT hr;
-    LPDIRECTSOUND pDS;
+    IDirectSoundBufferImpl **newbuffers;
+    HRESULT hr = DS_OK;
 
-    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
+    TRACE("(%p, %p)\n", device, pDSB);
 
-    if (ppDS == NULL) {
-        WARN("invalid parameter: ppDS == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 
-    if (pUnkOuter != NULL) {
-        WARN("invalid parameter: pUnkOuter != NULL\n");
-        *ppDS = 0;
-        return DSERR_INVALIDPARAM;
-    }
+    if (device->buffers)
+        newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
+    else
+        newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
 
-    hr = DSOUND_Create(&IID_IDirectSound, (void **)&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;
-        }
+    if (newbuffers) {
+        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", device->nrofbuffers);
+        hr = DSERR_OUTOFMEMORY;
     }
 
-    *ppDS = pDS;
+    RtlReleaseResource(&(device->buffer_list_lock));
 
     return hr;
 }
 
-/*******************************************************************************
- *        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
+/*
+ * Remove secondary buffer from buffer list.
+ * Gets exclusive access to buffer for writing.
  */
-HRESULT WINAPI DirectSoundCreate8(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND8 *ppDS,
-    IUnknown *pUnkOuter)
+void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
 {
-    HRESULT hr;
-    LPDIRECTSOUND8 pDS;
-
-    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
+    int i;
 
-    if (ppDS == NULL) {
-        WARN("invalid parameter: ppDS == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    TRACE("(%p, %p)\n", device, pDSB);
 
-    if (pUnkOuter != NULL) {
-        WARN("invalid parameter: pUnkOuter != NULL\n");
-        *ppDS = 0;
-        return DSERR_INVALIDPARAM;
-    }
+    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 
-    hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&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;
+    if (device->nrofbuffers == 1) {
+        assert(device->buffers[0] == pDSB);
+        HeapFree(GetProcessHeap(), 0, device->buffers);
+        device->buffers = NULL;
+    } else {
+        for (i = 0; i < device->nrofbuffers; i++) {
+            if (device->buffers[i] == pDSB) {
+                /* Put the last buffer of the list in the (now empty) position */
+                device->buffers[i] = device->buffers[device->nrofbuffers - 1];
+                break;
+            }
         }
     }
+    device->nrofbuffers--;
+    TRACE("buffer count is now %d\n", device->nrofbuffers);
 
-    *ppDS = pDS;
-
-    return hr;
+    RtlReleaseResource(&(device->buffer_list_lock));
 }
 
 /*******************************************************************************
- *        DirectSoundDevice
+ *      IUnknown Implementation for DirectSound
  */
-static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
-{
-    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;
-    }
+static void directsound_destroy(IDirectSoundImpl *This)
+{
+    if (This->device)
+        DirectSoundDevice_Release(This->device);
+    HeapFree(GetProcessHeap(),0,This);
+    TRACE("(%p) released\n", This);
+}
 
-    device->ref            = 1;
-    device->priolevel      = DSSCL_NORMAL;
-    device->state          = STATE_STOPPED;
-    device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
+static inline IDirectSoundImpl *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, IDirectSoundImpl, IUnknown_inner);
+}
 
-    /* 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;
+static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    IDirectSoundImpl *This = impl_from_IUnknown(iface);
 
-    device->prebuf = ds_snd_queue_max;
-    device->guid = GUID_NULL;
+    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
 
-    /* Set default wave format (may need it for waveOutOpen) */
-    device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE));
-    device->primary_pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEXTENSIBLE));
-    if (!device->pwfx || !device->primary_pwfx) {
-        WARN("out of memory\n");
-        HeapFree(GetProcessHeap(),0,device->primary_pwfx);
-        HeapFree(GetProcessHeap(),0,device->pwfx);
-        HeapFree(GetProcessHeap(),0,device);
-        return DSERR_OUTOFMEMORY;
+    if (!ppv) {
+        WARN("invalid parameter\n");
+        return E_INVALIDARG;
     }
+    *ppv = NULL;
 
-    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;
-    memcpy(device->primary_pwfx, device->pwfx, sizeof(*device->pwfx));
+    if (IsEqualIID(riid, &IID_IUnknown))
+        *ppv = &This->IUnknown_inner;
+    else if (IsEqualIID(riid, &IID_IDirectSound) ||
+            (IsEqualIID(riid, &IID_IDirectSound8) && This->has_ds8))
+        *ppv = &This->IDirectSound8_iface;
+    else {
+        WARN("unknown IID %s\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
 
-    InitializeCriticalSection(&(device->mixlock));
-    device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
 
-    RtlInitializeResource(&(device->buffer_list_lock));
+static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
+{
+    IDirectSoundImpl *This = impl_from_IUnknown(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
 
-   *ppDevice = device;
+    TRACE("(%p) ref=%d\n", This, ref);
 
-    return DS_OK;
-}
+    if(ref == 1)
+        InterlockedIncrement(&This->numIfaces);
 
-static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
-{
-    ULONG ref = InterlockedIncrement(&(device->ref));
-    TRACE("(%p) ref was %d\n", device, ref - 1);
     return ref;
 }
 
-ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
+static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
 {
-    HRESULT hr;
-    ULONG ref = InterlockedDecrement(&(device->ref));
-    TRACE("(%p) ref was %u\n", device, ref + 1);
-    if (!ref) {
-        int i;
+    IDirectSoundImpl *This = impl_from_IUnknown(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
 
-        SetEvent(device->sleepev);
-        if (device->thread) {
-            WaitForSingleObject(device->thread, INFINITE);
-            CloseHandle(device->thread);
-        }
-        CloseHandle(device->sleepev);
+    TRACE("(%p) ref=%d\n", This, ref);
 
-        EnterCriticalSection(&DSOUND_renderers_lock);
-        list_remove(&device->entry);
-        LeaveCriticalSection(&DSOUND_renderers_lock);
+    if (!ref && !InterlockedDecrement(&This->numIfaces))
+        directsound_destroy(This);
 
-        /* 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++)
-                secondarybuffer_destroy(device->buffers[i]);
-        }
+    return ref;
+}
 
-        hr = DSOUND_PrimaryDestroy(device);
-        if (hr != DS_OK)
-            WARN("DSOUND_PrimaryDestroy failed\n");
+static const IUnknownVtbl unk_vtbl =
+{
+    IUnknownImpl_QueryInterface,
+    IUnknownImpl_AddRef,
+    IUnknownImpl_Release
+};
 
-        if(device->client)
-            IAudioClient_Release(device->client);
-        if(device->render)
-            IAudioRenderClient_Release(device->render);
-        if(device->clock)
-            IAudioClock_Release(device->clock);
-        if(device->volume)
-            IAudioStreamVolume_Release(device->volume);
+/*******************************************************************************
+ *      IDirectSound and IDirectSound8 Implementation
+ */
+static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
+{
+    return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
+}
 
-        HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
-        HeapFree(GetProcessHeap(), 0, device->mix_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);
-    }
-    return ref;
+static HRESULT WINAPI IDirectSound8Impl_QueryInterface(IDirectSound8 *iface, REFIID riid,
+        void **ppv)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
+    return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
 }
 
-BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
-        DWORD depth, WORD channels)
+static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
 {
-    WAVEFORMATEX fmt, *junk;
-    HRESULT hr;
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    ULONG ref = InterlockedIncrement(&This->refds);
 
-    fmt.wFormatTag = WAVE_FORMAT_PCM;
-    fmt.nChannels = channels;
-    fmt.nSamplesPerSec = rate;
-    fmt.wBitsPerSample = depth;
-    fmt.nBlockAlign = (channels * depth) / 8;
-    fmt.nAvgBytesPerSec = rate * fmt.nBlockAlign;
-    fmt.cbSize = 0;
+    TRACE("(%p) refds=%d\n", This, ref);
 
-    hr = IAudioClient_IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED, &fmt, &junk);
-    if(SUCCEEDED(hr))
-        CoTaskMemFree(junk);
+    if(ref == 1)
+        InterlockedIncrement(&This->numIfaces);
 
-    return hr == S_OK;
+    return ref;
 }
 
-HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
+static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
 {
-    HRESULT hr = DS_OK;
-    GUID devGUID;
-    DirectSoundDevice *device;
-    IMMDevice *mmdevice;
-
-    TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    ULONG ref = InterlockedDecrement(&(This->refds));
 
-    if (*ppDevice != NULL) {
-        WARN("already initialized\n");
-        return DSERR_ALREADYINITIALIZED;
-    }
+    TRACE("(%p) refds=%d\n", This, ref);
 
-    /* Default device? */
-    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
-        lpcGUID = &DSDEVID_DefaultPlayback;
+    if (!ref && !InterlockedDecrement(&This->numIfaces))
+        directsound_destroy(This);
 
-    if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
-            IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
-        return DSERR_NODRIVER;
+    return ref;
+}
 
-    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
-        WARN("invalid parameter: lpcGUID\n");
-        return DSERR_INVALIDPARAM;
-    }
+static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
+        const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    TRACE("(%p,%p,%p,%p)\n", This, dsbd, ppdsb, lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(This->device, dsbd, ppdsb, lpunk, This->has_ds8);
+}
 
-    hr = get_mmdevice(eRender, &devGUID, &mmdevice);
-    if(FAILED(hr))
-        return hr;
+static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    EnterCriticalSection(&DSOUND_renderers_lock);
+    TRACE("(%p, %p)\n", This, dscaps);
 
-    LIST_FOR_EACH_ENTRY(device, &DSOUND_renderers, DirectSoundDevice, entry){
-        if(IsEqualGUID(&device->guid, &devGUID)){
-            IMMDevice_Release(mmdevice);
-            DirectSoundDevice_AddRef(device);
-            *ppDevice = device;
-            LeaveCriticalSection(&DSOUND_renderers_lock);
-            return DS_OK;
-        }
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
-
-    hr = DirectSoundDevice_Create(&device);
-    if(FAILED(hr)){
-        WARN("DirectSoundDevice_Create failed\n");
-        IMMDevice_Release(mmdevice);
-        LeaveCriticalSection(&DSOUND_renderers_lock);
-        return hr;
+    if (!dscaps) {
+        WARN("invalid parameter: dscaps = NULL\n");
+        return DSERR_INVALIDPARAM;
     }
-
-    device->mmdevice = mmdevice;
-    device->guid = devGUID;
-    device->sleepev = CreateEventW(0, 0, 0, 0);
-
-    hr = DSOUND_ReopenDevice(device, FALSE);
-    if (FAILED(hr))
-    {
-        HeapFree(GetProcessHeap(), 0, device);
-        LeaveCriticalSection(&DSOUND_renderers_lock);
-        IMMDevice_Release(mmdevice);
-        WARN("DSOUND_ReopenDevice failed: %08x\n", hr);
-        return hr;
+    if (dscaps->dwSize < sizeof(*dscaps)) {
+        WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
+        return DSERR_INVALIDPARAM;
     }
 
-    ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
-
-    if(DSOUND_check_supported(device->client, 11025, 8, 1) ||
-            DSOUND_check_supported(device->client, 22050, 8, 1) ||
-            DSOUND_check_supported(device->client, 44100, 8, 1) ||
-            DSOUND_check_supported(device->client, 48000, 8, 1) ||
-            DSOUND_check_supported(device->client, 96000, 8, 1))
-        device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYMONO;
-
-    if(DSOUND_check_supported(device->client, 11025, 16, 1) ||
-            DSOUND_check_supported(device->client, 22050, 16, 1) ||
-            DSOUND_check_supported(device->client, 44100, 16, 1) ||
-            DSOUND_check_supported(device->client, 48000, 16, 1) ||
-            DSOUND_check_supported(device->client, 96000, 16, 1))
-        device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYMONO;
-
-    if(DSOUND_check_supported(device->client, 11025, 8, 2) ||
-            DSOUND_check_supported(device->client, 22050, 8, 2) ||
-            DSOUND_check_supported(device->client, 44100, 8, 2) ||
-            DSOUND_check_supported(device->client, 48000, 8, 2) ||
-            DSOUND_check_supported(device->client, 96000, 8, 2))
-        device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT | DSCAPS_PRIMARYSTEREO;
+    dscaps->dwFlags                        = This->device->drvcaps.dwFlags;
+    dscaps->dwMinSecondarySampleRate       = This->device->drvcaps.dwMinSecondarySampleRate;
+    dscaps->dwMaxSecondarySampleRate       = This->device->drvcaps.dwMaxSecondarySampleRate;
+    dscaps->dwPrimaryBuffers               = This->device->drvcaps.dwPrimaryBuffers;
+    dscaps->dwMaxHwMixingAllBuffers        = This->device->drvcaps.dwMaxHwMixingAllBuffers;
+    dscaps->dwMaxHwMixingStaticBuffers     = This->device->drvcaps.dwMaxHwMixingStaticBuffers;
+    dscaps->dwMaxHwMixingStreamingBuffers  = This->device->drvcaps.dwMaxHwMixingStreamingBuffers;
+    dscaps->dwFreeHwMixingAllBuffers       = This->device->drvcaps.dwFreeHwMixingAllBuffers;
+    dscaps->dwFreeHwMixingStaticBuffers    = This->device->drvcaps.dwFreeHwMixingStaticBuffers;
+    dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers;
+    dscaps->dwMaxHw3DAllBuffers            = This->device->drvcaps.dwMaxHw3DAllBuffers;
+    dscaps->dwMaxHw3DStaticBuffers         = This->device->drvcaps.dwMaxHw3DStaticBuffers;
+    dscaps->dwMaxHw3DStreamingBuffers      = This->device->drvcaps.dwMaxHw3DStreamingBuffers;
+    dscaps->dwFreeHw3DAllBuffers           = This->device->drvcaps.dwFreeHw3DAllBuffers;
+    dscaps->dwFreeHw3DStaticBuffers        = This->device->drvcaps.dwFreeHw3DStaticBuffers;
+    dscaps->dwFreeHw3DStreamingBuffers     = This->device->drvcaps.dwFreeHw3DStreamingBuffers;
+    dscaps->dwTotalHwMemBytes              = This->device->drvcaps.dwTotalHwMemBytes;
+    dscaps->dwFreeHwMemBytes               = This->device->drvcaps.dwFreeHwMemBytes;
+    dscaps->dwMaxContigFreeHwMemBytes      = This->device->drvcaps.dwMaxContigFreeHwMemBytes;
+    dscaps->dwUnlockTransferRateHwBuffers  = This->device->drvcaps.dwUnlockTransferRateHwBuffers;
+    dscaps->dwPlayCpuOverheadSwBuffers     = This->device->drvcaps.dwPlayCpuOverheadSwBuffers;
 
-    if(DSOUND_check_supported(device->client, 11025, 16, 2) ||
-            DSOUND_check_supported(device->client, 22050, 16, 2) ||
-            DSOUND_check_supported(device->client, 44100, 16, 2) ||
-            DSOUND_check_supported(device->client, 48000, 16, 2) ||
-            DSOUND_check_supported(device->client, 96000, 16, 2))
-        device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT | DSCAPS_PRIMARYSTEREO;
+    if (TRACE_ON(dsound)) {
+        TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
+        _dump_DSCAPS(dscaps->dwFlags);
+        TRACE(")\n");
+    }
 
-    /* the dsound mixer supports all of the following */
-    device->drvcaps.dwFlags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT;
-    device->drvcaps.dwFlags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO;
-    device->drvcaps.dwFlags |= DSCAPS_CONTINUOUSRATE;
+    return DS_OK;
+}
 
-    device->drvcaps.dwPrimaryBuffers = 1;
-    device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
-    device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
-    device->drvcaps.dwMaxHwMixingAllBuffers = 1;
-    device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
-    device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
+static HRESULT WINAPI IDirectSound8Impl_DuplicateSoundBuffer(IDirectSound8 *iface,
+        IDirectSoundBuffer *psb, IDirectSoundBuffer **ppdsb)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    TRACE("(%p,%p,%p)\n", This, psb, ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(This->device, psb, ppdsb);
+}
 
-    ZeroMemory(&device->volpan, sizeof(device->volpan));
+static HRESULT WINAPI IDirectSound8Impl_SetCooperativeLevel(IDirectSound8 *iface, HWND hwnd,
+        DWORD level)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    DirectSoundDevice *device = This->device;
+    DWORD oldlevel;
+    HRESULT hr = S_OK;
 
-    hr = DSOUND_PrimaryCreate(device);
-    if (hr == DS_OK) {
-        device->thread = CreateThread(0, 0, DSOUND_mixthread, device, 0, 0);
-        SetThreadPriority(device->thread, THREAD_PRIORITY_TIME_CRITICAL);
-    } else
-        WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
+    TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
 
-    *ppDevice = device;
-    list_add_tail(&DSOUND_renderers, &device->entry);
+    if (!device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    LeaveCriticalSection(&DSOUND_renderers_lock);
+    if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
+        WARN("level=%s not fully supported\n",
+             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
+    }
 
+    RtlAcquireResourceExclusive(&device->buffer_list_lock, TRUE);
+    EnterCriticalSection(&device->mixlock);
+    oldlevel = device->priolevel;
+    device->priolevel = level;
+    if ((level == DSSCL_WRITEPRIMARY) != (oldlevel == DSSCL_WRITEPRIMARY)) {
+        hr = DSOUND_ReopenDevice(device, level == DSSCL_WRITEPRIMARY);
+        if (FAILED(hr))
+            device->priolevel = oldlevel;
+        else
+            DSOUND_PrimaryOpen(device);
+    }
+    LeaveCriticalSection(&device->mixlock);
+    RtlReleaseResource(&device->buffer_list_lock);
     return hr;
 }
 
-HRESULT DirectSoundDevice_CreateSoundBuffer(
-    DirectSoundDevice * device,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk,
-    BOOL from8)
+static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
 {
-    HRESULT hres = DS_OK;
-    TRACE("(%p,%p,%p,%p)\n",device,dsbd,ppdsb,lpunk);
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    if (device == NULL) {
+    TRACE("(%p)\n", This);
+
+    if (!This->device) {
         WARN("not initialized\n");
         return DSERR_UNINITIALIZED;
     }
 
-    if (dsbd == NULL) {
-        WARN("invalid parameter: dsbd == NULL\n");
-        return DSERR_INVALIDPARAM;
+    if (This->device->priolevel < DSSCL_PRIORITY) {
+        WARN("incorrect priority level\n");
+        return DSERR_PRIOLEVELNEEDED;
     }
+    return DS_OK;
+}
 
-    if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
-        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
-        WARN("invalid parameter: dsbd\n");
-        return DSERR_INVALIDPARAM;
-    }
+static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    if (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-    *ppdsb = NULL;
+    TRACE("(%p, %p)\n", This, config);
 
-    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);
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
-
-    if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
-            !(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
-        TRACE("LOCHARDWARE is not supported, returning E_NOTIMPL\n");
-        return E_NOTIMPL;
+    if (!config) {
+        WARN("invalid parameter: config == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    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 {
-            hres = primarybuffer_create(device, &device->primary, dsbd);
-            if (device->primary) {
-                *ppdsb = (IDirectSoundBuffer*)&device->primary->IDirectSoundBuffer8_iface;
-                device->primary->dsbd.dwFlags &= ~(DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE);
-                device->primary->dsbd.dwFlags |= DSBCAPS_LOCSOFTWARE;
-            } else
-                WARN("primarybuffer_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.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
-        {
-            /* check if cbSize is at least 22 bytes */
-            if (pwfxe->Format.cbSize < (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)))
-            {
-                WARN("Too small a cbSize %u\n", pwfxe->Format.cbSize);
-                return DSERR_INVALIDPARAM;
-            }
-
-            /* cbSize should be 22 bytes, with one possible exception */
-            if (pwfxe->Format.cbSize > (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) &&
-                !((IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) &&
-                pwfxe->Format.cbSize == sizeof(WAVEFORMATEXTENSIBLE)))
-            {
-                WARN("Too big a cbSize %u\n", pwfxe->Format.cbSize);
-                return DSERR_CONTROLUNAVAIL;
-            }
+    WARN("not fully functional\n");
+    *config = This->device->speaker_config;
+    return DS_OK;
+}
 
-            if ((!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) && (!IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
-            {
-                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;
-            }
-        }
+static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-        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);
+    TRACE("(%p,0x%08x)\n", This, config);
 
-        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
-            WARN("invalid parameter: 3D buffer format must be mono\n");
-            return DSERR_INVALIDPARAM;
-        }
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-        hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
-        if (dsb)
-            *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
-        else
-            WARN("IDirectSoundBufferImpl_Create failed\n");
-   }
+    This->device->speaker_config = config;
+    WARN("not fully functional\n");
+    return DS_OK;
+}
 
-   return hres;
+static HRESULT WINAPI IDirectSound8Impl_Initialize(IDirectSound8 *iface, const GUID *lpcGuid)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&This->device, lpcGuid);
 }
 
-HRESULT DirectSoundDevice_DuplicateSoundBuffer(
-    DirectSoundDevice * device,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
+static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
 {
-    HRESULT hres = DS_OK;
-    IDirectSoundBufferImpl* dsb;
-    TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    if (device == NULL) {
+    TRACE("(%p, %p)\n", This, certified);
+
+    if (!This->device) {
         WARN("not initialized\n");
         return DSERR_UNINITIALIZED;
     }
 
-    if (psb == NULL) {
-        WARN("invalid parameter: psb == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
+        *certified = DS_CERTIFIED;
+    else
+        *certified = DS_UNCERTIFIED;
 
-    if (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    return DS_OK;
+}
 
-    /* make sure we have a secondary buffer */
-    if (psb == (IDirectSoundBuffer *)&device->primary->IDirectSoundBuffer8_iface) {
-        WARN("trying to duplicate primary buffer\n");
-        *ppdsb = NULL;
-        return DSERR_INVALIDCALL;
+static const IDirectSound8Vtbl ds8_vtbl =
+{
+    IDirectSound8Impl_QueryInterface,
+    IDirectSound8Impl_AddRef,
+    IDirectSound8Impl_Release,
+    IDirectSound8Impl_CreateSoundBuffer,
+    IDirectSound8Impl_GetCaps,
+    IDirectSound8Impl_DuplicateSoundBuffer,
+    IDirectSound8Impl_SetCooperativeLevel,
+    IDirectSound8Impl_Compact,
+    IDirectSound8Impl_GetSpeakerConfig,
+    IDirectSound8Impl_SetSpeakerConfig,
+    IDirectSound8Impl_Initialize,
+    IDirectSound8Impl_VerifyCertification
+};
+
+HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
+{
+    IDirectSoundImpl *obj;
+    HRESULT hr;
+
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
+    if (!obj) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
     }
 
-    /* duplicate the actual buffer implementation */
-    hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
-    if (hres == DS_OK)
-        *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
+    setup_dsound_options();
+
+    obj->IUnknown_inner.lpVtbl = &unk_vtbl;
+    obj->IDirectSound8_iface.lpVtbl = &ds8_vtbl;
+    obj->ref = 1;
+    obj->refds = 0;
+    obj->numIfaces = 1;
+    obj->device = NULL;
+    obj->has_ds8 = has_ds8;
+
+    /* COM aggregation supported only internally */
+    if (outer_unk)
+        obj->outer_unk = outer_unk;
     else
-        WARN("IDirectSoundBufferImpl_Duplicate failed\n");
+        obj->outer_unk = &obj->IUnknown_inner;
 
-    return hres;
+    hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
+    IUnknown_Release(&obj->IUnknown_inner);
+
+    return hr;
 }
 
-/*
- * Add secondary buffer to buffer list.
- * Gets exclusive access to buffer for writing.
+HRESULT DSOUND_Create(REFIID riid, void **ppv)
+{
+    return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
+}
+
+HRESULT DSOUND_Create8(REFIID riid, void **ppv)
+{
+    return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
+}
+
+/*******************************************************************************
+ *		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 DirectSoundDevice_AddBuffer(
-    DirectSoundDevice * device,
-    IDirectSoundBufferImpl * pDSB)
+HRESULT WINAPI DirectSoundCreate(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUND *ppDS,
+    IUnknown *pUnkOuter)
 {
-    IDirectSoundBufferImpl **newbuffers;
-    HRESULT hr = DS_OK;
+    HRESULT hr;
+    LPDIRECTSOUND pDS;
 
-    TRACE("(%p, %p)\n", device, pDSB);
+    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
 
-    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
+    if (ppDS == NULL) {
+        WARN("invalid parameter: ppDS == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-    if (device->buffers)
-        newbuffers = HeapReAlloc(GetProcessHeap(),0,device->buffers,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
-    else
-        newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(device->nrofbuffers+1));
+    if (pUnkOuter != NULL) {
+        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDS = 0;
+        return DSERR_INVALIDPARAM;
+    }
 
-    if (newbuffers) {
-        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", device->nrofbuffers);
-        hr = DSERR_OUTOFMEMORY;
+    hr = DSOUND_Create(&IID_IDirectSound, (void **)&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;
+        }
     }
 
-    RtlReleaseResource(&(device->buffer_list_lock));
+    *ppDS = pDS;
 
     return hr;
 }
 
-/*
- * Remove secondary buffer from buffer list.
- * Gets exclusive access to buffer for writing.
+/*******************************************************************************
+ *        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
  */
-void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
+HRESULT WINAPI DirectSoundCreate8(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUND8 *ppDS,
+    IUnknown *pUnkOuter)
 {
-    int i;
+    HRESULT hr;
+    LPDIRECTSOUND8 pDS;
 
-    TRACE("(%p, %p)\n", device, pDSB);
+    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
 
-    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
+    if (ppDS == NULL) {
+        WARN("invalid parameter: ppDS == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-    if (device->nrofbuffers == 1) {
-        assert(device->buffers[0] == pDSB);
-        HeapFree(GetProcessHeap(), 0, device->buffers);
-        device->buffers = NULL;
-    } else {
-        for (i = 0; i < device->nrofbuffers; i++) {
-            if (device->buffers[i] == pDSB) {
-                /* Put the last buffer of the list in the (now empty) position */
-                device->buffers[i] = device->buffers[device->nrofbuffers - 1];
-                break;
-            }
+    if (pUnkOuter != NULL) {
+        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDS = 0;
+        return DSERR_INVALIDPARAM;
+    }
+
+    hr = DSOUND_Create8(&IID_IDirectSound8, (void **)&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;
         }
     }
-    device->nrofbuffers--;
-    TRACE("buffer count is now %d\n", device->nrofbuffers);
 
-    RtlReleaseResource(&(device->buffer_list_lock));
+    *ppDS = pDS;
+
+    return hr;
 }
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 66af81a..36285b4 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -107,24 +107,10 @@ typedef struct BufferMemory
     struct list buffers;
 } BufferMemory;
 
-ULONG DirectSoundDevice_Release(DirectSoundDevice * device) DECLSPEC_HIDDEN;
-HRESULT DirectSoundDevice_Initialize(
-    DirectSoundDevice ** ppDevice,
-    LPCGUID lpcGUID) DECLSPEC_HIDDEN;
 HRESULT DirectSoundDevice_AddBuffer(
     DirectSoundDevice * device,
     IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN;
 void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB) DECLSPEC_HIDDEN;
-HRESULT DirectSoundDevice_CreateSoundBuffer(
-    DirectSoundDevice * device,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk,
-    BOOL from8) DECLSPEC_HIDDEN;
-HRESULT DirectSoundDevice_DuplicateSoundBuffer(
-    DirectSoundDevice * device,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb) DECLSPEC_HIDDEN;
 
 /*****************************************************************************
  * IDirectSoundBuffer implementation structure
-- 
2.1.4




More information about the wine-patches mailing list