buffer.c 38.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*  			DirectSound
 *
 * Copyright 1998 Marcus Meissner
 * Copyright 1998 Rob Riggs
 * Copyright 2000-2002 TransGaming Technologies, Inc.
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22
#include <stdarg.h>
23

24 25
#define COBJMACROS

26 27
#include "windef.h"
#include "winbase.h"
28
#include "winuser.h"
29
#include "mmsystem.h"
30
#include "winternl.h"
31
#include "vfwmsgs.h"
32 33 34
#include "wine/debug.h"
#include "dsound.h"
#include "dsound_private.h"
35
#include "dsconf.h"
36 37 38 39 40 41

WINE_DEFAULT_DEBUG_CHANNEL(dsound);

/*******************************************************************************
 *		IDirectSoundNotify
 */
42

43
static inline struct IDirectSoundBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
44
{
45 46
    return CONTAINING_RECORD(iface, struct IDirectSoundBufferImpl, IDirectSoundNotify_iface);
}
47

48 49 50 51
static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
        void **ppobj)
{
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
52

53
    TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
54

55
    return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
56 57
}

58
static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
59
{
60 61 62
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
    ULONG ref = InterlockedIncrement(&This->refn);

63
    TRACE("(%p) ref was %d\n", This, ref - 1);
64 65 66 67

    if(ref == 1)
        InterlockedIncrement(&This->numIfaces);

68
    return ref;
69 70
}

71
static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
72
{
73 74 75
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
    ULONG ref = InterlockedDecrement(&This->refn);

76
    TRACE("(%p) ref was %d\n", This, ref + 1);
77

78 79 80
    if (!ref && !InterlockedDecrement(&This->numIfaces))
        secondarybuffer_destroy(This);

81
    return ref;
82 83
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
static int notify_compar(const void *l, const void *r)
{
    const DSBPOSITIONNOTIFY *left = l;
    const DSBPOSITIONNOTIFY *right = r;

    /* place DSBPN_OFFSETSTOP at the start of the sorted array */
    if(left->dwOffset == DSBPN_OFFSETSTOP){
        if(right->dwOffset != DSBPN_OFFSETSTOP)
            return -1;
    }else if(right->dwOffset == DSBPN_OFFSETSTOP)
        return 1;

    if(left->dwOffset == right->dwOffset)
        return 0;

    if(left->dwOffset < right->dwOffset)
        return -1;

    return 1;
}

105 106 107 108 109
static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
        DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);

110
	TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
111

112
        if (howmuch > 0 && notify == NULL) {
113
	    WARN("invalid parameter: notify == NULL\n");
114 115
	    return DSERR_INVALIDPARAM;
	}
116 117

	if (TRACE_ON(dsound)) {
118
	    unsigned int	i;
119
	    for (i=0;i<howmuch;i++)
120
		TRACE("notify at %d to %p\n",
121
		    notify[i].dwOffset,notify[i].hEventNotify);
122 123
	}

124
	if (howmuch > 0) {
125 126
	    /* Make an internal copy of the caller-supplied array.
	     * Replace the existing copy if one is already present. */
127 128
            HeapFree(GetProcessHeap(), 0, This->notifies);
            This->notifies = HeapAlloc(GetProcessHeap(), 0,
129 130
			howmuch * sizeof(DSBPOSITIONNOTIFY));

131
            if (This->notifies == NULL) {
132 133 134
		    WARN("out of memory\n");
		    return DSERR_OUTOFMEMORY;
	    }
135 136
            CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
            This->nrofnotifies = howmuch;
137
            qsort(This->notifies, howmuch, sizeof(DSBPOSITIONNOTIFY), notify_compar);
138
	} else {
139 140 141
           HeapFree(GetProcessHeap(), 0, This->notifies);
           This->notifies = NULL;
           This->nrofnotifies = 0;
142
	}
143 144 145 146

	return S_OK;
}

147
static const IDirectSoundNotifyVtbl dsnvt =
148
{
149 150 151 152
    IDirectSoundNotifyImpl_QueryInterface,
    IDirectSoundNotifyImpl_AddRef,
    IDirectSoundNotifyImpl_Release,
    IDirectSoundNotifyImpl_SetNotificationPositions,
153 154 155 156 157 158
};

/*******************************************************************************
 *		IDirectSoundBuffer
 */

159 160 161 162 163
static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
{
    return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
}

164 165
static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
{
166
    return (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) != 0;
167 168
}

169 170 171
static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
        LPCWAVEFORMATEX wfex)
{
172 173 174
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

    TRACE("(%p,%p)\n", iface, wfex);
175

176 177 178 179 180 181
    if (is_primary_buffer(This))
        return primarybuffer_SetFormat(This->device, wfex);
    else {
        WARN("not available for secondary buffers.\n");
        return DSERR_INVALIDCALL;
    }
182 183
}

184 185 186
static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
187
	LONG oldVol;
188

189
	HRESULT hres = DS_OK;
190

191
	TRACE("(%p,%d)\n",This,vol);
192

193
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
194
		WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
