duplex.c 11.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*              DirectSoundFullDuplex
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998 Rob Riggs
 * Copyright 2000-2001 TransGaming Technologies, Inc.
 * Copyright 2005 Robert Reif
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 24
 */

#include <stdarg.h>

25
#define COBJMACROS
26 27
#include "windef.h"
#include "winbase.h"
28
#include "winuser.h"
29 30 31 32 33 34 35 36
#include "mmsystem.h"
#include "mmddk.h"
#include "wine/debug.h"
#include "dsound.h"
#include "dsound_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dsound);

37 38 39 40 41
/*****************************************************************************
 * IDirectSoundFullDuplex implementation structure
 */
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 48
} IDirectSoundFullDuplexImpl;

49 50
static void fullduplex_destroy(IDirectSoundFullDuplexImpl *This)
{
51
    IDirectSound8 *ds8;
52
    IDirectSoundCapture8 *dsc8;
53 54 55 56 57 58

    if (This->ds8_unk) {
        IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
        while(IDirectSound8_Release(ds8) > 0);
        IUnknown_Release(This->ds8_unk);
    }
59 60 61 62 63
    if (This->dsc8_unk) {
        IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
        while(IDirectSoundCapture_Release(dsc8) > 0);
        IUnknown_Release(This->dsc8_unk);
    }
64
    TRACE("(%p) released\n", This);
65
    HeapFree(GetProcessHeap(), 0, This);
66 67
}

68
/*******************************************************************************
69
 * IUnknown implementation for DirectSoundFullDuplex
70
 */
71
static inline IDirectSoundFullDuplexImpl *impl_from_IUnknown(IUnknown *iface)
72
{
73
    return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IUnknown_iface);
74 75
}

76
static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
77
{
78
    IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
79

80
    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

    if (!ppv) {
        WARN("invalid parameter\n");
        return E_INVALIDARG;
    }

    if (IsEqualIID(riid, &IID_IUnknown)) {
        IUnknown_AddRef(&This->IUnknown_iface);
        *ppv = &This->IUnknown_iface;
        return S_OK;
    } else if (IsEqualIID(riid, &IID_IDirectSoundFullDuplex)) {
        IDirectSoundFullDuplex_AddRef(&This->IDirectSoundFullDuplex_iface);
        *ppv = &This->IDirectSoundFullDuplex_iface;
        return S_OK;
    } else if (This->ds8_unk && (IsEqualIID(riid, &IID_IDirectSound) ||
                                 IsEqualIID(riid, &IID_IDirectSound8)))
        return IUnknown_QueryInterface(This->ds8_unk, riid, ppv);
    else if (This->dsc8_unk && IsEqualIID(riid, &IID_IDirectSoundCapture))
        return IUnknown_QueryInterface(This->dsc8_unk, riid, ppv);

    *ppv = NULL;
    return E_NOINTERFACE;
103 104
}

105
static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface)
106
{
107 108 109
    IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
    ULONG ref = InterlockedIncrement(&This->ref);

110
    TRACE("(%p) ref=%ld\n", This, ref);
111 112 113

    if(ref == 1)
        InterlockedIncrement(&This->numIfaces);
114 115 116
    return ref;
}

117
static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface)
118
{
119 120
    IDirectSoundFullDuplexImpl *This = impl_from_IUnknown(iface);
    ULONG ref = InterlockedDecrement(&This->ref);
121

122
    TRACE("(%p) ref=%ld\n", This, ref);
123

124 125 126
    if (!ref && !InterlockedDecrement(&This->numIfaces))
        fullduplex_destroy(This);
    return ref;
127 128
}

129 130 131 132 133 134 135
static const IUnknownVtbl unk_vtbl =
{
    IUnknownImpl_QueryInterface,
    IUnknownImpl_AddRef,
    IUnknownImpl_Release
};

136
/***************************************************************************
137
 * IDirectSoundFullDuplex implementation
138
 */
139
static inline IDirectSoundFullDuplexImpl *impl_from_IDirectSoundFullDuplex(IDirectSoundFullDuplex *iface)
140
{
141 142 143
    return CONTAINING_RECORD(iface, IDirectSoundFullDuplexImpl, IDirectSoundFullDuplex_iface);
}

144 145 146 147 148 149 150 151
static HRESULT WINAPI IDirectSoundFullDuplexImpl_QueryInterface(IDirectSoundFullDuplex *iface,
        REFIID riid, void **ppv)
{
    IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppv);
    return IUnknown_QueryInterface(&This->IUnknown_iface, riid, ppv);
}

