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