195
		return DSERR_CONTROLUNAVAIL;
196
	}
197

198
	if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
199
		WARN("invalid parameter: vol = %d\n", vol);
200
		return DSERR_INVALIDPARAM;
201
	}
202 203

	/* **** */
204
	RtlAcquireResourceExclusive(&This->lock, TRUE);
205 206

	if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
207 208
		oldVol = This->ds3db_lVolume;
		This->ds3db_lVolume = vol;
209 210 211
		if (vol != oldVol)
			/* recalc 3d volume, which in turn recalcs the pans */
			DSOUND_Calc3DBuffer(This);
212 213 214
	} else {
		oldVol = This->volpan.lVolume;
		This->volpan.lVolume = vol;
215
		if (vol != oldVol)
216
			DSOUND_RecalcVolPan(&(This->volpan));
217 218
	}

219
	RtlReleaseResource(&This->lock);
220 221
	/* **** */

222
	return hres;
223 224
}

225 226 227 228
static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

229 230
	TRACE("(%p,%p)\n",This,vol);

231 232 233 234 235
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

236 237
	if (vol == NULL) {
		WARN("invalid parameter: vol == NULL\n");
238
		return DSERR_INVALIDPARAM;
239
	}
240

241 242
	*vol = This->volpan.lVolume;

243 244 245
	return DS_OK;
}

246 247 248
static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
249 250
	DWORD oldFreq;

251
	TRACE("(%p,%d)\n",This,freq);
252

253 254 255 256 257
        if (is_primary_buffer(This)) {
                WARN("not available for primary buffers.\n");
                return DSERR_CONTROLUNAVAIL;
        }

258 259
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
		WARN("control unavailable\n");
260
		return DSERR_CONTROLUNAVAIL;
261
	}
262 263

	if (freq == DSBFREQUENCY_ORIGINAL)
264
		freq = This->pwfx->nSamplesPerSec;
265

266
	if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
267
		WARN("invalid parameter: freq = %d\n", freq);
268
		return DSERR_INVALIDPARAM;
269
	}
270 271

	/* **** */
272
	RtlAcquireResourceExclusive(&This->lock, TRUE);
273 274 275 276

	oldFreq = This->freq;
	This->freq = freq;
	if (freq != oldFreq) {
277 278
		This->freqAdjustNum = This->freq;
		This->freqAdjustDen = This->device->pwfx->nSamplesPerSec;
279
		This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
280 281 282
		DSOUND_RecalcFormat(This);
	}

283
	RtlReleaseResource(&This->lock);
284 285 286 287 288
	/* **** */

	return DS_OK;
}

289 290 291 292
static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
        DWORD reserved2, DWORD flags)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
293
	HRESULT hres = DS_OK;
294
	int i;
295

296
	TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
297 298

	/* **** */
299
	RtlAcquireResourceExclusive(&This->lock, TRUE);
300 301

	This->playflags = flags;
302
	if (This->state == STATE_STOPPED) {
303 304 305 306 307
		This->leadin = TRUE;
		This->state = STATE_STARTING;
	} else if (This->state == STATE_STOPPING)
		This->state = STATE_PLAYING;

308 309 310 311
	for (i = 0; i < This->num_filters; i++) {
		IMediaObject_Discontinuity(This->filters[i].obj, 0);
	}

312
	RtlReleaseResource(&This->lock);
313 314
	/* **** */

315
	return hres;
316 317
}

318
static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
319
{
320
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
321
	HRESULT hres = DS_OK;
322

323 324 325
	TRACE("(%p)\n",This);

	/* **** */
326
	RtlAcquireResourceExclusive(&This->lock, TRUE);
327 328 329 330

	if (This->state == STATE_PLAYING)
		This->state = STATE_STOPPING;
	else if (This->state == STATE_STARTING)
331
	{
332
		This->state = STATE_STOPPED;
333 334
		DSOUND_CheckEvent(This, 0, 0);
	}
335

336
	RtlReleaseResource(&This->lock);
337 338
	/* **** */

339
	return hres;
340 341
}

342
static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
343
{
344 345 346
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
    ULONG ref = InterlockedIncrement(&This->ref);

347
    TRACE("(%p) ref was %d\n", This, ref - 1);
348 349 350 351

    if(ref == 1)
        InterlockedIncrement(&This->numIfaces);

352
    return ref;
353
}
354

355
static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
356
{
357
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
358 359 360 361 362 363 364 365 366
    ULONG ref;

    if (is_primary_buffer(This)){
        ref = capped_refcount_dec(&This->ref);
        if(!ref)
            capped_refcount_dec(&This->numIfaces);
        TRACE("(%p) ref is now: %d\n", This, ref);
        return ref;
    }
367

368 369
    ref = InterlockedDecrement(&This->ref);
    if (!ref && !InterlockedDecrement(&This->numIfaces))
370
            secondarybuffer_destroy(This);
371 372 373

    TRACE("(%p) ref is now %d\n", This, ref);

374
    return ref;
375 376
}

