dsound: Unofficially support 5.1 sound.
[wine] / dlls / dsound / duplex.c
1 /*              DirectSoundFullDuplex
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998 Rob Riggs
5  * Copyright 2000-2001 TransGaming Technologies, Inc.
6  * Copyright 2005 Robert Reif
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <stdarg.h>
24
25 #define NONAMELESSSTRUCT
26 #define NONAMELESSUNION
27 #define CINTERFACE
28 #define COBJMACROS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "mmsystem.h"
33 #include "mmddk.h"
34 #include "winternl.h"
35 #include "wine/debug.h"
36 #include "dsound.h"
37 #include "dsdriver.h"
38 #include "dsound_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
41
42 /*****************************************************************************
43  * IDirectSoundFullDuplex implementation structure
44  */
45 typedef struct IDirectSoundFullDuplexImpl
46 {
47     /* IUnknown fields */
48     const IDirectSoundFullDuplexVtbl *lpVtbl;
49     LONG                              ref;
50
51     /* IDirectSoundFullDuplexImpl fields */
52     IDirectSound8                    *renderer_device;
53     IDirectSoundCapture              *capture_device;
54
55     LPUNKNOWN                         pUnknown;
56     LPDIRECTSOUND8                    pDS8;
57     LPDIRECTSOUNDCAPTURE              pDSC;
58 } IDirectSoundFullDuplexImpl;
59
60 typedef struct IDirectSoundFullDuplex_IUnknown {
61     const IUnknownVtbl         *lpVtbl;
62     LONG                        ref;
63     IDirectSoundFullDuplexImpl *pdsfd;
64 } IDirectSoundFullDuplex_IUnknown;
65
66 typedef struct IDirectSoundFullDuplex_IDirectSound8 {
67     const IDirectSound8Vtbl    *lpVtbl;
68     LONG                        ref;
69     IDirectSoundFullDuplexImpl *pdsfd;
70 } IDirectSoundFullDuplex_IDirectSound8;
71
72 typedef struct IDirectSoundFullDuplex_IDirectSoundCapture {
73     const IDirectSoundCaptureVtbl *lpVtbl;
74     LONG                           ref;
75     IDirectSoundFullDuplexImpl    *pdsfd;
76 } IDirectSoundFullDuplex_IDirectSoundCapture;
77
78 /*******************************************************************************
79  * IUnknown
80  */
81 static HRESULT WINAPI IDirectSoundFullDuplex_IUnknown_QueryInterface(
82     LPUNKNOWN iface,
83     REFIID riid,
84     LPVOID * ppobj)
85 {
86     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
87     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
88     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
89 }
90
91 static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_AddRef(
92     LPUNKNOWN iface)
93 {
94     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
95     ULONG ref = InterlockedIncrement(&(This->ref));
96     TRACE("(%p) ref was %d\n", This, ref - 1);
97     return ref;
98 }
99
100 static ULONG WINAPI IDirectSoundFullDuplex_IUnknown_Release(
101     LPUNKNOWN iface)
102 {
103     IDirectSoundFullDuplex_IUnknown *This = (IDirectSoundFullDuplex_IUnknown *)iface;
104     ULONG ref = InterlockedDecrement(&(This->ref));
105     TRACE("(%p) ref was %d\n", This, ref + 1);
106     if (!ref) {
107         This->pdsfd->pUnknown = NULL;
108         HeapFree(GetProcessHeap(), 0, This);
109         TRACE("(%p) released\n", This);
110     }
111     return ref;
112 }
113
114 static const IUnknownVtbl DirectSoundFullDuplex_Unknown_Vtbl =
115 {
116     IDirectSoundFullDuplex_IUnknown_QueryInterface,
117     IDirectSoundFullDuplex_IUnknown_AddRef,
118     IDirectSoundFullDuplex_IUnknown_Release
119 };
120
121 static HRESULT IDirectSoundFullDuplex_IUnknown_Create(
122     LPDIRECTSOUNDFULLDUPLEX pdsfd,
123     LPUNKNOWN * ppunk)
124 {
125     IDirectSoundFullDuplex_IUnknown * pdsfdunk;
126     TRACE("(%p,%p)\n",pdsfd,ppunk);
127
128     if (pdsfd == NULL) {
129         ERR("invalid parameter: pdsfd == NULL\n");
130         return DSERR_INVALIDPARAM;
131     }
132
133     if (ppunk == NULL) {
134         ERR("invalid parameter: ppunk == NULL\n");
135         return DSERR_INVALIDPARAM;
136     }
137
138     pdsfdunk = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdunk));
139     if (pdsfdunk == NULL) {
140         WARN("out of memory\n");
141         *ppunk = NULL;
142         return DSERR_OUTOFMEMORY;
143     }
144
145     pdsfdunk->lpVtbl = &DirectSoundFullDuplex_Unknown_Vtbl;
146     pdsfdunk->ref = 0;
147     pdsfdunk->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
148
149     *ppunk = (LPUNKNOWN)pdsfdunk;
150
151     return DS_OK;
152 }
153
154 /*******************************************************************************
155  * IDirectSoundFullDuplex_IDirectSound8
156  */
157 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_QueryInterface(
158     LPDIRECTSOUND8 iface,
159     REFIID riid,
160     LPVOID * ppobj)
161 {
162     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
163     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
164     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
165 }
166
167 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_AddRef(
168     LPDIRECTSOUND8 iface)
169 {
170     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
171     ULONG ref = InterlockedIncrement(&(This->ref));
172     TRACE("(%p) ref was %d\n", This, ref - 1);
173     return ref;
174 }
175
176 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSound8_Release(
177     LPDIRECTSOUND8 iface)
178 {
179     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
180     ULONG ref = InterlockedDecrement(&(This->ref));
181     TRACE("(%p) ref was %d\n", This, ref + 1);
182     if (!ref) {
183         This->pdsfd->pDS8 = NULL;
184         HeapFree(GetProcessHeap(), 0, This);
185         TRACE("(%p) released\n", This);
186     }
187     return ref;
188 }
189
190 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer(
191     LPDIRECTSOUND8 iface,
192     LPCDSBUFFERDESC dsbd,
193     LPLPDIRECTSOUNDBUFFER ppdsb,
194     LPUNKNOWN lpunk)
195 {
196     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
197     TRACE("(%p,%p,%p,%p)\n",This,dsbd,ppdsb,lpunk);
198     return IDirectSound8_CreateSoundBuffer(This->pdsfd->renderer_device,dsbd,ppdsb,lpunk);
199 }
200
201 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetCaps(
202     LPDIRECTSOUND8 iface,
203     LPDSCAPS lpDSCaps)
204 {
205     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
206     TRACE("(%p,%p)\n",This,lpDSCaps);
207     return IDirectSound8_GetCaps(This->pdsfd->renderer_device, lpDSCaps);
208 }
209
210 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer(
211     LPDIRECTSOUND8 iface,
212     LPDIRECTSOUNDBUFFER psb,
213     LPLPDIRECTSOUNDBUFFER ppdsb)
214 {
215     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
216     TRACE("(%p,%p,%p)\n",This,psb,ppdsb);
217     return IDirectSound8_DuplicateSoundBuffer(This->pdsfd->renderer_device,psb,ppdsb);
218 }
219
220 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel(
221     LPDIRECTSOUND8 iface,
222     HWND hwnd,
223     DWORD level)
224 {
225     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
226     TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level));
227     return IDirectSound8_SetCooperativeLevel(This->pdsfd->renderer_device,hwnd,level);
228 }
229
230 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Compact(
231     LPDIRECTSOUND8 iface)
232 {
233     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
234     TRACE("(%p)\n", This);
235     return IDirectSound8_Compact(This->pdsfd->renderer_device);
236 }
237
238 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig(
239     LPDIRECTSOUND8 iface,
240     LPDWORD lpdwSpeakerConfig)
241 {
242     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
243     TRACE("(%p, %p)\n", This, lpdwSpeakerConfig);
244     return IDirectSound8_GetSpeakerConfig(This->pdsfd->renderer_device,lpdwSpeakerConfig);
245 }
246
247 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig(
248     LPDIRECTSOUND8 iface,
249     DWORD config)
250 {
251     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
252     TRACE("(%p,0x%08x)\n",This,config);
253     return IDirectSound8_SetSpeakerConfig(This->pdsfd->renderer_device,config);
254 }
255
256 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_Initialize(
257     LPDIRECTSOUND8 iface,
258     LPCGUID lpcGuid)
259 {
260     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
261     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGuid));
262     return IDirectSound8_Initialize(This->pdsfd->renderer_device,lpcGuid);
263 }
264
265 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSound8_VerifyCertification(
266     LPDIRECTSOUND8 iface,
267     DWORD *cert)
268 {
269     IDirectSoundFullDuplex_IDirectSound8 *This = (IDirectSoundFullDuplex_IDirectSound8 *)iface;
270     TRACE("(%p, %p)\n", This, cert);
271     return IDirectSound8_VerifyCertification(This->pdsfd->renderer_device,cert);
272 }
273
274 static const IDirectSound8Vtbl DirectSoundFullDuplex_DirectSound8_Vtbl =
275 {
276     IDirectSoundFullDuplex_IDirectSound8_QueryInterface,
277     IDirectSoundFullDuplex_IDirectSound8_AddRef,
278     IDirectSoundFullDuplex_IDirectSound8_Release,
279     IDirectSoundFullDuplex_IDirectSound8_CreateSoundBuffer,
280     IDirectSoundFullDuplex_IDirectSound8_GetCaps,
281     IDirectSoundFullDuplex_IDirectSound8_DuplicateSoundBuffer,
282     IDirectSoundFullDuplex_IDirectSound8_SetCooperativeLevel,
283     IDirectSoundFullDuplex_IDirectSound8_Compact,
284     IDirectSoundFullDuplex_IDirectSound8_GetSpeakerConfig,
285     IDirectSoundFullDuplex_IDirectSound8_SetSpeakerConfig,
286     IDirectSoundFullDuplex_IDirectSound8_Initialize,
287     IDirectSoundFullDuplex_IDirectSound8_VerifyCertification
288 };
289
290 static HRESULT IDirectSoundFullDuplex_IDirectSound8_Create(
291     LPDIRECTSOUNDFULLDUPLEX pdsfd,
292     LPDIRECTSOUND8 * ppds8)
293 {
294     IDirectSoundFullDuplex_IDirectSound8 * pdsfdds8;
295     TRACE("(%p,%p)\n",pdsfd,ppds8);
296
297     if (pdsfd == NULL) {
298         ERR("invalid parameter: pdsfd == NULL\n");
299         return DSERR_INVALIDPARAM;
300     }
301
302     if (ppds8 == NULL) {
303         ERR("invalid parameter: ppds8 == NULL\n");
304         return DSERR_INVALIDPARAM;
305     }
306
307     if (((IDirectSoundFullDuplexImpl*)pdsfd)->renderer_device == NULL) {
308         WARN("not initialized\n");
309         *ppds8 = NULL;
310         return DSERR_UNINITIALIZED;
311     }
312
313     pdsfdds8 = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfdds8));
314     if (pdsfdds8 == NULL) {
315         WARN("out of memory\n");
316         *ppds8 = NULL;
317         return DSERR_OUTOFMEMORY;
318     }
319
320     pdsfdds8->lpVtbl = &DirectSoundFullDuplex_DirectSound8_Vtbl;
321     pdsfdds8->ref = 0;
322     pdsfdds8->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
323
324     *ppds8 = (LPDIRECTSOUND8)pdsfdds8;
325
326     return DS_OK;
327 }
328
329 /*******************************************************************************
330  * IDirectSoundFullDuplex_IDirectSoundCapture
331  */
332 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface(
333     LPDIRECTSOUNDCAPTURE iface,
334     REFIID riid,
335     LPVOID * ppobj)
336 {
337     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
338     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
339     return IDirectSoundFullDuplex_QueryInterface((LPDIRECTSOUNDFULLDUPLEX)This->pdsfd, riid, ppobj);
340 }
341
342 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(
343     LPDIRECTSOUNDCAPTURE iface)
344 {
345     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
346     ULONG ref = InterlockedIncrement(&(This->ref));
347     TRACE("(%p) ref was %d\n", This, ref - 1);
348     return ref;
349 }
350
351 static ULONG WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Release(
352     LPDIRECTSOUNDCAPTURE iface)
353 {
354     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
355     ULONG ref = InterlockedDecrement(&(This->ref));
356     TRACE("(%p) ref was %d\n", This, ref + 1);
357     if (!ref) {
358         This->pdsfd->pDSC = NULL;
359         HeapFree(GetProcessHeap(), 0, This);
360         TRACE("(%p) released\n", This);
361     }
362     return ref;
363 }
364
365 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer(
366     LPDIRECTSOUNDCAPTURE iface,
367     LPCDSCBUFFERDESC lpcDSCBufferDesc,
368     LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer,
369     LPUNKNOWN pUnk)
370 {
371     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
372     TRACE("(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
373     return IDirectSoundCapture_CreateCaptureBuffer(This->pdsfd->capture_device,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk);
374 }
375
376 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps(
377     LPDIRECTSOUNDCAPTURE iface,
378     LPDSCCAPS lpDSCCaps)
379 {
380     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
381     TRACE("(%p,%p)\n",This,lpDSCCaps);
382     return IDirectSoundCapture_GetCaps(This->pdsfd->capture_device, lpDSCCaps);
383 }
384
385 static HRESULT WINAPI IDirectSoundFullDuplex_IDirectSoundCapture_Initialize(
386     LPDIRECTSOUNDCAPTURE iface,
387     LPCGUID lpcGUID)
388 {
389     IDirectSoundFullDuplex_IDirectSoundCapture *This = (IDirectSoundFullDuplex_IDirectSoundCapture *)iface;
390     TRACE("(%p, %s)\n", This, debugstr_guid(lpcGUID));
391     return IDirectSoundCapture_Initialize(This->pdsfd->capture_device,lpcGUID);
392 }
393
394 static const IDirectSoundCaptureVtbl DirectSoundFullDuplex_DirectSoundCapture_Vtbl =
395 {
396     IDirectSoundFullDuplex_IDirectSoundCapture_QueryInterface,
397     IDirectSoundFullDuplex_IDirectSoundCapture_AddRef,
398     IDirectSoundFullDuplex_IDirectSoundCapture_Release,
399     IDirectSoundFullDuplex_IDirectSoundCapture_CreateCaptureBuffer,
400     IDirectSoundFullDuplex_IDirectSoundCapture_GetCaps,
401     IDirectSoundFullDuplex_IDirectSoundCapture_Initialize
402 };
403
404 static HRESULT IDirectSoundFullDuplex_IDirectSoundCapture_Create(
405     LPDIRECTSOUNDFULLDUPLEX pdsfd,
406     LPDIRECTSOUNDCAPTURE8 * ppdsc8)
407 {
408     IDirectSoundFullDuplex_IDirectSoundCapture * pdsfddsc;
409     TRACE("(%p,%p)\n",pdsfd,ppdsc8);
410
411     if (pdsfd == NULL) {
412         ERR("invalid parameter: pdsfd == NULL\n");
413         return DSERR_INVALIDPARAM;
414     }
415
416     if (ppdsc8 == NULL) {
417         ERR("invalid parameter: ppdsc8 == NULL\n");
418         return DSERR_INVALIDPARAM;
419     }
420
421     if (((IDirectSoundFullDuplexImpl*)pdsfd)->capture_device == NULL) {
422         WARN("not initialized\n");
423         *ppdsc8 = NULL;
424         return DSERR_UNINITIALIZED;
425     }
426
427     pdsfddsc = HeapAlloc(GetProcessHeap(),0,sizeof(*pdsfddsc));
428     if (pdsfddsc == NULL) {
429         WARN("out of memory\n");
430         *ppdsc8 = NULL;
431         return DSERR_OUTOFMEMORY;
432     }
433
434     pdsfddsc->lpVtbl = &DirectSoundFullDuplex_DirectSoundCapture_Vtbl;
435     pdsfddsc->ref = 0;
436     pdsfddsc->pdsfd = (IDirectSoundFullDuplexImpl *)pdsfd;
437
438     *ppdsc8 = (LPDIRECTSOUNDCAPTURE)pdsfddsc;
439
440     return DS_OK;
441 }
442
443 /***************************************************************************
444  * IDirectSoundFullDuplexImpl
445  */
446 static ULONG WINAPI
447 IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface )
448 {
449     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
450     ULONG ref = InterlockedIncrement(&(This->ref));
451     TRACE("(%p) ref was %d\n", This, ref - 1);
452     return ref;
453 }
454
455 static HRESULT WINAPI
456 IDirectSoundFullDuplexImpl_QueryInterface(
457     LPDIRECTSOUNDFULLDUPLEX iface,
458     REFIID riid,
459     LPVOID* ppobj )
460 {
461     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
462     TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj );
463
464     if (ppobj == NULL) {
465         WARN("invalid parameter\n");
466         return E_INVALIDARG;
467     }
468
469     *ppobj = NULL;
470
471     if (IsEqualIID(riid, &IID_IUnknown)) {
472         if (!This->pUnknown) {
473             IDirectSoundFullDuplex_IUnknown_Create(iface, &This->pUnknown);
474             if (!This->pUnknown) {
475                 WARN("IDirectSoundFullDuplex_IUnknown_Create() failed\n");
476                 *ppobj = NULL;
477                 return E_NOINTERFACE;
478             }
479         }
480         IDirectSoundFullDuplex_IUnknown_AddRef(This->pUnknown);
481         *ppobj = This->pUnknown;
482         return S_OK;
483     } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
484         IDirectSoundFullDuplexImpl_AddRef(iface);
485         *ppobj = This;
486         return S_OK;
487     } else if (IsEqualIID(riid, &IID_IDirectSound)
488                || IsEqualIID(riid, &IID_IDirectSound8)) {
489         if (!This->pDS8) {
490             IDirectSoundFullDuplex_IDirectSound8_Create(iface, &This->pDS8);
491             if (!This->pDS8) {
492                 WARN("IDirectSoundFullDuplex_IDirectSound8_Create() failed\n");
493                 *ppobj = NULL;
494                 return E_NOINTERFACE;
495             }
496         }
497         IDirectSoundFullDuplex_IDirectSound8_AddRef(This->pDS8);
498         *ppobj = This->pDS8;
499         return S_OK;
500     } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) {
501         if (!This->pDSC) {
502             IDirectSoundFullDuplex_IDirectSoundCapture_Create(iface, &This->pDSC);
503             if (!This->pDSC) {
504                 WARN("IDirectSoundFullDuplex_IDirectSoundCapture_Create() failed\n");
505                 *ppobj = NULL;
506                 return E_NOINTERFACE;
507             }
508         }
509         IDirectSoundFullDuplex_IDirectSoundCapture_AddRef(This->pDSC);
510         *ppobj = This->pDSC;
511         return S_OK;
512     }
513
514     return E_NOINTERFACE;
515 }
516
517 static ULONG WINAPI
518 IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface )
519 {
520     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
521     ULONG ref = InterlockedDecrement(&(This->ref));
522     TRACE("(%p) ref was %d\n", This, ref - 1);
523
524     if (!ref) {
525         if (This->capture_device)
526             IDirectSoundCapture_Release(This->capture_device);
527         if (This->renderer_device)
528             IDirectSound_Release(This->renderer_device);
529         HeapFree( GetProcessHeap(), 0, This );
530         TRACE("(%p) released\n", This);
531     }
532     return ref;
533 }
534
535 static HRESULT WINAPI
536 IDirectSoundFullDuplexImpl_Initialize(
537     LPDIRECTSOUNDFULLDUPLEX iface,
538     LPCGUID pCaptureGuid,
539     LPCGUID pRendererGuid,
540     LPCDSCBUFFERDESC lpDscBufferDesc,
541     LPCDSBUFFERDESC lpDsBufferDesc,
542     HWND hWnd,
543     DWORD dwLevel,
544     LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8,
545     LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 )
546 {
547     HRESULT hr;
548     IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface;
549
550     TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This,
551         debugstr_guid(pCaptureGuid), debugstr_guid(pRendererGuid),
552         lpDscBufferDesc, lpDsBufferDesc, hWnd, dwLevel,
553         lplpDirectSoundCaptureBuffer8, lplpDirectSoundBuffer8);
554
555     if (This->renderer_device != NULL || This->capture_device != NULL) {
556         WARN("already initialized\n");
557         *lplpDirectSoundCaptureBuffer8 = NULL;
558         *lplpDirectSoundBuffer8 = NULL;
559         return DSERR_ALREADYINITIALIZED;
560     }
561
562     hr = DSOUND_Create8(&IID_IDirectSound8, &This->renderer_device);
563     if (SUCCEEDED(hr))
564         hr = IDirectSound_Initialize(This->renderer_device, pRendererGuid);
565     if (hr != DS_OK) {
566         WARN("DirectSoundDevice_Initialize() failed\n");
567         *lplpDirectSoundCaptureBuffer8 = NULL;
568         *lplpDirectSoundBuffer8 = NULL;
569         return hr;
570     }
571
572     IDirectSound8_SetCooperativeLevel(This->renderer_device, hWnd, dwLevel);
573
574     hr = IDirectSound8_CreateSoundBuffer(This->renderer_device, lpDsBufferDesc,
575         (IDirectSoundBuffer**)lplpDirectSoundBuffer8, NULL);
576     if (hr != DS_OK) {
577         WARN("IDirectSoundBufferImpl_Create() failed\n");
578         *lplpDirectSoundCaptureBuffer8 = NULL;
579         *lplpDirectSoundBuffer8 = NULL;
580         return hr;
581     }
582
583     hr = DSOUND_CaptureCreate8(&IID_IDirectSoundCapture8, &This->capture_device);
584     if (SUCCEEDED(hr))
585         hr = IDirectSoundCapture_Initialize(This->capture_device, pCaptureGuid);
586     if (hr != DS_OK) {
587         WARN("DirectSoundCaptureDevice_Initialize() failed\n");
588         *lplpDirectSoundCaptureBuffer8 = NULL;
589         *lplpDirectSoundBuffer8 = NULL;
590         return hr;
591     }
592
593     hr = IDirectSoundCapture_CreateCaptureBuffer(This->capture_device,
594         lpDscBufferDesc,
595         (IDirectSoundCaptureBuffer**)lplpDirectSoundCaptureBuffer8,
596         NULL);
597     if (hr != DS_OK) {
598         WARN("IDirectSoundCaptureBufferImpl_Create() failed\n");
599         *lplpDirectSoundCaptureBuffer8 = NULL;
600         *lplpDirectSoundBuffer8 = NULL;
601         return hr;
602     }
603
604     return hr;
605 }
606
607 static const IDirectSoundFullDuplexVtbl dsfdvt =
608 {
609     /* IUnknown methods */
610     IDirectSoundFullDuplexImpl_QueryInterface,
611     IDirectSoundFullDuplexImpl_AddRef,
612     IDirectSoundFullDuplexImpl_Release,
613
614     /* IDirectSoundFullDuplex methods */
615     IDirectSoundFullDuplexImpl_Initialize
616 };
617
618 HRESULT DSOUND_FullDuplexCreate(
619     REFIID riid,
620     LPDIRECTSOUNDFULLDUPLEX* ppDSFD)
621 {
622     IDirectSoundFullDuplexImpl *This = NULL;
623     TRACE("(%s, %p)\n", debugstr_guid(riid), ppDSFD);
624
625     if (ppDSFD == NULL) {
626         WARN("invalid parameter: ppDSFD == NULL\n");
627         return DSERR_INVALIDPARAM;
628     }
629
630     if (!IsEqualIID(riid, &IID_IUnknown) &&
631         !IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
632         *ppDSFD = 0;
633         return E_NOINTERFACE;
634     }
635
636     /* Get dsound configuration */
637     setup_dsound_options();
638
639     This = HeapAlloc(GetProcessHeap(),
640         HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl));
641
642     if (This == NULL) {
643         WARN("out of memory\n");
644         *ppDSFD = NULL;
645         return DSERR_OUTOFMEMORY;
646     }
647
648     This->lpVtbl = &dsfdvt;
649     This->ref = 1;
650     This->capture_device = NULL;
651     This->renderer_device = NULL;
652
653     *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
654
655     return DS_OK;
656 }
657
658 /***************************************************************************
659  * DirectSoundFullDuplexCreate [DSOUND.10]
660  *
661  * Create and initialize a DirectSoundFullDuplex interface.
662  *
663  * PARAMS
664  *    pcGuidCaptureDevice [I] Address of sound capture device GUID.
665  *    pcGuidRenderDevice  [I] Address of sound render device GUID.
666  *    pcDSCBufferDesc     [I] Address of capture buffer description.
667  *    pcDSBufferDesc      [I] Address of  render buffer description.
668  *    hWnd                [I] Handle to application window.
669  *    dwLevel             [I] Cooperative level.
670  *    ppDSFD              [O] Address where full duplex interface returned.
671  *    ppDSCBuffer8        [0] Address where capture buffer interface returned.
672  *    ppDSBuffer8         [0] Address where render buffer interface returned.
673  *    pUnkOuter           [I] Must be NULL.
674  *
675  * RETURNS
676  *    Success: DS_OK
677  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
678  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
679  */
680 HRESULT WINAPI
681 DirectSoundFullDuplexCreate(
682     LPCGUID pcGuidCaptureDevice,
683     LPCGUID pcGuidRenderDevice,
684     LPCDSCBUFFERDESC pcDSCBufferDesc,
685     LPCDSBUFFERDESC pcDSBufferDesc,
686     HWND hWnd,
687     DWORD dwLevel,
688     LPDIRECTSOUNDFULLDUPLEX *ppDSFD,
689     LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8,
690     LPDIRECTSOUNDBUFFER8 *ppDSBuffer8,
691     LPUNKNOWN pUnkOuter)
692 {
693     HRESULT hres;
694     IDirectSoundFullDuplexImpl *This = NULL;
695     TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n",
696         debugstr_guid(pcGuidCaptureDevice), debugstr_guid(pcGuidRenderDevice),
697         pcDSCBufferDesc, pcDSBufferDesc, hWnd, dwLevel, ppDSFD, ppDSCBuffer8,
698         ppDSBuffer8, pUnkOuter);
699
700     if (pUnkOuter) {
701         WARN("pUnkOuter != 0\n");
702         *ppDSFD = NULL;
703         return DSERR_NOAGGREGATION;
704     }
705
706     if (pcDSCBufferDesc == NULL) {
707         WARN("invalid parameter: pcDSCBufferDesc == NULL\n");
708         *ppDSFD = NULL;
709         return DSERR_INVALIDPARAM;
710     }
711
712     if (pcDSBufferDesc == NULL) {
713         WARN("invalid parameter: pcDSBufferDesc == NULL\n");
714         *ppDSFD = NULL;
715         return DSERR_INVALIDPARAM;
716     }
717
718     if (ppDSFD == NULL) {
719         WARN("invalid parameter: ppDSFD == NULL\n");
720         return DSERR_INVALIDPARAM;
721     }
722
723     if (ppDSCBuffer8 == NULL) {
724         WARN("invalid parameter: ppDSCBuffer8 == NULL\n");
725         *ppDSFD = NULL;
726         return DSERR_INVALIDPARAM;
727     }
728
729     if (ppDSBuffer8 == NULL) {
730         WARN("invalid parameter: ppDSBuffer8 == NULL\n");
731         *ppDSFD = NULL;
732         return DSERR_INVALIDPARAM;
733     }
734
735     hres = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (LPDIRECTSOUNDFULLDUPLEX*)&This);
736     if (FAILED(hres)) return hres;
737
738     hres = IDirectSoundFullDuplexImpl_Initialize((LPDIRECTSOUNDFULLDUPLEX)This,
739                                                  pcGuidCaptureDevice,
740                                                  pcGuidRenderDevice,
741                                                  pcDSCBufferDesc,
742                                                  pcDSBufferDesc,
743                                                  hWnd, dwLevel, ppDSCBuffer8,
744                                                  ppDSBuffer8);
745     if (hres != DS_OK) {
746         IUnknown_Release((LPDIRECTSOUNDFULLDUPLEX)This);
747         WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
748         *ppDSFD = NULL;
749     } else
750         *ppDSFD = (LPDIRECTSOUNDFULLDUPLEX)This;
751
752     return hres;
753 }