[AUDIO-BRINGUP]
[reactos.git] / dll / directx / dsound / duplex.c
index 8c732c5..1fe6bbc 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-/*
- * TODO:
- *     Implement DirectSoundFullDuplex support.
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
 #define NONAMELESSUNION
 #include "windef.h"
 #include "winbase.h"
+#include "winuser.h"
 #include "mmsystem.h"
 #include "mmddk.h"
-#include "winreg.h"
 #include "winternl.h"
-#include "winnls.h"
 #include "wine/debug.h"
 #include "dsound.h"
 #include "dsdriver.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(
-    LPDIRECTSOUNDFULLDUPLEX iface,
-    LPCGUID pCaptureGuid,
-    LPCGUID pRendererGuid,
-    LPCDSCBUFFERDESC lpDscBufferDesc,
-    LPCDSBUFFERDESC lpDsBufferDesc,
-    HWND hWnd,
-    DWORD dwLevel,
-    LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
-    LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 );
+/*******************************************************************************
+ * IUnknown
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IUnknown_QueryInterface(
+    LPUNKNOWN iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
 
-static const IDirectSoundFullDuplexVtbl dsfdvt;
+static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_AddRef(
+    LPUNKNOWN iface)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
 
-/***************************************************************************
- * DirectSoundFullDuplexCreate [DSOUND.10]
- *
- * Create and initialize a DirectSoundFullDuplex interface.
- *
- * PARAMS
- *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
- *    pcGuidRenderDevice  [I] Address of sound render device GUID.
- *    pcDSCBufferDesc     [I] Address of capture buffer description.
- *    pcDSBufferDesc      [I] Address of  render buffer description.
- *    hWnd                [I] Handle to application window.
- *    dwLevel             [I] Cooperative level.
- *    ppDSFD              [O] Address where full duplex interface returned.
- *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
- *    ppDSBuffer8         [0] Address where render buffer interface returned.
- *    pUnkOuter           [I] Must be NULL.
- *
- * RETURNS
- *    Success: DS_OK
- *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
- *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
+static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_Release(
+    LPUNKNOWN iface)
+{
+    IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pUnknown);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static const IUnknownVtbl DirectSoundFullDuplex_Unknown_Vtbl =
+{
+    IDirectSoundFullDuplex_IUnknown_QueryInterface,
+    IDirectSoundFullDuplex_IUnknown_AddRef,
+    IDirectSoundFullDuplex_IUnknown_Release
+};
+
+static HRESULT IDirectSoundFullDuplex_IUnknown_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPUNKNOWN * ppunk)
+{
+    IDirectSoundFullDuplex_IUnknown * pdsfdunk;
+    TRACE("(%p,%p)\n",pdsfd,ppunk);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppunk == NULL) {
+        ERR("invalid parameter: ppunk == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    pdsfdunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdunk));
+    if (pdsfdunk == NULL) {
+        WARN("out of memory\n");
+        *ppunk = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfdunk->lpVtbl = &DirectSoundFullDuplex_Unknown_Vtbl;
+    pdsfdunk->ref = 0;
+    pdsfdunk->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppunk = (LPUNKNOWN)pdsfdunk;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSound
  */