377 378 379 380
static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
        DWORD *playpos, DWORD *writepos)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
381
	DWORD pos;
382

383
	TRACE("(%p,%p,%p)\n",This,playpos,writepos);
384 385 386

	RtlAcquireResourceShared(&This->lock, TRUE);

387
	pos = This->sec_mixpos;
388

389 390 391 392
	/* sanity */
	if (pos >= This->buflen){
		FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
		pos %= This->buflen;
393
	}
394 395 396 397 398 399 400

	if (playpos)
		*playpos = pos;
	if (writepos)
		*writepos = pos;

	if (writepos && This->state != STATE_STOPPED) {
401 402
		/* apply the documented 10ms lead to writepos */
		*writepos += This->writelead;
403
		*writepos %= This->buflen;
404
	}
405

406
	RtlReleaseResource(&This->lock);
407 408

	TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
409
		playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
410

411 412 413
	return DS_OK;
}

414 415 416 417
static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

418
	TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
419

420 421
	if (status == NULL) {
		WARN("invalid parameter: status = NULL\n");
422
		return DSERR_INVALIDPARAM;
423
	}
424 425

	*status = 0;
426
	RtlAcquireResourceShared(&This->lock, TRUE);
427 428 429 430 431
	if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
		*status |= DSBSTATUS_PLAYING;
		if (This->playflags & DSBPLAY_LOOPING)
			*status |= DSBSTATUS_LOOPING;
	}
432
	RtlReleaseResource(&This->lock);
433

434
	TRACE("status=%x\n", *status);
435 436 437 438
	return DS_OK;
}


439 440
static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
        LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
441
{
442
    IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
443
    DWORD size;
444

445
    TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
446

447
    size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
448

449 450
    if (lpwf) { /* NULL is valid */
        if (wfsize >= size) {
451
            CopyMemory(lpwf,This->pwfx,size);
452 453 454
            if (wfwritten)
                *wfwritten = size;
        } else {
455
            WARN("invalid parameter: wfsize too small\n");
456
            CopyMemory(lpwf,This->pwfx,wfsize);
457
            if (wfwritten)
458
                *wfwritten = wfsize;
459 460 461 462 463 464 465 466 467 468 469 470
            return DSERR_INVALIDPARAM;
        }
    } else {
        if (wfwritten)
            *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
        else {
            WARN("invalid parameter: wfwritten == NULL\n");
            return DSERR_INVALIDPARAM;
        }
    }

    return DS_OK;
471 472
}

473 474 475 476 477
static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
        DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
        DWORD *audiobytes2, DWORD flags)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
478
	HRESULT hres = DS_OK;
479 480 481

        TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
                audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
482

483 484 485
        if (!audiobytes1)
            return DSERR_INVALIDPARAM;

486
        /* when this flag is set, writecursor is meaningless and must be calculated */
487 488
	if (flags & DSBLOCK_FROMWRITECURSOR) {
		/* GetCurrentPosition does too much magic to duplicate here */
489
		hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
490 491 492 493
		if (hres != DS_OK) {
			WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
			return hres;
		}
494
	}
495 496

        /* when this flag is set, writebytes is meaningless and must be set */
497 498
	if (flags & DSBLOCK_ENTIREBUFFER)
		writebytes = This->buflen;
499 500

	if (writecursor >= This->buflen) {
501
		WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
502 503 504 505 506
		     writecursor, This->buflen);
		return DSERR_INVALIDPARAM;
        }

	if (writebytes > This->buflen) {
507
		WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
508 509 510
		     writebytes, This->buflen);
		return DSERR_INVALIDPARAM;
        }
511

512
	/* **** */
513
	RtlAcquireResourceShared(&This->lock, TRUE);
514

515 516 517 518 519 520 521 522 523 524 525 526
	if (writecursor+writebytes <= This->buflen) {
		*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
		if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
			WARN("Overwriting mixing position, case 1\n");
		*audiobytes1 = writebytes;
		if (lplpaudioptr2)
			*(LPBYTE*)lplpaudioptr2 = NULL;
		if (audiobytes2)
			*audiobytes2 = 0;
		TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
		  *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
		TRACE("->%d.0\n",writebytes);
527
		This->buffer->lockedbytes += writebytes;
528
	} else {
529 530 531
		DWORD remainder = writebytes + writecursor - This->buflen;
		*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
		*audiobytes1 = This->buflen-writecursor;
532
		This->buffer->lockedbytes += *audiobytes1;
533 534 535 536
		if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
			WARN("Overwriting mixing position, case 2\n");
		if (lplpaudioptr2)
			*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
537
		if (audiobytes2) {
538
			*audiobytes2 = writebytes-(This->buflen-writecursor);
539 540
			This->buffer->lockedbytes += *audiobytes2;
		}
541 542 543
		if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
			WARN("Overwriting mixing position, case 3\n");
		TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
544
	}
545

546
	RtlReleaseResource(&This->lock);
547
	/* **** */
548

549 550 551
	return DS_OK;
}

552 553 554 555
static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
        DWORD newpos)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
