dsound: Aggregate IDirectSoundCapture8 instead of wrapping it.
[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 "dsound_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
39
40 /*****************************************************************************
41  * IDirectSoundFullDuplex implementation structure
42  */
43 typedef struct IDirectSoundFullDuplexImpl
44 {
45     IUnknown               IUnknown_iface;
46     IDirectSoundFullDuplex IDirectSoundFullDuplex_iface;
47     LONG                   ref, refdsfd, numIfaces;
48     IUnknown              *ds8_unk;     /* Aggregated IDirectSound8 */
49     IUnknown              *dsc8_unk;    /* Aggregated IDirectSoundCapture8 */
50 } IDirectSoundFullDuplexImpl;
51
52 static void fullduplex_destroy(IDirectSoundFullDuplexImpl *This)
53 {
54     IDirectSound8 *ds8;
55     IDirectSoundCapture8 *dsc8;
56
57     if (This->ds8_unk) {
58         IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
59         while(IDirectSound8_Release(ds8) > 0);
60         IUnknown_Release(This->ds8_unk);
61     }
62     if (This->dsc8_unk) {
63         IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
64         while(IDirectSoundCapture_Release(dsc8) > 0);
65         IUnknown_Release(This->dsc8_unk);
66     }
67     HeapFree(GetProcessHeap(), 0, This);
68     TRACE("(%p) released\n", This);
69 }
70
71 /*******************************************************************************
72  * IUnknown implemetation for DirectSoundFullDuplex
73  */
74 static inline IDirectSoundFullDuplexImpl *impl_from_IUnknown(IUnknown *iface)
75 {
76     return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IUnknown_iface);
77 }
78
79 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
80 {
81     IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
82     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
83     return IDirectSoundFullDuplex_QueryInterface(&This->IDirectSoundFullDuplex_iface, riid, ppv);
84 }
85
86 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
87 {
88     IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
89     ULONG ref = InterlockedIncrement(&This->ref);
90
91     TRACE("(%p) ref=%d\n", This, ref);
92
93     if(ref == 1)
94         InterlockedIncrement(&This->numIfaces);
95     return ref;
96 }
97
98 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
99 {
100     IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
101     ULONG ref = InterlockedDecrement(&This->ref);
102
103     TRACE("(%p) ref=%d\n", This, ref);
104
105     if (!ref && !InterlockedDecrement(&This->numIfaces))
106         fullduplex_destroy(This);
107     return ref;
108 }
109
110 static const IUnknownVtbl unk_vtbl =
111 {
112     IUnknownImpl_QueryInterface,
113     IUnknownImpl_AddRef,
114     IUnknownImpl_Release
115 };
116
117 /***************************************************************************
118  * IDirectSoundFullDuplex implementation
119  */
120 static inline IDirectSoundFullDuplexImpl *impl_from_IDirectSoundFullDuplex(IDirectSoundFullDuplex *iface)
121 {
122     return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IDirectSoundFullDuplex_iface);
123 }
124
125 static ULONG WINAPI IDirectSoundFullDuplexImpl_AddRef(IDirectSoundFullDuplex *iface)
126 {
127     IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
128     ULONG ref = InterlockedIncrement(&This->refdsfd);
129
130     TRACE("(%p) ref=%d\n", This, ref);
131
132     if(ref == 1)
133         InterlockedIncrement(&This->numIfaces);
134     return ref;
135 }
136
137 static HRESULT WINAPI IDirectSoundFullDuplexImpl_QueryInterface(IDirectSoundFullDuplex *iface,
138         REFIID riid, void **ppv)
139 {
140     IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
141     TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
142
143     if (ppv == NULL) {
144         WARN("invalid parameter\n");
145         return E_INVALIDARG;
146     }
147
148     *ppv = NULL;
149
150     if (IsEqualIID(riid, &IID_IUnknown)) {
151         IUnknown_AddRef(&This->IUnknown_iface);
152         *ppv = &This->IUnknown_iface;
153         return S_OK;
154     } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
155         IDirectSoundFullDuplexImpl_AddRef(iface);
156         *ppv = &This->IDirectSoundFullDuplex_iface;
157         return S_OK;
158     } else if (This->ds8_unk && (IsEqualIID(riid, &IID_IDirectSound) ||
159                                  IsEqualIID(riid, &IID_IDirectSound8))) {
160         return IUnknown_QueryInterface(This->ds8_unk, riid, ppv);
161     } else if (This->dsc8_unk && IsEqualIID(riid, &IID_IDirectSoundCapture)) {
162         return IUnknown_QueryInterface(This->dsc8_unk, riid, ppv);
163     }
164
165     return E_NOINTERFACE;
166 }
167
168 static ULONG WINAPI IDirectSoundFullDuplexImpl_Release(IDirectSoundFullDuplex *iface)
169 {
170     IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
171     ULONG ref = InterlockedDecrement(&This->refdsfd);
172
173     TRACE("(%p) ref=%d\n", This, ref);
174
175     if (!ref && !InterlockedDecrement(&This->numIfaces))
176         fullduplex_destroy(This);
177     return ref;
178 }
179
180 static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(IDirectSoundFullDuplex *iface,
181         const GUID *capture_dev, const GUID *render_dev, const DSCBUFFERDESC *cbufdesc,
182         const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level, IDirectSoundCaptureBuffer8 **dscb8,
183         IDirectSoundBuffer8 **dsb8)
184 {
185     IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
186     IDirectSound8 *ds8 = NULL;
187     IDirectSoundCapture8 *dsc8 = NULL;
188     HRESULT hr;
189
190     TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This, debugstr_guid(capture_dev),
191             debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dscb8, dsb8);
192
193     if (!dscb8 || !dsb8)
194         return E_INVALIDARG;
195
196     *dscb8 = NULL;
197     *dsb8 = NULL;
198
199     if (This->ds8_unk || This->dsc8_unk) {
200         WARN("already initialized\n");
201         return DSERR_ALREADYINITIALIZED;
202     }
203
204     hr = IDirectSoundImpl_Create(&This->IUnknown_iface, &IID_IUnknown, (void**)&This->ds8_unk,
205             TRUE);
206     if (SUCCEEDED(hr)) {
207         IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
208         hr = IDirectSound_Initialize(ds8, render_dev);
209     }
210     if (hr != DS_OK) {
211         WARN("Creating/initializing IDirectSound8 failed\n");
212         goto error;
213     }
214
215     IDirectSound8_SetCooperativeLevel(ds8, hwnd, level);
216
217     hr = IDirectSound8_CreateSoundBuffer(ds8, bufdesc, (IDirectSoundBuffer**)dsb8, NULL);
218     if (hr != DS_OK) {
219         WARN("IDirectSoundBuffer_Create() failed\n");
220         goto error;
221     }
222
223     hr = IDirectSoundCaptureImpl_Create(&This->IUnknown_iface, &IID_IUnknown,
224             (void**)&This->dsc8_unk, TRUE);
225     if (SUCCEEDED(hr)) {
226         IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
227         hr = IDirectSoundCapture_Initialize(dsc8, capture_dev);
228     }
229     if (hr != DS_OK) {
230         WARN("Creating/initializing IDirectSoundCapture8 failed\n");
231         goto error;
232     }
233
234     hr = IDirectSoundCapture_CreateCaptureBuffer(dsc8, cbufdesc,
235             (IDirectSoundCaptureBuffer**)dscb8, NULL);
236     if (hr != DS_OK) {
237         WARN("IDirectSoundCapture_CreateCaptureBuffer() failed\n");
238         goto error;
239     }
240
241     IDirectSound8_Release(ds8);
242     IDirectSoundCapture_Release(dsc8);
243     return DS_OK;
244
245 error:
246     if (*dsb8) {
247         IDirectSoundBuffer8_Release(*dsb8);
248         *dsb8 = NULL;
249     }
250     if (ds8)
251         IDirectSound8_Release(ds8);
252     if (This->ds8_unk) {
253         IUnknown_Release(This->ds8_unk);
254         This->ds8_unk = NULL;
255     }
256     if (*dscb8) {
257         IDirectSoundCaptureBuffer8_Release(*dscb8);
258         *dscb8 = NULL;
259     }
260     if (dsc8)
261         IDirectSoundCapture_Release(dsc8);
262     if (This->dsc8_unk) {
263         IUnknown_Release(This->dsc8_unk);
264         This->dsc8_unk = NULL;
265     }
266     return hr;
267 }
268
269 static const IDirectSoundFullDuplexVtbl dsfd_vtbl =
270 {
271     /* IUnknown methods */
272     IDirectSoundFullDuplexImpl_QueryInterface,
273     IDirectSoundFullDuplexImpl_AddRef,
274     IDirectSoundFullDuplexImpl_Release,
275
276     /* IDirectSoundFullDuplex methods */
277     IDirectSoundFullDuplexImpl_Initialize
278 };
279
280 HRESULT DSOUND_FullDuplexCreate(REFIID riid, void **ppv)
281 {
282     IDirectSoundFullDuplexImpl *obj;
283     HRESULT hr;
284
285     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
286
287     *ppv = NULL;
288     obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
289     if (!obj) {
290         WARN("out of memory\n");
291         return DSERR_OUTOFMEMORY;
292     }
293
294     setup_dsound_options();
295
296     obj->IDirectSoundFullDuplex_iface.lpVtbl = &dsfd_vtbl;
297     obj->IUnknown_iface.lpVtbl = &unk_vtbl;
298     obj->ref = 1;
299     obj->refdsfd = 0;
300     obj->numIfaces = 1;
301
302     hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
303     IUnknown_Release(&obj->IUnknown_iface);
304
305     return hr;
306 }
307
308 /***************************************************************************
309  * DirectSoundFullDuplexCreate [DSOUND.10]
310  *
311  * Create and initialize a DirectSoundFullDuplex interface.
312  *
313  * PARAMS
314  *    capture_dev         [I] Address of sound capture device GUID.
315  *    render_dev          [I] Address of sound render device GUID.
316  *    cbufdesc            [I] Address of capture buffer description.
317  *    bufdesc             [I] Address of  render buffer description.
318  *    hwnd                [I] Handle to application window.
319  *    level               [I] Cooperative level.
320  *    dsfd                [O] Address where full duplex interface returned.
321  *    dscb8               [0] Address where capture buffer interface returned.
322  *    dsb8                [0] Address where render buffer interface returned.
323  *    outer_unk           [I] Must be NULL.
324  *
325  * RETURNS
326  *    Success: DS_OK
327  *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
328  *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
329  */
330 HRESULT WINAPI DirectSoundFullDuplexCreate(const GUID *capture_dev, const GUID *render_dev,
331         const DSCBUFFERDESC *cbufdesc, const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level,
332         IDirectSoundFullDuplex **dsfd, IDirectSoundCaptureBuffer8 **dscb8,
333         IDirectSoundBuffer8 **dsb8, IUnknown *outer_unk)
334 {
335     HRESULT hr;
336
337     TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n", debugstr_guid(capture_dev),
338             debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dsfd, dscb8, dsb8,
339             outer_unk);
340
341     if (!dsfd)
342         return DSERR_INVALIDPARAM;
343     if (outer_unk) {
344         *dsfd = NULL;
345         return DSERR_NOAGGREGATION;
346     }
347
348     hr = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (void**)dsfd);
349     if (hr == DS_OK) {
350         hr = IDirectSoundFullDuplex_Initialize(*dsfd, capture_dev, render_dev, cbufdesc, bufdesc,
351                 hwnd, level, dscb8, dsb8);
352         if (hr != DS_OK) {
353             IDirectSoundFullDuplex_Release(*dsfd);
354             *dsfd = NULL;
355             WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
356         }
357     }
358
359     return hr;
360 }