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

Francois Gouget fgouget at free.fr
Mon Jan 19 20:28:02 CST 2015


---

I'm resubmitting this pair now that there's less traffic in dsound. Of 
course this first patch was recreated from the updated code (pretty easy 
really, all it takes is moving up DirectSoundDevice 'en masse').

 dlls/dsound/dsound.c         | 1675 +++++++++++++++++++++---------------------
 dlls/dsound/dsound_private.h |   14 -
 2 files changed, 838 insertions(+), 851 deletions(-)

diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c
index ab050b5..2a41967 100644
--- a/dlls/dsound/dsound.c
+++ b/dlls/dsound/dsound.c
@@ -119,1075 +119,1076 @@ 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;
+    DSOUND_ParseSpeakerConfig(device);
 
-    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;
+    /* 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(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 (!dscaps) {
-        WARN("invalid parameter: dscaps = NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-    if (dscaps->dwSize < sizeof(*dscaps)) {
-        WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
-        return DSERR_INVALIDPARAM;
+    if (*ppDevice != NULL) {
+        WARN("already initialized\n");
+        return DSERR_ALREADYINITIALIZED;
     }
 
-    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;
+    /* Default device? */
+    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
+        lpcGUID = &DSDEVID_DefaultPlayback;
 
-    if (This->device->drvcaps.dwFreeHwMixingAllBuffers > 0) {
-        dscaps->dwFreeHwMixingStaticBuffers    = This->device->drvcaps.dwFreeHwMixingStaticBuffers;
-        dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers;
-    } else {
-        dscaps->dwFreeHwMixingStaticBuffers    = 0;
-        dscaps->dwFreeHwMixingStreamingBuffers = 0;
+    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;
     }
 
-    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 (TRACE_ON(dsound)) {
-        TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
-        _dump_DSCAPS(dscaps->dwFlags);
-        TRACE(")\n");
-    }
-
-    return DS_OK;
-}
-
-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);
-}
-
-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;
-
-    TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
+    hr = get_mmdevice(eRender, &devGUID, &mmdevice);
+    if(FAILED(hr))
+        return hr;
 
-    if (!device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    EnterCriticalSection(&DSOUND_renderers_lock);
 
-    if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
-        WARN("level=%s not fully supported\n",
-             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
+    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;
+        }
     }
 
-    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);
+    hr = DirectSoundDevice_Create(&device);
+    if(FAILED(hr)){
+        WARN("DirectSoundDevice_Create failed\n");
+        IMMDevice_Release(mmdevice);
+        LeaveCriticalSection(&DSOUND_renderers_lock);
+        return hr;
     }
-    LeaveCriticalSection(&device->mixlock);
-    RtlReleaseResource(&device->buffer_list_lock);
-    return hr;
-}
-
-static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    TRACE("(%p)\n", This);
+    device->mmdevice = mmdevice;
+    device->guid = devGUID;
+    device->sleepev = CreateEventW(0, 0, 0, 0);
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
+    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 (This->device->priolevel < DSSCL_PRIORITY) {
-        WARN("incorrect priority level\n");
-        return DSERR_PRIOLEVELNEEDED;
-    }
-    return DS_OK;
-}
+    ZeroMemory(&device->drvcaps, sizeof(device->drvcaps));
 
-static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    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;
 
-    TRACE("(%p, %p)\n", This, config);
+    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 (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
-    if (!config) {
-        WARN("invalid parameter: config == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
+    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;
 
-    WARN("not fully functional\n");
-    *config = This->device->speaker_config;
-    return DS_OK;
-}
+    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;
 
-static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
-{
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    /* 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;
 
-    TRACE("(%p,0x%08x)\n", This, config);
+    device->drvcaps.dwPrimaryBuffers = 1;
+    device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
+    device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
+    device->drvcaps.dwMaxHwMixingAllBuffers = 16;
+    device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
+    device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
+    device->drvcaps.dwFreeHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
+    device->drvcaps.dwFreeHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
+    device->drvcaps.dwFreeHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
 
-    if (!This->device) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+    ZeroMemory(&device->volpan, sizeof(device->volpan));
 
-    /* NOP on Vista and above */
+    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);
 
-    return DS_OK;
-}
+    *ppDevice = device;
+    list_add_tail(&DSOUND_renderers, &device->entry);
 
-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);
+    LeaveCriticalSection(&DSOUND_renderers_lock);
+
+    return hr;
 }
 