556
	HRESULT hres = DS_OK;
557

558
	TRACE("(%p,%d)\n",This,newpos);
559 560

	/* **** */
561
	RtlAcquireResourceExclusive(&This->lock, TRUE);
562

563
	/* start mixing from this new location instead */
564
	newpos %= This->buflen;
565
	newpos -= newpos%This->pwfx->nBlockAlign;
566
	This->sec_mixpos = newpos;
567 568

	/* at this point, do not attempt to reset buffers, mess with primary mix position,
569
           or anything like that to reduce latency. The data already prebuffered cannot be changed */
570

571
	RtlReleaseResource(&This->lock);
572 573
	/* **** */

574
	return hres;
575 576
}

577 578 579
static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
580
	HRESULT hres = DS_OK;
581

582
	TRACE("(%p,%d)\n",This,pan);
583

584
	if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
585
		WARN("invalid parameter: pan = %d\n", pan);
586
		return DSERR_INVALIDPARAM;
587
	}
588 589 590

	/* You cannot use both pan and 3D controls */
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
591 592
	    (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
		WARN("control unavailable\n");
593
		return DSERR_CONTROLUNAVAIL;
594
	}
595 596

	/* **** */
597
	RtlAcquireResourceExclusive(&This->lock, TRUE);
598

599 600
	if (This->volpan.lPan != pan) {
		This->volpan.lPan = pan;
601 602 603
		DSOUND_RecalcVolPan(&(This->volpan));
	}

604
	RtlReleaseResource(&This->lock);
605 606
	/* **** */

607
	return hres;
608 609
}

610 611 612 613
static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

614 615
	TRACE("(%p,%p)\n",This,pan);

616 617 618 619 620
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

621 622
	if (pan == NULL) {
		WARN("invalid parameter: pan = NULL\n");
623
		return DSERR_INVALIDPARAM;
624
	}
625 626 627 628 629 630

	*pan = This->volpan.lPan;

	return DS_OK;
}

631 632 633 634
static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
        void *p2, DWORD x2)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
635
	HRESULT hres = DS_OK;
636

637
	TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
638

639 640 641
	if (!p2)
		x2 = 0;

