ntdll: Switch back to the pthread %fs register in signal handlers.
[wine.git] / dlls / dsound / duplex.c
blobcccfeba0f0678b89a9d05d68c77e421cfd66eb9c
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 "wine/debug.h"
32 #include "dsound.h"
33 #include "dsound_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
37 /*****************************************************************************
38 * IDirectSoundFullDuplex implementation structure
40 typedef struct IDirectSoundFullDuplexImpl
42 IUnknown IUnknown_iface;
43 IDirectSoundFullDuplex IDirectSoundFullDuplex_iface;
44 LONG ref, refdsfd, numIfaces;
45 IUnknown *ds8_unk; /* Aggregated IDirectSound8 */
46 IUnknown *dsc8_unk; /* Aggregated IDirectSoundCapture8 */
47 } IDirectSoundFullDuplexImpl;
49 static void fullduplex_destroy(IDirectSoundFullDuplexImpl *This)
51 IDirectSound8 *ds8;
52 IDirectSoundCapture8 *dsc8;
54 if (This->ds8_unk) {
55 IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
56 while(IDirectSound8_Release(ds8) > 0);
57 IUnknown_Release(This->ds8_unk);
59 if (This->dsc8_unk) {
60 IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
61 while(IDirectSoundCapture_Release(dsc8) > 0);
62 IUnknown_Release(This->dsc8_unk);
64 HeapFree(GetProcessHeap(), 0, This);
65 TRACE("(%p) released\n", This);
68 /*******************************************************************************
69 * IUnknown implementation for DirectSoundFullDuplex
71 static inline IDirectSoundFullDuplexImpl *impl_from_IUnknown(IUnknown *iface)
73 return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IUnknown_iface);
76 static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
78 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
80 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
82 if (!ppv) {
83 WARN("invalid parameter\n");
84 return E_INVALIDARG;
87 if (IsEqualIID(riid, &IID_IUnknown)) {
88 IUnknown_AddRef(&This->IUnknown_iface);
89 *ppv = &This->IUnknown_iface;
90 return S_OK;
91 } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
92 IDirectSoundFullDuplex_AddRef(&This->IDirectSoundFullDuplex_iface);
93 *ppv = &This->IDirectSoundFullDuplex_iface;
94 return S_OK;
95 } else if (This->ds8_unk && (IsEqualIID(riid, &IID_IDirectSound) ||
96 IsEqualIID(riid, &IID_IDirectSound8)))
97 return IUnknown_QueryInterface(This->ds8_unk, riid, ppv);
98 else if (This->dsc8_unk && IsEqualIID(riid, &IID_IDirectSoundCapture))
99 return IUnknown_QueryInterface(This->dsc8_unk, riid, ppv);
101 *ppv = NULL;
102 return E_NOINTERFACE;
105 static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
107 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
108 ULONG ref = InterlockedIncrement(&This->ref);
110 TRACE("(%p) ref=%d\n", This, ref);
112 if(ref == 1)
113 InterlockedIncrement(&This->numIfaces);
114 return ref;
117 static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
119 IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
120 ULONG ref = InterlockedDecrement(&This->ref);
122 TRACE("(%p) ref=%d\n", This, ref);
124 if (!ref && !InterlockedDecrement(&This->numIfaces))
125 fullduplex_destroy(This);
126 return ref;
129 static const IUnknownVtbl unk_vtbl =
131 IUnknownImpl_QueryInterface,
132 IUnknownImpl_AddRef,
133 IUnknownImpl_Release
136 /***************************************************************************
137 * IDirectSoundFullDuplex implementation
139 static inline IDirectSoundFullDuplexImpl *impl_from_IDirectSoundFullDuplex(IDirectSoundFullDuplex *iface)
141 return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IDirectSoundFullDuplex_iface);
144 static HRESULT WINAPI IDirectSoundFullDuplexImpl_QueryInterface(IDirectSoundFullDuplex *iface,
145 REFIID riid, void **ppv)
147 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
148 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
149 return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
152 static ULONG WINAPI IDirectSoundFullDuplexImpl_AddRef(IDirectSoundFullDuplex *iface)
154 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
155 ULONG ref = InterlockedIncrement(&This->refdsfd);
157 TRACE("(%p) ref=%d\n", This, ref);
159 if(ref == 1)
160 InterlockedIncrement(&This->numIfaces);
161 return ref;
164 static ULONG WINAPI IDirectSoundFullDuplexImpl_Release(IDirectSoundFullDuplex *iface)
166 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
167 ULONG ref = InterlockedDecrement(&This->refdsfd);
169 TRACE("(%p) ref=%d\n", This, ref);
171 if (!ref && !InterlockedDecrement(&This->numIfaces))
172 fullduplex_destroy(This);
173 return ref;
176 static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(IDirectSoundFullDuplex *iface,
177 const GUID *capture_dev, const GUID *render_dev, const DSCBUFFERDESC *cbufdesc,
178 const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level, IDirectSoundCaptureBuffer8 **dscb8,
179 IDirectSoundBuffer8 **dsb8)
181 IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
182 IDirectSound8 *ds8 = NULL;
183 IDirectSoundCapture8 *dsc8 = NULL;
184 HRESULT hr;
186 TRACE("(%p,%s,%s,%p,%p,%p,%x,%p,%p)\n", This, debugstr_guid(capture_dev),
187 debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dscb8, dsb8);
189 if (!dscb8 || !dsb8)
190 return E_INVALIDARG;
192 *dscb8 = NULL;
193 *dsb8 = NULL;
195 if (This->ds8_unk || This->dsc8_unk) {
196 WARN("already initialized\n");
197 return DSERR_ALREADYINITIALIZED;
200 hr = IDirectSoundImpl_Create(&This->IUnknown_iface, &IID_IUnknown, (void**)&This->ds8_unk,
201 TRUE);
202 if (SUCCEEDED(hr)) {
203 IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
204 hr = IDirectSound8_Initialize(ds8, render_dev);
206 if (hr != DS_OK) {
207 WARN("Creating/initializing IDirectSound8 failed\n");
208 goto error;
211 IDirectSound8_SetCooperativeLevel(ds8, hwnd, level);
213 hr = IDirectSound8_CreateSoundBuffer(ds8, bufdesc, (IDirectSoundBuffer**)dsb8, NULL);
214 if (hr != DS_OK) {
215 WARN("IDirectSoundBuffer_Create() failed\n");
216 goto error;
219 hr = IDirectSoundCaptureImpl_Create(&This->IUnknown_iface, &IID_IUnknown,
220 (void**)&This->dsc8_unk, TRUE);
221 if (SUCCEEDED(hr)) {
222 IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
223 hr = IDirectSoundCapture_Initialize(dsc8, capture_dev);
225 if (hr != DS_OK) {
226 WARN("Creating/initializing IDirectSoundCapture8 failed\n");
227 goto error;
230 hr = IDirectSoundCapture_CreateCaptureBuffer(dsc8, cbufdesc,
231 (IDirectSoundCaptureBuffer**)dscb8, NULL);
232 if (hr != DS_OK) {
233 WARN("IDirectSoundCapture_CreateCaptureBuffer() failed\n");
234 goto error;
237 IDirectSound8_Release(ds8);
238 IDirectSoundCapture_Release(dsc8);
239 return DS_OK;
241 error:
242 if (*dsb8) {
243 IDirectSoundBuffer8_Release(*dsb8);
244 *dsb8 = NULL;
246 if (ds8)
247 IDirectSound8_Release(ds8);
248 if (This->ds8_unk) {
249 IUnknown_Release(This->ds8_unk);
250 This->ds8_unk = NULL;
252 if (*dscb8) {
253 IDirectSoundCaptureBuffer8_Release(*dscb8);
254 *dscb8 = NULL;
256 if (dsc8)
257 IDirectSoundCapture_Release(dsc8);
258 if (This->dsc8_unk) {
259 IUnknown_Release(This->dsc8_unk);
260 This->dsc8_unk = NULL;
262 return hr;
265 static const IDirectSoundFullDuplexVtbl dsfd_vtbl =
267 /* IUnknown methods */
268 IDirectSoundFullDuplexImpl_QueryInterface,
269 IDirectSoundFullDuplexImpl_AddRef,
270 IDirectSoundFullDuplexImpl_Release,
272 /* IDirectSoundFullDuplex methods */
273 IDirectSoundFullDuplexImpl_Initialize
276 HRESULT DSOUND_FullDuplexCreate(REFIID riid, void **ppv)
278 IDirectSoundFullDuplexImpl *obj;
279 HRESULT hr;
281 TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
283 *ppv = NULL;
284 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
285 if (!obj) {
286 WARN("out of memory\n");
287 return DSERR_OUTOFMEMORY;
290 setup_dsound_options();
292 obj->IDirectSoundFullDuplex_iface.lpVtbl = &dsfd_vtbl;
293 obj->IUnknown_iface.lpVtbl = &unk_vtbl;
294 obj->ref = 1;
295 obj->refdsfd = 0;
296 obj->numIfaces = 1;
298 hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
299 IUnknown_Release(&obj->IUnknown_iface);
301 return hr;
304 /***************************************************************************
305 * DirectSoundFullDuplexCreate [DSOUND.10]
307 * Create and initialize a DirectSoundFullDuplex interface.
309 * PARAMS
310 * capture_dev [I] Address of sound capture device GUID.
311 * render_dev [I] Address of sound render device GUID.
312 * cbufdesc [I] Address of capture buffer description.
313 * bufdesc [I] Address of render buffer description.
314 * hwnd [I] Handle to application window.
315 * level [I] Cooperative level.
316 * dsfd [O] Address where full duplex interface returned.
317 * dscb8 [0] Address where capture buffer interface returned.
318 * dsb8 [0] Address where render buffer interface returned.
319 * outer_unk [I] Must be NULL.
321 * RETURNS
322 * Success: DS_OK
323 * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
324 * DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
326 HRESULT WINAPI DirectSoundFullDuplexCreate(const GUID *capture_dev, const GUID *render_dev,
327 const DSCBUFFERDESC *cbufdesc, const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level,
328 IDirectSoundFullDuplex **dsfd, IDirectSoundCaptureBuffer8 **dscb8,
329 IDirectSoundBuffer8 **dsb8, IUnknown *outer_unk)
331 HRESULT hr;
333 TRACE("(%s,%s,%p,%p,%p,%x,%p,%p,%p,%p)\n", debugstr_guid(capture_dev),
334 debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dsfd, dscb8, dsb8,
335 outer_unk);
337 if (!dsfd)
338 return DSERR_INVALIDPARAM;
339 if (outer_unk) {
340 *dsfd = NULL;
341 return DSERR_NOAGGREGATION;
344 hr = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (void**)dsfd);
345 if (hr == DS_OK) {
346 hr = IDirectSoundFullDuplex_Initialize(*dsfd, capture_dev, render_dev, cbufdesc, bufdesc,
347 hwnd, level, dscb8, dsb8);
348 if (hr != DS_OK) {
349 IDirectSoundFullDuplex_Release(*dsfd);
350 *dsfd = NULL;
351 WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
355 return hr;