-static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
+HRESULT DirectSoundDevice_CreateSoundBuffer(
+    DirectSoundDevice * device,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk,
+    BOOL from8)
 {
-    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
-
-    TRACE("(%p, %p)\n", This, certified);
+    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 (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
-        *certified = DS_CERTIFIED;
-    else
-        *certified = DS_UNCERTIFIED;
-
-    return DS_OK;
-}
+    if (dsbd == NULL) {
+        WARN("invalid parameter: dsbd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-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 (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
+        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
+        WARN("invalid parameter: dsbd\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
-{
-    IDirectSoundImpl *obj;
-    HRESULT hr;
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+    *ppdsb = NULL;
 
-    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
+    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);
+    }
 
-    *ppv = NULL;
-    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
-    if (!obj) {
-        WARN("out of memory\n");
-        return DSERR_OUTOFMEMORY;
+    if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) &&
+        dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
+        device->drvcaps.dwFreeHwMixingAllBuffers == 0)
+    {
+        WARN("ran out of emulated hardware buffers\n");
+        return DSERR_ALLOCATED;
     }
 
-    setup_dsound_options();
+    if (dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) {
+        if (dsbd->lpwfxFormat != NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat must be NULL for "
+                 "primary buffer\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;
+        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;
 
-    /* COM aggregation supported only internally */
-    if (outer_unk)
-        obj->outer_unk = outer_unk;
-    else
-        obj->outer_unk = &obj->IUnknown_inner;
+        if (dsbd->lpwfxFormat == NULL) {
+            WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
+                 "secondary buffer\n");
+            return DSERR_INVALIDPARAM;
+        }
+        pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
 
-    hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
-    IUnknown_Release(&obj->IUnknown_inner);
+        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;
+            }
 
-    return hr;
-}
+            /* 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;
+            }
 
-HRESULT DSOUND_Create(REFIID riid, void **ppv)
-{
-    return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
-}
+            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;
+            }
+        }
 
-HRESULT DSOUND_Create8(REFIID riid, void **ppv)
-{
-    return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
+        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);
+
+        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
+            WARN("invalid parameter: 3D buffer format must be mono\n");
+            return DSERR_INVALIDPARAM;
+        }
+
+        hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
+        if (dsb) {
+            *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
+            if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
+                device->drvcaps.dwFreeHwMixingAllBuffers--;
+        } else
+            WARN("IDirectSoundBufferImpl_Create failed\n");
+   }
+
+   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
- */
-HRESULT WINAPI DirectSoundCreate(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_DuplicateSoundBuffer(
+    DirectSoundDevice * device,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
 {
-    HRESULT hr;
-    LPDIRECTSOUND pDS;
+    HRESULT hres = DS_OK;
+    IDirectSoundBufferImpl* dsb;
+    TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
 
-    TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter);
+    if (device == NULL) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    if (ppDS == NULL) {
-        WARN("invalid parameter: ppDS == NULL\n");
+    if (psb == NULL) {
+        WARN("invalid parameter: psb == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (pUnkOuter != NULL) {
-        WARN("invalid parameter: pUnkOuter != NULL\n");
-        *ppDS = 0;
+    if (ppdsb == NULL) {
+        WARN("invalid parameter: ppdsb == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    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;
-        }
+    /* 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;
     }
 
-    *ppDS = pDS;
+    /* duplicate the actual buffer implementation */
+    hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
+    if (hres == DS_OK)
+        *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
+    else
+        WARN("IDirectSoundBufferImpl_Duplicate failed\n");
 
-    return hr;
+    return hres;
 }
 
-/*******************************************************************************
- *        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
+/*
+ * Add secondary buffer to buffer list.
+ * Gets exclusive access to buffer for writing.
  */
-HRESULT WINAPI DirectSoundCreate8(
-    LPCGUID lpcGUID,
-    LPDIRECTSOUND8 *ppDS,
-    IUnknown *pUnkOuter)
+HRESULT DirectSoundDevice_AddBuffer(
+    DirectSoundDevice * device,
+    IDirectSoundBufferImpl * pDSB)
 {
-    HRESULT hr;
-    LPDIRECTSOUND8 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_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 (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;
 }
 
-void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device)
+/*
+ * Remove secondary buffer from buffer list.
+ * Gets exclusive access to buffer for writing.
+ */
+void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
 {
-    switch (DSSPEAKER_CONFIG(device->speaker_config)) {
-        case DSSPEAKER_MONO:
-            device->speaker_angles[0] = M_PI/180.0f * 0.0f;
-            device->speaker_num[0] = 0;
-            device->num_speakers = 1;
-            device->lfe_channel = -1;
-        break;
+    int i;
 
-        case DSSPEAKER_STEREO:
-        case DSSPEAKER_HEADPHONE:
-            device->speaker_angles[0] = M_PI/180.0f * -90.0f;
-            device->speaker_angles[1] = M_PI/180.0f *  90.0f;
-            device->speaker_num[0] = 0; /* Left */
-            device->speaker_num[1] = 1; /* Right */
-            device->num_speakers = 2;
-            device->lfe_channel = -1;
-        break;
-
-        case DSSPEAKER_QUAD:
-            device->speaker_angles[0] = M_PI/180.0f * -135.0f;
-            device->speaker_angles[1] = M_PI/180.0f *  -45.0f;
-            device->speaker_angles[2] = M_PI/180.0f *   45.0f;
-            device->speaker_angles[3] = M_PI/180.0f *  135.0f;
-            device->speaker_num[0] = 2; /* Rear left */
-            device->speaker_num[1] = 0; /* Front left */
-            device->speaker_num[2] = 1; /* Front right */
-            device->speaker_num[3] = 3; /* Rear right */
-            device->num_speakers = 4;
-            device->lfe_channel = -1;
-        break;
-
-        case DSSPEAKER_5POINT1_BACK:
-            device->speaker_angles[0] = M_PI/180.0f * -135.0f;
-            device->speaker_angles[1] = M_PI/180.0f *  -45.0f;
-            device->speaker_angles[2] = M_PI/180.0f *    0.0f;
-            device->speaker_angles[3] = M_PI/180.0f *   45.0f;
-            device->speaker_angles[4] = M_PI/180.0f *  135.0f;
-            device->speaker_angles[5] = 9999.0f;
-            device->speaker_num[0] = 4; /* Rear left */
-            device->speaker_num[1] = 0; /* Front left */
-            device->speaker_num[2] = 2; /* Front centre */
-            device->speaker_num[3] = 1; /* Front right */
-            device->speaker_num[4] = 5; /* Rear right */
-            device->speaker_num[5] = 3; /* LFE */
-            device->num_speakers = 6;
-            device->lfe_channel = 3;
-        break;
+    TRACE("(%p, %p)\n", device, pDSB);
 
-        case DSSPEAKER_5POINT1_SURROUND:
-            device->speaker_angles[0] = M_PI/180.0f *  -90.0f;
-            device->speaker_angles[1] = M_PI/180.0f *  -30.0f;
-            device->speaker_angles[2] = M_PI/180.0f *    0.0f;
-            device->speaker_angles[3] = M_PI/180.0f *   30.0f;
-            device->speaker_angles[4] = M_PI/180.0f *   90.0f;
-            device->speaker_angles[5] = 9999.0f;
-            device->speaker_num[0] = 4; /* Rear left */
-            device->speaker_num[1] = 0; /* Front left */
-            device->speaker_num[2] = 2; /* Front centre */
-            device->speaker_num[3] = 1; /* Front right */
-            device->speaker_num[4] = 5; /* Rear right */
-            device->speaker_num[5] = 3; /* LFE */
-            device->num_speakers = 6;
-            device->lfe_channel = 3;
-        break;
+    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
 
-        default:
-            WARN("unknown speaker_config %u\n", device->speaker_config);
+    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);
+
+    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);
+}
 
-    DSOUND_ParseSpeakerConfig(device);
+static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
+{
+    IDirectSoundImpl *This = impl_from_IUnknown(iface);
 
-    /* 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;
+    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
 
-    device->prebuf = ds_snd_queue_max;
-    device->guid = GUID_NULL;
+    if (!ppv) {
+        WARN("invalid parameter\n");
+        return E_INVALIDARG;
+    }
+    *ppv = 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;
+    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->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));
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
 
-    InitializeCriticalSection(&(device->mixlock));
-    device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DirectSoundDevice.mixlock");
+static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
+{
+    IDirectSoundImpl *This = impl_from_IUnknown(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
 
-    RtlInitializeResource(&(device->buffer_list_lock));
+    TRACE("(%p) ref=%d\n", This, ref);
 
-   *ppDevice = device;
+    if(ref == 1)
+        InterlockedIncrement(&This->numIfaces);
 
-    return DS_OK;
+    return ref;
 }
 
-static ULONG DirectSoundDevice_AddRef(DirectSoundDevice * device)
+static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
 {
-    ULONG ref = InterlockedIncrement(&(device->ref));
-    TRACE("(%p) ref was %d\n", device, ref - 1);
+    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);
+
     return ref;
 }
 
-ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
+static const IUnknownVtbl unk_vtbl =
 {
-    HRESULT hr;
-    ULONG ref = InterlockedDecrement(&(device->ref));
-    TRACE("(%p) ref was %u\n", device, ref + 1);
-    if (!ref) {
-        int i;
+    IUnknownImpl_QueryInterface,
+    IUnknownImpl_AddRef,
+    IUnknownImpl_Release
+};
 
-        SetEvent(device->sleepev);
-        if (device->thread) {
-            WaitForSingleObject(device->thread, INFINITE);
-            CloseHandle(device->thread);
-        }
-        CloseHandle(device->sleepev);
+/*******************************************************************************
+ *      IDirectSound and IDirectSound8 Implementation
+ */
+static inline IDirectSoundImpl *impl_from_IDirectSound8(IDirectSound8 *iface)
+{
+    return CONTAINING_RECORD(iface, IDirectSoundImpl, IDirectSound8_iface);
+}
 
-        EnterCriticalSection(&DSOUND_renderers_lock);
-        list_remove(&device->entry);
-        LeaveCriticalSection(&DSOUND_renderers_lock);
+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);
+}
 
-        /* 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]);
-        }
+static ULONG WINAPI IDirectSound8Impl_AddRef(IDirectSound8 *iface)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    ULONG ref = InterlockedIncrement(&This->refds);
 
-        hr = DSOUND_PrimaryDestroy(device);
-        if (hr != DS_OK)
-            WARN("DSOUND_PrimaryDestroy failed\n");
+    TRACE("(%p) refds=%d\n", This, ref);
 
-        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);
+    if(ref == 1)
+        InterlockedIncrement(&This->numIfaces);
 
-        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;
 }
 
-BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate,
-        DWORD depth, WORD channels)
+static ULONG WINAPI IDirectSound8Impl_Release(IDirectSound8 *iface)
 {
-    WAVEFORMATEX fmt, *junk;
-    HRESULT hr;
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+    ULONG ref = InterlockedDecrement(&(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 && !InterlockedDecrement(&This->numIfaces))
+        directsound_destroy(This);
 
-    return hr == S_OK;
+    return ref;
 }
 
-HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcGUID)
+static HRESULT WINAPI IDirectSound8Impl_CreateSoundBuffer(IDirectSound8 *iface,
+        const DSBUFFERDESC *dsbd, IDirectSoundBuffer **ppdsb, IUnknown *lpunk)
 {
-    HRESULT hr = DS_OK;
-    GUID devGUID;
-    DirectSoundDevice *device;
-    IMMDevice *mmdevice;
-
-    TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
-
-    if (*ppDevice != NULL) {
-        WARN("already initialized\n");
-        return DSERR_ALREADYINITIALIZED;
-    }
+    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);
+}
 
-    /* Default device? */
-    if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL))
-        lpcGUID = &DSDEVID_DefaultPlayback;
+static HRESULT WINAPI IDirectSound8Impl_GetCaps(IDirectSound8 *iface, DSCAPS *dscaps)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    if(IsEqualGUID(lpcGUID, &DSDEVID_DefaultCapture) ||
-            IsEqualGUID(lpcGUID, &DSDEVID_DefaultVoiceCapture))
-        return DSERR_NODRIVER;
+    TRACE("(%p, %p)\n", This, dscaps);
 
-    if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) {
-        WARN("invalid parameter: lpcGUID\n");
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
+    if (!dscaps) {
+        WARN("invalid parameter: dscaps = NULL\n");
         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;
-        }
+    if (dscaps->dwSize < sizeof(*dscaps)) {
+        WARN("invalid parameter: dscaps->dwSize = %d\n", dscaps->dwSize);
+        return DSERR_INVALIDPARAM;
     }
 
-    hr = DirectSoundDevice_Create(&device);
-    if(FAILED(hr)){
-        WARN("DirectSoundDevice_Create failed\n");
-        IMMDevice_Release(mmdevice);
-        LeaveCriticalSection(&DSOUND_renderers_lock);
-        return hr;
+    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;
+
+    if (This->device->drvcaps.dwFreeHwMixingAllBuffers > 0) {
+        dscaps->dwFreeHwMixingStaticBuffers    = This->device->drvcaps.dwFreeHwMixingStaticBuffers;
+        dscaps->dwFreeHwMixingStreamingBuffers = This->device->drvcaps.dwFreeHwMixingStreamingBuffers;
+    } else {
+        dscaps->dwFreeHwMixingStaticBuffers    = 0;
+        dscaps->dwFreeHwMixingStreamingBuffers = 0;
     }
 
-    device->mmdevice = mmdevice;
-    device->guid = devGUID;
-    device->sleepev = CreateEventW(0, 0, 0, 0);
+    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 = 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 (TRACE_ON(dsound)) {
+        TRACE("(flags=0x%08x:\n", dscaps->dwFlags);
+        _dump_DSCAPS(dscaps->dwFlags);
+        TRACE(")\n");
     }
 
-    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;
+    return DS_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;
+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, 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;
+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, 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;
+    TRACE("(%p,%p,%s)\n", This, hwnd, dumpCooperativeLevel(level));
 
-    /* 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;
+    if (!device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    device->drvcaps.dwPrimaryBuffers = 1;
-    device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
-    device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
-    device->drvcaps.dwMaxHwMixingAllBuffers = 16;
-    device->drvcaps.dwMaxHwMixingStaticBuffers = 1;
-    device->drvcaps.dwMaxHwMixingStreamingBuffers = 1;
-    device->drvcaps.dwFreeHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers;
-    device->drvcaps.dwFreeHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers;
-    device->drvcaps.dwFreeHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers;
+    if (level == DSSCL_PRIORITY || level == DSSCL_EXCLUSIVE) {
+        WARN("level=%s not fully supported\n",
+             level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
+    }
 
-    ZeroMemory(&device->volpan, sizeof(device->volpan));
+    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;
+}
 
-    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);
+static HRESULT WINAPI IDirectSound8Impl_Compact(IDirectSound8 *iface)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    *ppDevice = device;
-    list_add_tail(&DSOUND_renderers, &device->entry);
+    TRACE("(%p)\n", This);
 
-    LeaveCriticalSection(&DSOUND_renderers_lock);
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
+    }
 
-    return hr;
+    if (This->device->priolevel < DSSCL_PRIORITY) {
+        WARN("incorrect priority level\n");
+        return DSERR_PRIOLEVELNEEDED;
+    }
+    return DS_OK;
 }
 
-HRESULT DirectSoundDevice_CreateSoundBuffer(
-    DirectSoundDevice * device,
-    LPCDSBUFFERDESC dsbd,
-    LPLPDIRECTSOUNDBUFFER ppdsb,
-    LPUNKNOWN lpunk,
-    BOOL from8)
+static HRESULT WINAPI IDirectSound8Impl_GetSpeakerConfig(IDirectSound8 *iface, DWORD *config)
 {
-    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, %p)\n", This, config);
+
+    if (!This->device) {
         WARN("not initialized\n");
         return DSERR_UNINITIALIZED;
     }
-
-    if (dsbd == NULL) {
-        WARN("invalid parameter: dsbd == NULL\n");
+    if (!config) {
+        WARN("invalid parameter: config == NULL\n");
         return DSERR_INVALIDPARAM;
     }
 
-    if (dsbd->dwSize != sizeof(DSBUFFERDESC) &&
-        dsbd->dwSize != sizeof(DSBUFFERDESC1)) {
-        WARN("invalid parameter: dsbd\n");
-        return DSERR_INVALIDPARAM;
-    }
+    WARN("not fully functional\n");
+    *config = This->device->speaker_config;
+    return DS_OK;
+}
 
-    if (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
-        return DSERR_INVALIDPARAM;
-    }
-    *ppdsb = NULL;
+static HRESULT WINAPI IDirectSound8Impl_SetSpeakerConfig(IDirectSound8 *iface, DWORD config)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
 
-    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);
+    TRACE("(%p,0x%08x)\n", This, config);
+
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
 
-    if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) &&
-        dsbd->dwFlags & DSBCAPS_LOCHARDWARE &&
-        device->drvcaps.dwFreeHwMixingAllBuffers == 0)
-    {
-        WARN("ran out of emulated hardware buffers\n");
-        return DSERR_ALLOCATED;
+    /* NOP on Vista and above */
+
+    return DS_OK;
+}
+
+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);
+}
+
+static HRESULT WINAPI IDirectSound8Impl_VerifyCertification(IDirectSound8 *iface, DWORD *certified)
+{
+    IDirectSoundImpl *This = impl_from_IDirectSound8(iface);
+
+    TRACE("(%p, %p)\n", This, certified);
+
+    if (!This->device) {
+        WARN("not initialized\n");
+        return DSERR_UNINITIALIZED;
     }
 
-    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 (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED)
+        *certified = DS_CERTIFIED;
+    else
+        *certified = DS_UNCERTIFIED;
 
-        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;
+    return DS_OK;
+}
 