Andrew Talbot's avatar
Andrew Talbot committed
642 643 644
	if((p1 && ((BYTE*)p1 < This->buffer->memory || (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
	   (p2 && ((BYTE*)p2 < This->buffer->memory || (BYTE*)p2 >= This->buffer->memory + This->buflen)))
		return DSERR_INVALIDPARAM;
645

646
	if (x1 || x2)
647 648 649 650 651 652
	{
		RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
		LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
		{
			RtlAcquireResourceShared(&iter->lock, TRUE);
			if (x1)
653 654 655
                        {
			    if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
			      hres = DSERR_INVALIDPARAM;
656 657
			    else
			      iter->buffer->lockedbytes -= x1;
658
                        }
659 660 661 662 663 664 665 666

			if (x2)
			{
			    if(x2 + (DWORD_PTR)p2 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
			      hres = DSERR_INVALIDPARAM;
			    else
			      iter->buffer->lockedbytes -= x2;
			}
667 668 669 670 671
			RtlReleaseResource(&iter->lock);
		}
		RtlReleaseResource(&This->device->buffer_list_lock);
	}

672
	return hres;
673 674
}

675 676 677 678
static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

679 680 681 682
	FIXME("(%p):stub\n",This);
	return DS_OK;
}

683 684 685 686
static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

687 688
	TRACE("(%p,%p)\n",This,freq);

689 690
	if (freq == NULL) {
		WARN("invalid parameter: freq = NULL\n");
691
		return DSERR_INVALIDPARAM;
692
	}
693 694

	*freq = This->freq;
695
	TRACE("-> %d\n", *freq);
696 697 698 699

	return DS_OK;
}

700 701 702 703
static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
        LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
704
	DWORD u;
705 706 707 708
	DSFilter *filters;
	HRESULT hr, hr2;
	DMO_MEDIA_TYPE dmt;
	WAVEFORMATEX wfx;
709

710
	TRACE("(%p,%u,%p,%p)\n", This, dwEffectsCount, pDSFXDesc, pdwResultCodes);
711 712 713 714

	if (pdwResultCodes)
		for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;

715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
	if ((dwEffectsCount > 0 && !pDSFXDesc) ||
		(dwEffectsCount == 0 && (pDSFXDesc || pdwResultCodes))
	)
		return E_INVALIDARG;

	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFX)) {
		WARN("attempted to call SetFX on buffer without DSBCAPS_CTRLFX\n");
		return DSERR_CONTROLUNAVAIL;
	}

	if (This->state != STATE_STOPPED)
		return DSERR_INVALIDCALL;

	if (This->buffer->lockedbytes > 0)
		return DSERR_INVALIDCALL;

	if (dwEffectsCount == 0) {
		if (This->num_filters > 0) {
			for (u = 0; u < This->num_filters; u++) {
				IMediaObject_Release(This->filters[u].obj);
			}
			HeapFree(GetProcessHeap(), 0, This->filters);

			This->filters = NULL;
			This->num_filters = 0;
		}

		return DS_OK;
	}

	filters = HeapAlloc(GetProcessHeap(), 0, dwEffectsCount * sizeof(DSFilter));
	if (!filters) {
		WARN("out of memory\n");
		return DSERR_OUTOFMEMORY;
	}

	hr = DS_OK;

	wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
	wfx.nChannels = This->pwfx->nChannels;
	wfx.nSamplesPerSec = This->pwfx->nSamplesPerSec;
	wfx.wBitsPerSample = sizeof(float) * 8;
	wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample)/8;
	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
	wfx.cbSize = sizeof(wfx);

	dmt.majortype = KSDATAFORMAT_TYPE_AUDIO;
	dmt.subtype = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
	dmt.bFixedSizeSamples = TRUE;
	dmt.bTemporalCompression = FALSE;
	dmt.lSampleSize = sizeof(float) * This->pwfx->nChannels / 8;
	dmt.formattype = FORMAT_WaveFormatEx;
	dmt.pUnk = NULL;
	dmt.cbFormat = sizeof(WAVEFORMATEX);
	dmt.pbFormat = (BYTE*)&wfx;

	for (u = 0; u < dwEffectsCount; u++) {
		hr2 = CoCreateInstance(&pDSFXDesc[u].guidDSFXClass, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (LPVOID*)&filters[u].obj);

		if (SUCCEEDED(hr2)) {
			hr2 = IMediaObject_SetInputType(filters[u].obj, 0, &dmt, 0);
			if (FAILED(hr2))
				WARN("Could not set DMO input type\n");
		}

		if (SUCCEEDED(hr2)) {
			hr2 = IMediaObject_SetOutputType(filters[u].obj, 0, &dmt, 0);
			if (FAILED(hr2))
				WARN("Could not set DMO output type\n");
		}

		if (FAILED(hr2)) {
			if (hr == DS_OK)
				hr = hr2;

			if (pdwResultCodes)
				pdwResultCodes[u] = (hr2 == REGDB_E_CLASSNOTREG) ? DSFXR_UNKNOWN : DSFXR_FAILED;
		} else {
			if (pdwResultCodes)
				pdwResultCodes[u] = DSFXR_LOCSOFTWARE;
		}
	}

	if (FAILED(hr)) {
		for (u = 0; u < dwEffectsCount; u++) {
			if (pdwResultCodes)
				pdwResultCodes[u] = (pdwResultCodes[u] != DSFXR_UNKNOWN) ? DSFXR_PRESENT : DSFXR_UNKNOWN;

			if (filters[u].obj)
				IMediaObject_Release(filters[u].obj);
		}

		HeapFree(GetProcessHeap(), 0, filters);
	} else {
		if (This->num_filters > 0) {
			for (u = 0; u < This->num_filters; u++) {
				IMediaObject_Release(This->filters[u].obj);
				if (This->filters[u].inplace) IMediaObjectInPlace_Release(This->filters[u].inplace);
			}
			HeapFree(GetProcessHeap(), 0, This->filters);
		}

		for (u = 0; u < dwEffectsCount; u++) {
			memcpy(&filters[u].guid, &pDSFXDesc[u].guidDSFXClass, sizeof(GUID));
			if (FAILED(IMediaObject_QueryInterface(filters[u].obj, &IID_IMediaObjectInPlace, (void*)&filters[u].inplace)))
				filters[u].inplace = NULL;
		}

		This->filters = filters;
		This->num_filters = dwEffectsCount;
	}

	return hr;
828 829
}

830 831 832 833
static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
        DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
834 835
	DWORD u;

836
	FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
837 838 839 840

	if (pdwResultCodes)
		for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;

841
	WARN("control unavailable\n");
842
	return DS_OK;
843 844
}

845 846 847 848
static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
        REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
849

850
	TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
851

852
	if (dwIndex >= This->num_filters)
853
		return DSERR_CONTROLUNAVAIL;
854 855 856 857 858 859 860 861 862 863 864 865 866

	if (!ppObject)
		return E_INVALIDARG;

	if (IsEqualGUID(rguidObject, &This->filters[dwIndex].guid) || IsEqualGUID(rguidObject, &GUID_All_Objects)) {
		if (SUCCEEDED(IMediaObject_QueryInterface(This->filters[dwIndex].obj, rguidInterface, ppObject)))
			return DS_OK;
		else
			return E_NOINTERFACE;
	} else {
		WARN("control unavailable\n");
		return DSERR_OBJECTNOTFOUND;
	}
867 868
}

869 870 871 872 873
static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
        IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

874
	WARN("(%p) already initialized\n", This);
875 876 877
	return DSERR_ALREADYINITIALIZED;
}

878 879 880 881
static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);

882 883
  	TRACE("(%p)->(%p)\n",This,caps);