-HRESULT WINAPI
-DirectSoundFullDuplexCreate(
-    LPCGUID pcGuidCaptureDevice,
-    LPCGUID pcGuidRenderDevice,
-    LPCDSCBUFFERDESC pcDSCBufferDesc,
-    LPCDSBUFFERDESC pcDSBufferDesc,
-    HWND hWnd,
-    DWORD dwLevel,
-    LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
-    LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
-    LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
-    LPUNKNOWN pUnkOuter)
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_QueryInterface(
+    LPDIRECTSOUND iface,
+    REFIID riid,
+    LPVOID * ppobj)
 {
-    IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD;
-    TRACE("(%s,%s,%p,%p,%p,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice),
-       debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc,
-       hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter);
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
 
-    if ( pUnkOuter ) {
-       WARN("pUnkOuter != 0\n");
-        return DSERR_NOAGGREGATION;
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound_AddRef(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound_Release(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pDS);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_CreateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk,FALSE);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_GetCaps(
+    LPDIRECTSOUND iface,
+    LPDSCAPS lpDSCaps)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_DuplicateSoundBuffer(
+    LPDIRECTSOUND iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_SetCooperativeLevel(
+    LPDIRECTSOUND iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_Compact(
+    LPDIRECTSOUND iface)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(This->pdsfd->renderer_device);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_GetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_SetSpeakerConfig(
+    LPDIRECTSOUND iface,
+    DWORD config)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(This->pdsfd->renderer_device,config);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound_Initialize(
+    LPDIRECTSOUND iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSoundFullDuplex_IDirectSound *This = (IDirectSoundFullDuplex_IDirectSound *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&This->pdsfd->renderer_device,lpcGuid);
+}
+
+static const IDirectSoundVtbl DirectSoundFullDuplex_DirectSound_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSound_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSound_AddRef,
+    IDirectSoundFullDuplex_IDirectSound_Release,
+    IDirectSoundFullDuplex_IDirectSound_CreateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound_GetCaps,
+    IDirectSoundFullDuplex_IDirectSound_DuplicateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound_SetCooperativeLevel,
+    IDirectSoundFullDuplex_IDirectSound_Compact,
+    IDirectSoundFullDuplex_IDirectSound_GetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound_SetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound_Initialize
+};
+
+static HRESULT IDirectSoundFullDuplex_IDirectSound_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUND * ppds)
+{
+    IDirectSoundFullDuplex_IDirectSound * pdsfdds;
+    TRACE("(%p,%p)\n",pdsfd,ppds);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppds == NULL) {
+        ERR("invalid parameter: ppds == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
+        WARN("not initialized\n");
+        *ppds = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfdds = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds));
+    if (pdsfdds == NULL) {
+        WARN("out of memory\n");
+        *ppds = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfdds->lpVtbl = &DirectSoundFullDuplex_DirectSound_Vtbl;
+    pdsfdds->ref = 0;
+    pdsfdds->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppds = (LPDIRECTSOUND)pdsfdds;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSound8
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_QueryInterface(
+    LPDIRECTSOUND8 iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_AddRef(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_Release(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSound_Release(This->pdsfd->pDS8);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPCDSBUFFERDESC dsbd,
+    LPLPDIRECTSOUNDBUFFER ppdsb,
+    LPUNKNOWN lpunk)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
+    return DirectSoundDevice_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk,TRUE);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetCaps(
+    LPDIRECTSOUND8 iface,
+    LPDSCAPS lpDSCaps)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCaps);
+    return DirectSoundDevice_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer(
+    LPDIRECTSOUND8 iface,
+    LPDIRECTSOUNDBUFFER psb,
+    LPLPDIRECTSOUNDBUFFER ppdsb)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
+    return DirectSoundDevice_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel(
+    LPDIRECTSOUND8 iface,
+    HWND hwnd,
+    DWORD level)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
+    return DirectSoundDevice_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Compact(
+    LPDIRECTSOUND8 iface)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p)\n", This);
+    return DirectSoundDevice_Compact(This->pdsfd->renderer_device);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    LPDWORD lpdwSpeakerConfig)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
+    return DirectSoundDevice_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig(
+    LPDIRECTSOUND8 iface,
+    DWORD config)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p,0x%08x)\n",This,config);
+    return DirectSoundDevice_SetSpeakerConfig(This->pdsfd->renderer_device,config);
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Initialize(
+    LPDIRECTSOUND8 iface,
+    LPCGUID lpcGuid)
+{
+    IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
+    return DirectSoundDevice_Initialize(&This->pdsfd->renderer_device,lpcGuid);
+}
+
+static const IDirectSound8Vtbl DirectSoundFullDuplex_DirectSound8_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSound8_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSound8_AddRef,
+    IDirectSoundFullDuplex_IDirectSound8_Release,
+    IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound8_GetCaps,
+    IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer,
+    IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel,
+    IDirectSoundFullDuplex_IDirectSound8_Compact,
+    IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig,
+    IDirectSoundFullDuplex_IDirectSound8_Initialize
+};
+
+static HRESULT IDirectSoundFullDuplex_IDirectSound8_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUND8 * ppds8)
+{
+    IDirectSoundFullDuplex_IDirectSound8 * pdsfdds8;
+    TRACE("(%p,%p)\n",pdsfd,ppds8);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (ppds8 == NULL) {
+        ERR("invalid parameter: ppds8 == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
+        WARN("not initialized\n");
+        *ppds8 = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfdds8 = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds8));
+    if (pdsfdds8 == NULL) {
+        WARN("out of memory\n");
+        *ppds8 = NULL;
+        return DSERR_OUTOFMEMORY;
     }
 
-    *ippDSFD = HeapAlloc(GetProcessHeap(),
-       HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
+    pdsfdds8->lpVtbl = &DirectSoundFullDuplex_DirectSound8_Vtbl;
+    pdsfdds8->ref = 0;
+    pdsfdds8->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppds8 = (LPDIRECTSOUND8)pdsfdds8;
+
+    return DS_OK;
+}
+
+/*******************************************************************************
+ * IDirectSoundFullDuplex_IDirectSoundCapture
+ */
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface(
+    LPDIRECTSOUNDCAPTURE iface,
+    REFIID riid,
+    LPVOID * ppobj)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
+    return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(
+    LPDIRECTSOUNDCAPTURE iface)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
+}
+
+static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Release(
+    LPDIRECTSOUNDCAPTURE iface)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    ULONG ref = InterlockedDecrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref + 1);
+    if (!ref) {
+        IDirectSoundCapture_Release(This->pdsfd->pDSC);
+        HeapFree(GetProcessHeap(), 0, This);
+        TRACE("(%p) released\n", This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCDSCBUFFERDESC lpcDSCBufferDesc,
+    LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
+    LPUNKNOWN pUnk)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
+    return IDirectSoundCaptureImpl_CreateCaptureBuffer(This->pdsfd->pDSC,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
+}
 
-    if (*ippDSFD == NULL) {
-       WARN("out of memory\n");
-       return DSERR_OUTOFMEMORY;
-    } else {
-       HRESULT hres;
-        IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD;
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPDSCCAPS lpDSCCaps)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p,%p)\n",This,lpDSCCaps);
+    return IDirectSoundCaptureImpl_GetCaps(This->pdsfd->pDSC, lpDSCCaps);
+}
 