-        if (dsbd->lpwfxFormat == NULL) {
-            WARN("invalid parameter: dsbd->lpwfxFormat can't be NULL for "
-                 "secondary buffer\n");
-            return DSERR_INVALIDPARAM;
-        }
-        pwfxe = (WAVEFORMATEXTENSIBLE*)dsbd->lpwfxFormat;
+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 (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;
-            }
+HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8)
+{
+    IDirectSoundImpl *obj;
+    HRESULT hr;
 
-            /* 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;
-            }
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
 
-            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;
-            }
-        }
+    *ppv = NULL;
+    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
+    if (!obj) {
+        WARN("out of memory\n");
+        return DSERR_OUTOFMEMORY;
+    }
+
+    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;
 
-        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);
+    /* COM aggregation supported only internally */
+    if (outer_unk)
+        obj->outer_unk = outer_unk;
+    else
+        obj->outer_unk = &obj->IUnknown_inner;
 
-        if (from8 && (dsbd->dwFlags & DSBCAPS_CTRL3D) && (dsbd->lpwfxFormat->nChannels != 1)) {
-            WARN("invalid parameter: 3D buffer format must be mono\n");
-            return DSERR_INVALIDPARAM;
-        }
+    hr = IUnknown_QueryInterface(&obj->IUnknown_inner, riid, ppv);
+    IUnknown_Release(&obj->IUnknown_inner);
 
-        hres = IDirectSoundBufferImpl_Create(device, &dsb, dsbd);
-        if (dsb) {
-            *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
-            if (dsbd->dwFlags & DSBCAPS_LOCHARDWARE)
-                device->drvcaps.dwFreeHwMixingAllBuffers--;
-        } else
-            WARN("IDirectSoundBufferImpl_Create failed\n");
-   }
+    return hr;
+}
 