884 885
	if (caps == NULL) {
		WARN("invalid parameter: caps == NULL\n");
886
		return DSERR_INVALIDPARAM;
887 888 889
	}

	if (caps->dwSize < sizeof(*caps)) {
890
		WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
891 892
		return DSERR_INVALIDPARAM;
	}
893 894

	caps->dwFlags = This->dsbd.dwFlags;
895
	caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
896 897 898

	caps->dwBufferBytes = This->buflen;

899 900
	/* According to windows, this is zero*/
	caps->dwUnlockTransferRate = 0;
901 902 903 904 905
	caps->dwPlayCpuOverhead = 0;

	return DS_OK;
}

906 907 908 909
static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
        void **ppobj)
{
        IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
910 911 912

	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);

913 914 915 916 917
	if (ppobj == NULL) {
		WARN("invalid parameter\n");
		return E_INVALIDARG;
	}

918 919
	*ppobj = NULL;	/* assume failure */

920 921
	if ( IsEqualGUID(riid, &IID_IUnknown) ||
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
922
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
923 924 925
                IDirectSoundBuffer8_AddRef(iface);
                *ppobj = iface;
                return S_OK;
926 927
	}

928
	if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
929 930 931
                IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
                *ppobj = &This->IDirectSoundNotify_iface;
                return S_OK;
932 933 934
	}

	if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
935
            if(This->dsbd.dwFlags & DSBCAPS_CTRL3D){
936 937 938
                IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
                *ppobj = &This->IDirectSound3DBuffer_iface;
                return S_OK;
939 940 941
            }
            TRACE("app requested IDirectSound3DBuffer on non-3D secondary buffer\n");
            return E_NOINTERFACE;
942 943
	}

944
	if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
945
		ERR("app requested IDirectSound3DListener on secondary buffer\n");
946
		return E_NOINTERFACE;
947 948 949
	}

	if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
950 951 952
                IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
                *ppobj = &This->IKsPropertySet_iface;
                return S_OK;
953 954
	}

955 956 957 958 959
	FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );

	return E_NOINTERFACE;
}

960
static const IDirectSoundBuffer8Vtbl dsbvt =
961 962 963 964 965 966 967 968 969
{
	IDirectSoundBufferImpl_QueryInterface,
	IDirectSoundBufferImpl_AddRef,
	IDirectSoundBufferImpl_Release,
	IDirectSoundBufferImpl_GetCaps,
	IDirectSoundBufferImpl_GetCurrentPosition,
	IDirectSoundBufferImpl_GetFormat,
	IDirectSoundBufferImpl_GetVolume,
	IDirectSoundBufferImpl_GetPan,
970
	IDirectSoundBufferImpl_GetFrequency,
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
	IDirectSoundBufferImpl_GetStatus,
	IDirectSoundBufferImpl_Initialize,
	IDirectSoundBufferImpl_Lock,
	IDirectSoundBufferImpl_Play,
	IDirectSoundBufferImpl_SetCurrentPosition,
	IDirectSoundBufferImpl_SetFormat,
	IDirectSoundBufferImpl_SetVolume,
	IDirectSoundBufferImpl_SetPan,
	IDirectSoundBufferImpl_SetFrequency,
	IDirectSoundBufferImpl_Stop,
	IDirectSoundBufferImpl_Unlock,
	IDirectSoundBufferImpl_Restore,
	IDirectSoundBufferImpl_SetFX,
	IDirectSoundBufferImpl_AcquireResources,
	IDirectSoundBufferImpl_GetObjectInPath
};

988
HRESULT IDirectSoundBufferImpl_Create(
Robert Reif's avatar
Robert Reif committed
989
	DirectSoundDevice * device,
990
	IDirectSoundBufferImpl **pdsb,
991
	LPCDSBUFFERDESC dsbd)
992 993 994 995 996
{
	IDirectSoundBufferImpl *dsb;
	LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
	HRESULT err = DS_OK;
	DWORD capf = 0;
Robert Reif's avatar
Robert Reif committed
997
	TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
998 999

	if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1000
		WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
1001
		*pdsb = NULL;
1002 1003 1004
		return DSERR_INVALIDPARAM; /* FIXME: which error? */
	}

1005
	dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1006 1007 1008 1009 1010 1011

	if (dsb == 0) {
		WARN("out of memory\n");
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}
1012 1013 1014

	TRACE("Created buffer at %p\n", dsb);

1015
	dsb->ref = 0;
1016
        dsb->refn = 0;
1017
        dsb->ref3D = 0;
1018
        dsb->refiks = 0;
1019
	dsb->numIfaces = 0;
Robert Reif's avatar
Robert Reif committed
1020
	dsb->device = device;
1021
	dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
1022
        dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
1023
        dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
1024
        dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
1025

1026
	/* size depends on version */
1027
	CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1028

1029
	dsb->pwfx = DSOUND_CopyFormat(wfex);
1030 1031 1032 1033 1034 1035
	if (dsb->pwfx == NULL) {
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}