-        This->ref = 1;
-        This->lpVtbl = &dsfdvt;
+static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Initialize(
+    LPDIRECTSOUNDCAPTURE iface,
+    LPCGUID lpcGUID)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
+    TRACE("(%p, %s)\n", This, debugstr_guid(lpcGUID));
+    return IDirectSoundCaptureImpl_Initialize(This->pdsfd->pDSC,lpcGUID);
+}
 
-        InitializeCriticalSection( &(This->lock) );
-        This->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSDUPLEX_lock";
+static const IDirectSoundCaptureVtbl DirectSoundFullDuplex_DirectSoundCapture_Vtbl =
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface,
+    IDirectSoundFullDuplex_IDirectSoundCapture_AddRef,
+    IDirectSoundFullDuplex_IDirectSoundCapture_Release,
+    IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer,
+    IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps,
+    IDirectSoundFullDuplex_IDirectSoundCapture_Initialize
+};
 
-        hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This,
-                                                      pcGuidCaptureDevice, pcGuidRenderDevice,
-                                                      pcDSCBufferDesc, pcDSBufferDesc,
-                                                      hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8);
-       if (hres != DS_OK)
-           WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
-       return hres;
+static HRESULT IDirectSoundFullDuplex_IDirectSoundCapture_Create(
+    LPDIRECTSOUNDFULLDUPLEX pdsfd,
+    LPDIRECTSOUNDCAPTURE8 * ppdsc8)
+{
+    IDirectSoundFullDuplex_IDirectSoundCapture * pdsfddsc;
+    TRACE("(%p,%p)\n",pdsfd,ppdsc8);
+
+    if (pdsfd == NULL) {
+        ERR("invalid parameter: pdsfd == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
+
+    if (ppdsc8 == NULL) {
+        ERR("invalid parameter: ppdsc8 == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
+
+    if (((IDirectSoundFullDuplexImpl*)pdsfd)->capture_device == NULL) {
+        WARN("not initialized\n");
+        *ppdsc8 = NULL;
+        return DSERR_UNINITIALIZED;
+    }
+
+    pdsfddsc = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfddsc));
+    if (pdsfddsc == NULL) {
+        WARN("out of memory\n");
+        *ppdsc8 = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    pdsfddsc->lpVtbl = &DirectSoundFullDuplex_DirectSoundCapture_Vtbl;
+    pdsfddsc->ref = 0;
+    pdsfddsc->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
+
+    *ppdsc8 = (LPDIRECTSOUNDCAPTURE)pdsfddsc;
+
+    return DS_OK;
+}
+
+/***************************************************************************
+ * IDirectSoundFullDuplexImpl
+ */
+static ULONG WINAPI
+IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
+{
+    IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
+    ULONG ref = InterlockedIncrement(&(This->ref));
+    TRACE("(%p) ref was %d\n", This, ref - 1);
+    return ref;
 }
 
 static HRESULT WINAPI
@@ -141,16 +584,62 @@ IDirectSoundFullDuplexImpl_QueryInterface(
     }
 
     *ppobj = NULL;
-    return E_NOINTERFACE;
-}
 
-static ULONG WINAPI
-IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
-{
-    IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
-    ULONG ref = InterlockedIncrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
-    return ref;
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        if (!This->pUnknown) {
+            IDirectSoundFullDuplex_IUnknown_Create(iface, &This->pUnknown);
+            if (!This->pUnknown) {
+                WARN("IDirectSoundFullDuplex_IUnknown_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IUnknown_AddRef(This->pUnknown);
+        *ppobj = This->pUnknown;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
+        IDirectSoundFullDuplexImpl_AddRef(iface);
+        *ppobj = This;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSound)) {
+        if (!This->pDS) {
+            IDirectSoundFullDuplex_IDirectSound_Create(iface, &This->pDS);
+            if (!This->pDS) {
+                WARN("IDirectSoundFullDuplex_IDirectSound_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSound_AddRef(This->pDS);
+        *ppobj = This->pDS;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSound8)) {
+        if (!This->pDS8) {
+            IDirectSoundFullDuplex_IDirectSound8_Create(iface, &This->pDS8);
+            if (!This->pDS8) {
+                WARN("IDirectSoundFullDuplex_IDirectSound8_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSound8_AddRef(This->pDS8);
+        *ppobj = This->pDS8;
+        return S_OK;
+    } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
+        if (!This->pDSC) {
+            IDirectSoundFullDuplex_IDirectSoundCapture_Create(iface, &This->pDSC);
+            if (!This->pDSC) {
+                WARN("IDirectSoundFullDuplex_IDirectSoundCapture_Create() failed\n");
+                *ppobj = NULL;
+                return E_NOINTERFACE;
+            }
+        }
+        IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(This->pDSC);
+        *ppobj = This->pDSC;
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
 }
 
 static ULONG WINAPI
@@ -158,11 +647,13 @@ IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
 {
     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
     ULONG ref = InterlockedDecrement(&(This->ref));
-    TRACE("(%p) ref was %ld\n", This, ref - 1);
+    TRACE("(%p) ref was %d\n", This, ref - 1);
 
     if (!ref) {
-        This->lock.DebugInfo->Spare[0] = 0;
-        DeleteCriticalSection( &(This->lock) );
+        if (This->capture_device)
+            DirectSoundCaptureDevice_Release(This->capture_device);
+        if (This->renderer_device)
+            DirectSoundDevice_Release(This->renderer_device);
         HeapFree( GetProcessHeap(), 0, This );
        TRACE("(%p) released\n", This);
     }
@@ -181,15 +672,79 @@ IDirectSoundFullDuplexImpl_Initialize(
     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
 {
+    HRESULT hr;
     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
-    IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8;
-    IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8;
+    IDirectSoundBufferImpl * dsb;
+
+    TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This,
+        debugstr_guid(pCaptureGuid), debugstr_guid(pRendererGuid),
+        lpDscBufferDesc, lpDsBufferDesc, hWnd, dwLevel,
+        lplpDirectSoundCaptureBuffer8, lplpDirectSoundBuffer8);
+
+    if (This->renderer_device != NULL || This->capture_device != NULL) {
+        WARN("already initialized\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return DSERR_ALREADYINITIALIZED;
+    }
 
-    FIXME( "(%p,%s,%s,%p,%p,%p,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid),
-       debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, hWnd, dwLevel,
-       ippdscb, ippdsc);
+    hr = DirectSoundDevice_Initialize(&This->renderer_device, pRendererGuid);
+    if (hr != DS_OK) {
+        WARN("DirectSoundDevice_Initialize() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
+
+    if (dwLevel==DSSCL_PRIORITY || dwLevel==DSSCL_EXCLUSIVE) {
+        WARN("level=%s not fully supported\n",
+             dwLevel==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE");
+    }
+    This->renderer_device->priolevel = dwLevel;
+
+    hr = DSOUND_PrimarySetFormat(This->renderer_device, lpDsBufferDesc->lpwfxFormat, dwLevel == DSSCL_EXCLUSIVE);
+    if (hr != DS_OK) {
+        WARN("DSOUND_PrimarySetFormat() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
+    hr = IDirectSoundBufferImpl_Create(This->renderer_device, &dsb, lpDsBufferDesc);
+    if (hr != DS_OK) {
+        WARN("IDirectSoundBufferImpl_Create() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
 
-    return E_FAIL;
+    hr = SecondaryBufferImpl_Create(dsb, (SecondaryBufferImpl **)lplpDirectSoundBuffer8);
+    if (hr != DS_OK) {
+        WARN("SecondaryBufferImpl_Create() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
+    IDirectSoundBuffer8_AddRef(*lplpDirectSoundBuffer8);
+
+    hr = DirectSoundCaptureDevice_Initialize(&This->capture_device, pCaptureGuid);
+    if (hr != DS_OK) {
+        WARN("DirectSoundCaptureDevice_Initialize() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
+
+    hr = IDirectSoundCaptureBufferImpl_Create(This->capture_device,
+         (IDirectSoundCaptureBufferImpl **)lplpDirectSoundCaptureBuffer8,
+         lpDscBufferDesc);
+    if (hr != DS_OK) {
+        WARN("IDirectSoundCaptureBufferImpl_Create() failed\n");
+        *lplpDirectSoundCaptureBuffer8 = NULL;
+        *lplpDirectSoundBuffer8 = NULL;
+        return hr;
+    }
+
+    return hr;
 }
 
 static const IDirectSoundFullDuplexVtbl dsfdvt =
@@ -203,81 +758,153 @@ static const IDirectSoundFullDuplexVtbl dsfdvt =
     IDirectSoundFullDuplexImpl_Initialize
 };
 
-/*******************************************************************************
- * DirectSoundFullDuplex ClassFactory
- */
-
-static HRESULT WINAPI
-DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj)
+HRESULT DSOUND_FullDuplexCreate(
+    REFIID riid,
+    LPDIRECTSOUNDFULLDUPLEX* ppDSFD)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    IDirectSoundFullDuplexImpl *This = NULL;
+    TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSFD);
 
-    FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
-    return E_NOINTERFACE;
-}
+    if (ppDSFD == NULL) {
+        WARN("invalid parameter: ppDSFD == NULL\n");
+        return DSERR_INVALIDPARAM;
+    }
 
-static ULONG WINAPI
-DSFDCF_AddRef(LPCLASSFACTORY iface)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-    return InterlockedIncrement(&(This->ref));
-}
+    if (!IsEqualIID(riid, &IID_IUnknown) &&
+        !IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
+        *ppDSFD = 0;
+        return E_NOINTERFACE;
+    }
 
-static ULONG WINAPI
-DSFDCF_Release(LPCLASSFACTORY iface)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    /* static class, won't be  freed */
-    TRACE("(%p) ref was %ld\n", This, This->ref);
-    return InterlockedDecrement(&(This->ref));
+    /* Get dsound configuration */
+    setup_dsound_options();
+
+    This = HeapAlloc(GetProcessHeap(),
+        HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
+
+    if (This == NULL) {
+        WARN("out of memory\n");
+        *ppDSFD = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
+
+    This->lpVtbl = &dsfdvt;
+    This->ref = 1;
+    This->capture_device = NULL;
+    This->renderer_device = NULL;
+
+    *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
+
+    return DS_OK;
 }
 
-static HRESULT WINAPI
-DSFDCF_CreateInstance(
-    LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj )
+/***************************************************************************
+ * DirectSoundFullDuplexCreate [DSOUND.10]
+ *
+ * Create and initialize a DirectSoundFullDuplex interface.
+ *
+ * PARAMS
+ *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
+ *    pcGuidRenderDevice  [I] Address of sound render device GUID.
+ *    pcDSCBufferDesc     [I] Address of capture buffer description.
+ *    pcDSBufferDesc      [I] Address of  render buffer description.
+ *    hWnd                [I] Handle to application window.
+ *    dwLevel             [I] Cooperative level.
+ *    ppDSFD              [O] Address where full duplex interface returned.
+ *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
+ *    ppDSBuffer8         [0] Address where render buffer interface returned.
+ *    pUnkOuter           [I] Must be NULL.
+ *
+ * RETURNS
+ *    Success: DS_OK
+ *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
+ *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
+ */
+HRESULT WINAPI
+DirectSoundFullDuplexCreate(
+    LPCGUID pcGuidCaptureDevice,
+    LPCGUID pcGuidRenderDevice,
+    LPCDSCBUFFERDESC pcDSCBufferDesc,
+    LPCDSBUFFERDESC pcDSBufferDesc,
+    HWND hWnd,
+    DWORD dwLevel,
+    LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
+    LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
+    LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
+    LPUNKNOWN pUnkOuter)
 {
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+    HRESULT hres;
+    IDirectSoundFullDuplexImpl *This = NULL;
+    TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n",
+        debugstr_guid(pcGuidCaptureDevice), debugstr_guid(pcGuidRenderDevice),
+        pcDSCBufferDesc, pcDSBufferDesc, hWnd, dwLevel, ppDSFD, ppDSCBuffer8,
+        ppDSBuffer8, pUnkOuter);
+
+    if (pUnkOuter) {
+        WARN("pUnkOuter != 0\n");
+        *ppDSFD = NULL;
+        return DSERR_NOAGGREGATION;
+    }
 
-    TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj);
+    if (pcDSCBufferDesc == NULL) {
+        WARN("invalid parameter: pcDSCBufferDesc == NULL\n");
+        *ppDSFD = NULL;
+        return DSERR_INVALIDPARAM;
+    }
 
-    if (pOuter) {
-        WARN("aggregation not supported\n");
-        return CLASS_E_NOAGGREGATION;
+    if (pcDSBufferDesc == NULL) {
+        WARN("invalid parameter: pcDSBufferDesc == NULL\n");
+        *ppDSFD = NULL;
+        return DSERR_INVALIDPARAM;
     }
 
-    if (ppobj == NULL) {
-       WARN("invalid parameter\n");
-       return E_INVALIDARG;
+    if (ppDSFD == NULL) {
+        WARN("invalid parameter: ppDSFD == NULL\n");
+        return DSERR_INVALIDPARAM;
     }
 
-    *ppobj = NULL;
+    if (ppDSCBuffer8 == NULL) {
+        WARN("invalid parameter: ppDSCBuffer8 == NULL\n");
+        *ppDSFD = NULL;
+        return DSERR_INVALIDPARAM;
+    }
 
-    if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) {
-       /* FIXME: how do we do this one ? */
-       FIXME("not implemented\n");
-       return E_NOINTERFACE;
+    if (ppDSBuffer8 == NULL) {
+        WARN("invalid parameter: ppDSBuffer8 == NULL\n");
+        *ppDSFD = NULL;
+        return DSERR_INVALIDPARAM;
     }
 
-    WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj);
-    return E_NOINTERFACE;
-}
+    /* Get dsound configuration */
+    setup_dsound_options();
 
-static HRESULT WINAPI
-DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock)
-{
-    IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
-    FIXME("(%p)->(%d),stub!\n",This,dolock);
-    return S_OK;
-}
+    This = HeapAlloc(GetProcessHeap(),
+        HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
 
-static const IClassFactoryVtbl DSFDCF_Vtbl =
-{
-    DSFDCF_QueryInterface,
-    DSFDCF_AddRef,
-    DSFDCF_Release,
-    DSFDCF_CreateInstance,
-    DSFDCF_LockServer
-};
+    if (This == NULL) {
+        WARN("out of memory\n");
+        *ppDSFD = NULL;
+        return DSERR_OUTOFMEMORY;
+    }
 
-IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 };
+    This->lpVtbl = &dsfdvt;
+    This->ref = 1;
+    This->capture_device = NULL;
+    This->renderer_device = NULL;
+
+    hres = IDirectSoundFullDuplexImpl_Initialize((LPDIRECTSOUNDFULLDUPLEX)This,
+                                                 pcGuidCaptureDevice,
+                                                 pcGuidRenderDevice,
+                                                 pcDSCBufferDesc,
+                                                 pcDSBufferDesc,
+                                                 hWnd, dwLevel, ppDSCBuffer8,
+                                                 ppDSBuffer8);
+    if (hres != DS_OK) {
+        HeapFree(GetProcessHeap(), 0, This);
+        WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
+        *ppDSFD = NULL;
+    } else
+        *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
+
+    return hres;
+}