-   return hres;
+HRESULT DSOUND_Create(REFIID riid, void **ppv)
+{
+    return IDirectSoundImpl_Create(NULL, riid, ppv, FALSE);
 }
 
-HRESULT DirectSoundDevice_DuplicateSoundBuffer(
-    DirectSoundDevice * device,
-    LPDIRECTSOUNDBUFFER psb,
-    LPLPDIRECTSOUNDBUFFER ppdsb)
+HRESULT DSOUND_Create8(REFIID riid, void **ppv)
 {
-    HRESULT hres = DS_OK;
-    IDirectSoundBufferImpl* dsb;
-    TRACE("(%p,%p,%p)\n",device,psb,ppdsb);
+    return IDirectSoundImpl_Create(NULL, riid, ppv, TRUE);
+}
 
-    if (device == NULL) {
-        WARN("not initialized\n");
-        return DSERR_UNINITIALIZED;
-    }
+/*******************************************************************************
+ *		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 hr;
+    LPDIRECTSOUND pDS;
 
-    if (psb == NULL) {
-        WARN("invalid parameter: psb == 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 (ppdsb == NULL) {
-        WARN("invalid parameter: ppdsb == NULL\n");
+    if (pUnkOuter != NULL) {
+        WARN("invalid parameter: pUnkOuter != NULL\n");
+        *ppDS = 0;
         return DSERR_INVALIDPARAM;
     }
 
-    /* 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;
+    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;
+        }
     }
 
-    /* duplicate the actual buffer implementation */
-    hres = IDirectSoundBufferImpl_Duplicate(device, &dsb, (IDirectSoundBufferImpl*)psb);
-    if (hres == DS_OK)
-        *ppdsb = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
-    else
-        WARN("IDirectSoundBufferImpl_Duplicate failed\n");
+    *ppDS = pDS;
 