1036 1037 1038 1039 1040 1041
	if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
		dsb->buflen = dsbd->dwBufferBytes + 
			(dsbd->lpwfxFormat->nBlockAlign - 
			(dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
	else
		dsb->buflen = dsbd->dwBufferBytes;
1042

1043
	dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1044 1045 1046
	dsb->notifies = NULL;
	dsb->nrofnotifies = 0;

1047 1048 1049 1050 1051
	/* Check necessary hardware mixing capabilities */
	if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
	else capf |= DSCAPS_SECONDARYMONO;
	if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
	else capf |= DSCAPS_SECONDARY8BIT;
1052

1053
	TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
1054

1055 1056 1057 1058 1059 1060 1061 1062 1063
	/* Allocate an empty buffer */
	dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
	if (dsb->buffer == NULL) {
		WARN("out of memory\n");
		HeapFree(GetProcessHeap(),0,dsb->pwfx);
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}
1064

1065 1066 1067 1068 1069 1070 1071 1072 1073
	/* Allocate system memory for buffer */
	dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
	if (dsb->buffer->memory == NULL) {
		WARN("out of memory\n");
		HeapFree(GetProcessHeap(),0,dsb->pwfx);
		HeapFree(GetProcessHeap(),0,dsb->buffer);
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
1074 1075
	}

1076
	dsb->buffer->ref = 1;
1077
	dsb->buffer->lockedbytes = 0;
1078 1079 1080 1081
	list_init(&dsb->buffer->buffers);
	list_add_head(&dsb->buffer->buffers, &dsb->entry);
	FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);

1082 1083
	/* It's not necessary to initialize values to zero since */
	/* we allocated this structure with HEAP_ZERO_MEMORY... */
1084
	dsb->sec_mixpos = 0;
1085 1086
	dsb->state = STATE_STOPPED;

1087 1088
	dsb->freqAdjustNum = dsb->freq;
	dsb->freqAdjustDen = device->pwfx->nSamplesPerSec;
1089 1090 1091
	dsb->nAvgBytesPerSec = dsb->freq *
		dsbd->lpwfxFormat->nBlockAlign;

1092 1093 1094
	/* calculate fragment size and write lead */
	DSOUND_RecalcFormat(dsb);

1095 1096
	if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
		dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1097 1098 1099 1100 1101 1102
		dsb->ds3db_ds3db.vPosition.x = 0.0;
		dsb->ds3db_ds3db.vPosition.y = 0.0;
		dsb->ds3db_ds3db.vPosition.z = 0.0;
		dsb->ds3db_ds3db.vVelocity.x = 0.0;
		dsb->ds3db_ds3db.vVelocity.y = 0.0;
		dsb->ds3db_ds3db.vVelocity.z = 0.0;
1103 1104
		dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
		dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1105 1106 1107
		dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1108 1109 1110 1111 1112 1113 1114
		dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
		dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
		dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
		dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;

		dsb->ds3db_need_recalc = FALSE;
		DSOUND_Calc3DBuffer(dsb);
1115
	} else
1116 1117
		DSOUND_RecalcVolPan(&(dsb->volpan));

1118
	RtlInitializeResource(&dsb->lock);
1119

1120
	/* register buffer if not primary */
1121
	if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1122
		err = DirectSoundDevice_AddBuffer(device, dsb);
1123
		if (err != DS_OK) {
1124 1125
			HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
			HeapFree(GetProcessHeap(),0,dsb->buffer);
1126
			RtlDeleteResource(&dsb->lock);
1127
			HeapFree(GetProcessHeap(),0,dsb->pwfx);
1128
			HeapFree(GetProcessHeap(),0,dsb);
1129
			dsb = NULL;
1130 1131
		}
	}
1132

1133
        IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1134
	*pdsb = dsb;
1135
	return err;
1136
}
1137

1138 1139
void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
{
1140 1141 1142 1143 1144
    ULONG ref = InterlockedIncrement(&This->numIfaces);

    if (ref > 1)
        WARN("Destroying buffer with %u in use interfaces\n", ref - 1);

1145 1146 1147
    if (This->dsbd.dwFlags & DSBCAPS_LOCHARDWARE)
        This->device->drvcaps.dwFreeHwMixingAllBuffers++;

1148 1149 1150
    DirectSoundDevice_RemoveBuffer(This->device, This);
    RtlDeleteResource(&This->lock);

1151 1152 1153 1154 1155
    This->buffer->ref--;
    list_remove(&This->entry);
    if (This->buffer->ref == 0) {
        HeapFree(GetProcessHeap(), 0, This->buffer->memory);
        HeapFree(GetProcessHeap(), 0, This->buffer);
1156 1157 1158 1159
    }

    HeapFree(GetProcessHeap(), 0, This->notifies);
    HeapFree(GetProcessHeap(), 0, This->pwfx);
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169

    if (This->filters) {
        int i;
        for (i = 0; i < This->num_filters; i++) {
            IMediaObject_Release(This->filters[i].obj);
            if (This->filters[i].inplace) IMediaObjectInPlace_Release(This->filters[i].inplace);
        }
        HeapFree(GetProcessHeap(), 0, This->filters);
    }

1170 1171 1172 1173 1174
    HeapFree(GetProcessHeap(), 0, This);

    TRACE("(%p) released\n", This);
}

