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