152 153 154
static ULONG WINAPI IDirectSoundFullDuplexImpl_AddRef(IDirectSoundFullDuplex *iface)
{
    IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
155
    ULONG ref = InterlockedIncrement(&This->refdsfd);
156

157
    TRACE("(%p) ref=%ld\n", This, ref);
158 159 160

    if(ref == 1)
        InterlockedIncrement(&This->numIfaces);
161 162 163
    return ref;
}

164
static ULONG WINAPI IDirectSoundFullDuplexImpl_Release(IDirectSoundFullDuplex *iface)
165
{
166
    IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
167
    ULONG ref = InterlockedDecrement(&This->refdsfd);
168

169
    TRACE("(%p) ref=%ld\n", This, ref);
170 171 172

    if (!ref && !InterlockedDecrement(&This->numIfaces))
        fullduplex_destroy(This);
173 174 175
    return ref;
}

176 177 178 179
static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize(IDirectSoundFullDuplex *iface,
        const GUID *capture_dev, const GUID *render_dev, const DSCBUFFERDESC *cbufdesc,
        const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level, IDirectSoundCaptureBuffer8 **dscb8,
        IDirectSoundBuffer8 **dsb8)
180
{
181
    IDirectSoundFullDuplexImpl *This = impl_from_IDirectSoundFullDuplex(iface);
182
    IDirectSound8 *ds8 = NULL;
183
    IDirectSoundCapture8 *dsc8 = NULL;
184 185
    HRESULT hr;

186
    TRACE("(%p,%s,%s,%p,%p,%p,%lx,%p,%p)\n", This, debugstr_guid(capture_dev),
187 188 189 190 191 192 193
            debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dscb8, dsb8);

    if (!dscb8 || !dsb8)
        return E_INVALIDARG;

    *dscb8 = NULL;
    *dsb8 = NULL;
194

195
    if (This->ds8_unk || This->dsc8_unk) {
196 197 198 199
        WARN("already initialized\n");
        return DSERR_ALREADYINITIALIZED;
    }

200 201 202 203
    hr = IDirectSoundImpl_Create(&This->IUnknown_iface, &IID_IUnknown, (void**)&This->ds8_unk,
            TRUE);
    if (SUCCEEDED(hr)) {
        IUnknown_QueryInterface(This->ds8_unk, &IID_IDirectSound8, (void**)&ds8);
204
        hr = IDirectSound8_Initialize(ds8, render_dev);
205
    }
206
    if (hr != DS_OK) {
207
        WARN("Creating/initializing IDirectSound8 failed\n");
208
        goto error;
209
    }
210

211
    IDirectSound8_SetCooperativeLevel(ds8, hwnd, level);
212

213
    hr = IDirectSound8_CreateSoundBuffer(ds8, bufdesc, (IDirectSoundBuffer**)dsb8, NULL);
214
    if (hr != DS_OK) {
215
        WARN("IDirectSoundBuffer_Create() failed\n");
216
        goto error;
217
    }
218

219 220 221 222 223 224
    hr = IDirectSoundCaptureImpl_Create(&This->IUnknown_iface, &IID_IUnknown,
            (void**)&This->dsc8_unk, TRUE);
    if (SUCCEEDED(hr)) {
        IUnknown_QueryInterface(This->dsc8_unk, &IID_IDirectSoundCapture8, (void**)&dsc8);
        hr = IDirectSoundCapture_Initialize(dsc8, capture_dev);
    }
225
    if (hr != DS_OK) {
226
        WARN("Creating/initializing IDirectSoundCapture8 failed\n");
227
        goto error;
228 229
    }

230
    hr = IDirectSoundCapture_CreateCaptureBuffer(dsc8, cbufdesc,
231
            (IDirectSoundCaptureBuffer**)dscb8, NULL);
232
    if (hr != DS_OK) {
233
        WARN("IDirectSoundCapture_CreateCaptureBuffer() failed\n");
234
        goto error;
235 236
    }

237
    IDirectSound8_Release(ds8);
238
    IDirectSoundCapture_Release(dsc8);
239 240 241 242 243 244 245
    return DS_OK;

error:
    if (*dsb8) {
        IDirectSoundBuffer8_Release(*dsb8);
        *dsb8 = NULL;
    }
246 247 248 249 250
    if (ds8)
        IDirectSound8_Release(ds8);
    if (This->ds8_unk) {
        IUnknown_Release(This->ds8_unk);
        This->ds8_unk = NULL;
251 252 253 254 255
    }
    if (*dscb8) {
        IDirectSoundCaptureBuffer8_Release(*dscb8);
        *dscb8 = NULL;
    }
256 257 258 259 260
    if (dsc8)
        IDirectSoundCapture_Release(dsc8);
    if (This->dsc8_unk) {
        IUnknown_Release(This->dsc8_unk);
        This->dsc8_unk = NULL;
261
    }
262
    return hr;
263 264
}

