kernel32/tests: Don't test functions directly when reporting GetLastError().
[wine.git] / dlls / dsound / duplex.c
blob153c7b66151b51fe80f56b0bb2c3463235a0176b
1 /* DirectSoundFullDuplex
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2001 TransGaming Technologies, Inc.
6 * Copyright 2005 Robert Reif
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.
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.
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
23 #include <stdarg.h>
25 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "mmddk.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33 #include "dsound.h"
34 #include "dsound_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
38 /*****************************************************************************
39 * IDirectSoundFullDuplex implementation structure
41 typedef struct IDirectSoundFullDuplexImpl
43 IUnknown IUnknown_iface;
44 IDirectSoundFullDuplex IDirectSoundFullDuplex_iface;
45 LONG ref, refdsfd, numIfaces;
46 IUnknown *ds8_unk; /* Aggregated IDirectSound8 */
47 IUnknown *dsc8_unk; /* Aggregated IDirectSoundCapture8 */
48 } IDirectSoundFullDuplexImpl;
50 static void fullduplex_destroy(IDirectSoundFullDuplexImpl *This)
52 IDirectSound8 *ds8;
53 IDirectSoundCapture8 *dsc8;
55 if (This->ds8_unk) {
56 IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
57 while(IDirectSound8_Release(ds8) > 0);
58 IUnknown_Release(This->ds8_unk);
60 if (This->dsc8_unk) {
61 IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
62 while(IDirectSoundCapture_Release(dsc8) > 0);
63 IUnknown_Release(This->dsc8_unk);
65 HeapFree(GetProcessHeap(), 0, This);
66 TRACE("(%p) released\n", This);
69 /*******************************************************************************
70 * IUnknown implementation for DirectSoundFullDuplex
72 static inline IDirectSoundFullDuplexImpl *impl_from_IUnknown(IUnknown *iface)
74 return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IUnknown_iface);
77 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
79 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
81 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
83 if (!ppv) {
84 WARN("invalid parameter\n");
85 return E_INVALIDARG;
88 if (IsEqualIID(riid, &IID_IUnknown)) {
89 IUnknown_AddRef(&This->IUnknown_iface);
90 *ppv = &This->IUnknown_iface;
91 return S_OK;
92 } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
93 IDirectSoundFullDuplex_AddRef(&This->IDirectSoundFullDuplex_iface);
94 *ppv = &This->IDirectSoundFullDuplex_iface;
95 return S_OK;
96 } else if (This->ds8_unk && (IsEqualIID(riid, &IID_IDirectSound) ||
97 IsEqualIID(riid, &IID_IDirectSound8)))
98 return IUnknown_QueryInterface(This->ds8_unk, riid, ppv);
99 else if (This->dsc8_unk && IsEqualIID(riid, &IID_IDirectSoundCapture))
100 return IUnknown_QueryInterface(This->dsc8_unk, riid, ppv);
102 *ppv = NULL;
103 return E_NOINTERFACE;
106 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
108 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
109 ULONG ref = InterlockedIncrement(&This->ref);
111 TRACE("(%p) ref=%d\n", This, ref);
113 if(ref == 1)
114 InterlockedIncrement(&This->numIfaces);
115 return ref;
118 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
120 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
121 ULONG ref = InterlockedDecrement(&This->ref);
123 TRACE("(%p) ref=%d\n", This, ref);
125 if (!ref && !InterlockedDecrement(&This->numIfaces))
126 fullduplex_destroy(This);
127 return ref;
130 static const IUnknownVtbl unk_vtbl =
132 IUnknownImpl_QueryInterface,
133 IUnknownImpl_AddRef,
134 IUnknownImpl_Release
137 /***************************************************************************
138 * IDirectSoundFullDuplex implementation
140 static inline IDirectSoundFullDuplexImpl *impl_from_IDirectSoundFullDuplex(IDirectSoundFullDuplex *iface)
142 return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IDirectSoundFullDuplex_iface);
145 static HRESULT WINAPI IDirectSoundFullDuplexImpl_QueryInterface(IDirectSoundFullDuplex *iface,
146 REFIID riid, void **ppv)
148 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
149 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
150 return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
153 static ULONG WINAPI IDirectSoundFullDuplexImpl_AddRef(IDirectSoundFullDuplex *iface)
155 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
156 ULONG ref = InterlockedIncrement(&This->refdsfd);
158 TRACE("(%p) ref=%d\n", This, ref);
160 if(ref == 1)
161 InterlockedIncrement(&This->numIfaces);
162 return ref;
165 static ULONG WINAPI IDirectSoundFullDuplexImpl_Release(IDirectSoundFullDuplex *iface)
167 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
168 ULONG ref = InterlockedDecrement(&This->refdsfd);
170 TRACE("(%p) ref=%d\n", This, ref);
172 if (!ref && !InterlockedDecrement(&This->numIfaces))
173 fullduplex_destroy(This);
174 return ref;
177 static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(IDirectSoundFullDuplex *iface,
178 const GUID *capture_dev, const GUID *render_dev, const DSCBUFFERDESC *cbufdesc,
179 const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level, IDirectSoundCaptureBuffer8 **dscb8,
180 IDirectSoundBuffer8 **dsb8)
182 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
183 IDirectSound8 *ds8 = NULL;
184 IDirectSoundCapture8 *dsc8 = NULL;
185 HRESULT hr;
187 TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This, debugstr_guid(capture_dev),
188 debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dscb8, dsb8);
190 if (!dscb8 || !dsb8)
191 return E_INVALIDARG;
193 *dscb8 = NULL;
194 *dsb8 = NULL;
196 if (This->ds8_unk || This->dsc8_unk) {
197 WARN("already initialized\n");
198 return DSERR_ALREADYINITIALIZED;
201 hr = IDirectSoundImpl_Create(&This->IUnknown_iface, &IID_IUnknown, (void**)&This->ds8_unk,
202 TRUE);
203 if (SUCCEEDED(hr)) {
204 IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
205 hr = IDirectSound_Initialize(ds8, render_dev);
207 if (hr != DS_OK) {
208 WARN("Creating/initializing IDirectSound8 failed\n");
209 goto error;
212 IDirectSound8_SetCooperativeLevel(ds8, hwnd, level);
214 hr = IDirectSound8_CreateSoundBuffer(ds8, bufdesc, (IDirectSoundBuffer**)dsb8, NULL);
215 if (hr != DS_OK) {
216 WARN("IDirectSoundBuffer_Create() failed\n");
217 goto error;
220 hr = IDirectSoundCaptureImpl_Create(&This->IUnknown_iface, &IID_IUnknown,
221 (void**)&This->dsc8_unk, TRUE);
222 if (SUCCEEDED(hr)) {
223 IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
224 hr = IDirectSoundCapture_Initialize(dsc8, capture_dev);
226 if (hr != DS_OK) {
227 WARN("Creating/initializing IDirectSoundCapture8 failed\n");
228 goto error;
231 hr = IDirectSoundCapture_CreateCaptureBuffer(dsc8, cbufdesc,
232 (IDirectSoundCaptureBuffer**)dscb8, NULL);
233 if (hr != DS_OK) {
234 WARN("IDirectSoundCapture_CreateCaptureBuffer() failed\n");
235 goto error;
238 IDirectSound8_Release(ds8);
239 IDirectSoundCapture_Release(dsc8);
240 return DS_OK;
242 error:
243 if (*dsb8) {
244 IDirectSoundBuffer8_Release(*dsb8);
245 *dsb8 = NULL;
247 if (ds8)
248 IDirectSound8_Release(ds8);
249 if (This->ds8_unk) {
250 IUnknown_Release(This->ds8_unk);
251 This->ds8_unk = NULL;
253 if (*dscb8) {
254 IDirectSoundCaptureBuffer8_Release(*dscb8);
255 *dscb8 = NULL;
257 if (dsc8)
258 IDirectSoundCapture_Release(dsc8);
259 if (This->dsc8_unk) {
260 IUnknown_Release(This->dsc8_unk);
261 This->dsc8_unk = NULL;
263 return hr;
266 static const IDirectSoundFullDuplexVtbl dsfd_vtbl =
268 /* IUnknown methods */
269 IDirectSoundFullDuplexImpl_QueryInterface,
270 IDirectSoundFullDuplexImpl_AddRef,
271 IDirectSoundFullDuplexImpl_Release,
273 /* IDirectSoundFullDuplex methods */
274 IDirectSoundFullDuplexImpl_Initialize
277 HRESULT DSOUND_FullDuplexCreate(REFIID riid, void **ppv)
279 IDirectSoundFullDuplexImpl *obj;
280 HRESULT hr;
282 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
284 *ppv = NULL;
285 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
286 if (!obj) {
287 WARN("out of memory\n");
288 return DSERR_OUTOFMEMORY;
291 setup_dsound_options();
293 obj->IDirectSoundFullDuplex_iface.lpVtbl = &dsfd_vtbl;
294 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
295 obj->ref = 1;
296 obj->refdsfd = 0;
297 obj->numIfaces = 1;
299 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
300 IUnknown_Release(&obj->IUnknown_iface);
302 return hr;
305 /***************************************************************************
306 * DirectSoundFullDuplexCreate [DSOUND.10]
308 * Create and initialize a DirectSoundFullDuplex interface.
310 * PARAMS
311 * capture_dev [I] Address of sound capture device GUID.
312 * render_dev [I] Address of sound render device GUID.
313 * cbufdesc [I] Address of capture buffer description.
314 * bufdesc [I] Address of render buffer description.
315 * hwnd [I] Handle to application window.
316 * level [I] Cooperative level.
317 * dsfd [O] Address where full duplex interface returned.
318 * dscb8 [0] Address where capture buffer interface returned.
319 * dsb8 [0] Address where render buffer interface returned.
320 * outer_unk [I] Must be NULL.
322 * RETURNS
323 * Success: DS_OK
324 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
325 * DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
327 HRESULT WINAPI DirectSoundFullDuplexCreate(const GUID *capture_dev, const GUID *render_dev,
328 const DSCBUFFERDESC *cbufdesc, const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level,
329 IDirectSoundFullDuplex **dsfd, IDirectSoundCaptureBuffer8 **dscb8,
330 IDirectSoundBuffer8 **dsb8, IUnknown *outer_unk)
332 HRESULT hr;
334 TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n", debugstr_guid(capture_dev),
335 debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dsfd, dscb8, dsb8,
336 outer_unk);
338 if (!dsfd)
339 return DSERR_INVALIDPARAM;
340 if (outer_unk) {
341 *dsfd = NULL;
342 return DSERR_NOAGGREGATION;
345 hr = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (void**)dsfd);
346 if (hr == DS_OK) {
347 hr = IDirectSoundFullDuplex_Initialize(*dsfd, capture_dev, render_dev, cbufdesc, bufdesc,
348 hwnd, level, dscb8, dsb8);
349 if (hr != DS_OK) {
350 IDirectSoundFullDuplex_Release(*dsfd);
351 *dsfd = NULL;
352 WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
356 return hr;