-    return hres;
+    return hr;
 }
 
-/*
- * Add secondary buffer to 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
  */
-HRESULT DirectSoundDevice_AddBuffer(
-    DirectSoundDevice * device,
-    IDirectSoundBufferImpl * pDSB)
+HRESULT WINAPI DirectSoundCreate8(
+    LPCGUID lpcGUID,
+    LPDIRECTSOUND8 *ppDS,
+    IUnknown *pUnkOuter)
 {
-    IDirectSoundBufferImpl **newbuffers;
-    HRESULT hr = DS_OK;
+    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->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_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;
+        }
     }
 
-    RtlReleaseResource(&(device->buffer_list_lock));
+    *ppDS = pDS;
 
     return hr;
 }
 
-/*
- * Remove secondary buffer from buffer list.
- * Gets exclusive access to buffer for writing.
- */
-void DirectSoundDevice_RemoveBuffer(DirectSoundDevice * device, IDirectSoundBufferImpl * pDSB)
+void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device)
 {
-    int i;
+    switch (DSSPEAKER_CONFIG(device->speaker_config)) {
+        case DSSPEAKER_MONO:
+            device->speaker_angles[0] = M_PI/180.0f * 0.0f;
+            device->speaker_num[0] = 0;
+            device->num_speakers = 1;
+            device->lfe_channel = -1;
+        break;
 
-    TRACE("(%p, %p)\n", device, pDSB);
+        case DSSPEAKER_STEREO:
+        case DSSPEAKER_HEADPHONE:
+            device->speaker_angles[0] = M_PI/180.0f * -90.0f;
+            device->speaker_angles[1] = M_PI/180.0f *  90.0f;
+            device->speaker_num[0] = 0; /* Left */
+            device->speaker_num[1] = 1; /* Right */
+            device->num_speakers = 2;
+            device->lfe_channel = -1;
+        break;
 
-    RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE);
+        case DSSPEAKER_QUAD:
+            device->speaker_angles[0] = M_PI/180.0f * -135.0f;
+            device->speaker_angles[1] = M_PI/180.0f *  -45.0f;
+            device->speaker_angles[2] = M_PI/180.0f *   45.0f;
+            device->speaker_angles[3] = M_PI/180.0f *  135.0f;
+            device->speaker_num[0] = 2; /* Rear left */
+            device->speaker_num[1] = 0; /* Front left */
+            device->speaker_num[2] = 1; /* Front right */
+            device->speaker_num[3] = 3; /* Rear right */
+            device->num_speakers = 4;
+            device->lfe_channel = -1;
+        break;
 
-    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);
+        case DSSPEAKER_5POINT1_BACK:
+            device->speaker_angles[0] = M_PI/180.0f * -135.0f;
+            device->speaker_angles[1] = M_PI/180.0f *  -45.0f;
+            device->speaker_angles[2] = M_PI/180.0f *    0.0f;
+            device->speaker_angles[3] = M_PI/180.0f *   45.0f;
+            device->speaker_angles[4] = M_PI/180.0f *  135.0f;
+            device->speaker_angles[5] = 9999.0f;
+            device->speaker_num[0] = 4; /* Rear left */
+            device->speaker_num[1] = 0; /* Front left */
+            device->speaker_num[2] = 2; /* Front centre */
+            device->speaker_num[3] = 1; /* Front right */
+            device->speaker_num[4] = 5; /* Rear right */
+            device->speaker_num[5] = 3; /* LFE */
+            device->num_speakers = 6;
+            device->lfe_channel = 3;
+        break;
 
-    RtlReleaseResource(&(device->buffer_list_lock));
+        case DSSPEAKER_5POINT1_SURROUND:
+            device->speaker_angles[0] = M_PI/180.0f *  -90.0f;
+            device->speaker_angles[1] = M_PI/180.0f *  -30.0f;
+            device->speaker_angles[2] = M_PI/180.0f *    0.0f;
+            device->speaker_angles[3] = M_PI/180.0f *   30.0f;
+            device->speaker_angles[4] = M_PI/180.0f *   90.0f;
+            device->speaker_angles[5] = 9999.0f;
+            device->speaker_num[0] = 4; /* Rear left */
+            device->speaker_num[1] = 0; /* Front left */
+            device->speaker_num[2] = 2; /* Front centre */
+            device->speaker_num[3] = 1; /* Front right */
+            device->speaker_num[4] = 5; /* Rear right */
+            device->speaker_num[5] = 3; /* LFE */
+            device->num_speakers = 6;
+            device->lfe_channel = 3;
+        break;
+
+        default:
+            WARN("unknown speaker_config %u\n", device->speaker_config);
+    }
 }
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index af2034a..3de0068 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -111,24 +111,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