265
static const IDirectSoundFullDuplexVtbl dsfd_vtbl =
266 267 268 269 270 271 272 273 274
{
    /* IUnknown methods */
    IDirectSoundFullDuplexImpl_QueryInterface,
    IDirectSoundFullDuplexImpl_AddRef,
    IDirectSoundFullDuplexImpl_Release,

    /* IDirectSoundFullDuplex methods */
    IDirectSoundFullDuplexImpl_Initialize
};
275

276
HRESULT DSOUND_FullDuplexCreate(REFIID riid, void **ppv)
277
{
278 279
    IDirectSoundFullDuplexImpl *obj;
    HRESULT hr;
280

281
    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
282

283 284 285
    *ppv = NULL;
    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj));
    if (!obj) {
286 287 288 289
        WARN("out of memory\n");
        return DSERR_OUTOFMEMORY;
    }

290 291
    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;
297

298 299
    hr = IUnknown_QueryInterface(&obj->IUnknown_iface, riid, ppv);
    IUnknown_Release(&obj->IUnknown_iface);
300

301
    return hr;
302 303
}

304 305 306 307 308 309
/***************************************************************************
 * DirectSoundFullDuplexCreate [DSOUND.10]
 *
 * Create and initialize a DirectSoundFullDuplex interface.
 *
 * PARAMS
310 311 312 313 314 315 316 317 318 319
 *    capture_dev         [I] Address of sound capture device GUID.
 *    render_dev          [I] Address of sound render device GUID.
 *    cbufdesc            [I] Address of capture buffer description.
 *    bufdesc             [I] Address of  render buffer description.
 *    hwnd                [I] Handle to application window.
 *    level               [I] Cooperative level.
 *    dsfd                [O] Address where full duplex interface returned.
 *    dscb8               [0] Address where capture buffer interface returned.
 *    dsb8                [0] Address where render buffer interface returned.
 *    outer_unk           [I] Must be NULL.
320 321 322 323 324 325
 *
 * RETURNS
 *    Success: DS_OK
 *    Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM,
 *             DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER
 */
326 327 328 329 330 331
HRESULT WINAPI DirectSoundFullDuplexCreate(const GUID *capture_dev, const GUID *render_dev,
        const DSCBUFFERDESC *cbufdesc, const DSBUFFERDESC *bufdesc, HWND hwnd, DWORD level,
        IDirectSoundFullDuplex **dsfd, IDirectSoundCaptureBuffer8 **dscb8,
        IDirectSoundBuffer8 **dsb8, IUnknown *outer_unk)
{
    HRESULT hr;
332

333
    TRACE("(%s,%s,%p,%p,%p,%lx,%p,%p,%p,%p)\n", debugstr_guid(capture_dev),
334 335
            debugstr_guid(render_dev), cbufdesc, bufdesc, hwnd, level, dsfd, dscb8, dsb8,
            outer_unk);
336

337
    if (!dsfd)
338
        return DSERR_INVALIDPARAM;
339 340 341
    if (outer_unk) {
        *dsfd = NULL;
        return DSERR_NOAGGREGATION;
342
    }
343

344 345 346 347 348 349 350 351 352
    hr = DSOUND_FullDuplexCreate(&IID_IDirectSoundFullDuplex, (void**)dsfd);
    if (hr == DS_OK) {
        hr = IDirectSoundFullDuplex_Initialize(*dsfd, capture_dev, render_dev, cbufdesc, bufdesc,
                hwnd, level, dscb8, dsb8);
        if (hr != DS_OK) {
            IDirectSoundFullDuplex_Release(*dsfd);
            *dsfd = NULL;
            WARN("IDirectSoundFullDuplexImpl_Initialize failed\n");
        }
353 354
    }

355
    return hr;
356
}