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