1175 1176 1177 1178 1179 1180 1181
HRESULT IDirectSoundBufferImpl_Duplicate(
    DirectSoundDevice *device,
    IDirectSoundBufferImpl **ppdsb,
    IDirectSoundBufferImpl *pdsb)
{
    IDirectSoundBufferImpl *dsb;
    HRESULT hres = DS_OK;
Akihiro Sagawa's avatar
Akihiro Sagawa committed
1182
    TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1183

1184
    dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1185 1186 1187 1188 1189
    if (dsb == NULL) {
        WARN("out of memory\n");
        *ppdsb = NULL;
        return DSERR_OUTOFMEMORY;
    }
1190 1191 1192

    RtlAcquireResourceShared(&pdsb->lock, TRUE);

1193
    CopyMemory(dsb, pdsb, sizeof(*dsb));
1194

1195
    dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1196 1197 1198

    RtlReleaseResource(&pdsb->lock);

1199 1200 1201 1202 1203
    if (dsb->pwfx == NULL) {
        HeapFree(GetProcessHeap(),0,dsb);
        *ppdsb = NULL;
        return DSERR_OUTOFMEMORY;
    }
1204

1205 1206
    dsb->buffer->ref++;
    list_add_head(&dsb->buffer->buffers, &dsb->entry);
1207
    dsb->ref = 0;
1208
    dsb->refn = 0;
1209
    dsb->ref3D = 0;
1210 1211
    dsb->refiks = 0;
    dsb->numIfaces = 0;
1212
    dsb->state = STATE_STOPPED;
1213
    dsb->sec_mixpos = 0;
1214 1215
    dsb->notifies = NULL;
    dsb->nrofnotifies = 0;
1216
    dsb->device = device;
1217
    DSOUND_RecalcFormat(dsb);
1218

1219
    RtlInitializeResource(&dsb->lock);
1220 1221 1222 1223

    /* register buffer */
    hres = DirectSoundDevice_AddBuffer(device, dsb);
    if (hres != DS_OK) {
1224
        RtlDeleteResource(&dsb->lock);
1225 1226
        list_remove(&dsb->entry);
        dsb->buffer->ref--;
1227 1228
        HeapFree(GetProcessHeap(),0,dsb->pwfx);
        HeapFree(GetProcessHeap(),0,dsb);
1229
        dsb = NULL;
1230 1231
    }

1232
    IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1233 1234 1235 1236
    *ppdsb = dsb;
    return hres;
}

1237
/*******************************************************************************
1238
 *              IKsPropertySet
1239 1240
 */

1241 1242 1243 1244 1245
static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
{
    return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
}

1246
/* IUnknown methods */
1247 1248
static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
        void **ppobj)
1249
{
1250 1251
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);

1252 1253
    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);

1254
    return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1255 1256
}

1257
static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1258
{
1259 1260 1261
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
    ULONG ref = InterlockedIncrement(&This->refiks);

1262
    TRACE("(%p) ref was %d\n", This, ref - 1);
1263 1264 1265 1266

    if(ref == 1)
        InterlockedIncrement(&This->numIfaces);

1267 1268 1269
    return ref;
}

1270
static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1271
{
1272
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1273 1274 1275 1276 1277 1278 1279 1280 1281
    ULONG ref;

    if (is_primary_buffer(This)){
        ref = capped_refcount_dec(&This->refiks);
        if(!ref)
            capped_refcount_dec(&This->numIfaces);
        TRACE("(%p) ref is now: %d\n", This, ref);
        return ref;
    }
1282

1283 1284 1285 1286 1287
    ref = InterlockedDecrement(&This->refiks);
    if (!ref && !InterlockedDecrement(&This->numIfaces))
        secondarybuffer_destroy(This);

    TRACE("(%p) ref is now %d\n", This, ref);
1288 1289 1290 1291

    return ref;
}

1292 1293 1294
static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
        ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
        ULONG cbPropData, ULONG *pcbReturned)
1295
{
1296
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1297

1298 1299 1300 1301 1302 1303
    TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
    This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);

    return E_PROP_ID_UNSUPPORTED;
}

1304 1305 1306
static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
        ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
        ULONG cbPropData)
1307
{
1308
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1309

1310
    TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1311 1312 1313 1314

    return E_PROP_ID_UNSUPPORTED;
}

1315 1316
static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
        ULONG dwPropID, ULONG *pTypeSupport)
1317
{
1318
    IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1319

1320
    TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1321 1322 1323 1324

    return E_PROP_ID_UNSUPPORTED;
}

1325
const IKsPropertySetVtbl iksbvt = {
1326 1327 1328 1329 1330 1331
    IKsPropertySetImpl_QueryInterface,
    IKsPropertySetImpl_AddRef,
    IKsPropertySetImpl_Release,
    IKsPropertySetImpl_Get,
    IKsPropertySetImpl_Set,
    IKsPropertySetImpl_QuerySupport
1332
};