buffer.c 49.6 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 NONAMELESSSTRUCT
#define NONAMELESSUNION
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 35
#include "wine/debug.h"
#include "dsound.h"
#include "dsdriver.h"
#include "dsound_private.h"
36
#include "dsconf.h"
37 38 39

WINE_DEFAULT_DEBUG_CHANNEL(dsound);

40 41
static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);

42 43 44
/*******************************************************************************
 *		IDirectSoundNotify
 */
45 46 47 48 49 50 51 52 53 54 55 56 57

struct IDirectSoundNotifyImpl
{
    /* IUnknown fields */
    const IDirectSoundNotifyVtbl *lpVtbl;
    LONG                        ref;
    IDirectSoundBufferImpl*     dsb;
};

static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
                                             IDirectSoundNotifyImpl **pdsn);
static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);

58 59 60
static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
	LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
) {
61
	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
62
	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
63

64
	if (This->dsb == NULL) {
65 66 67 68
		WARN("invalid parameter\n");
		return E_INVALIDARG;
	}

69
	return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
70 71
}

72 73
static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
{
74 75
    IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
    ULONG ref = InterlockedIncrement(&(This->ref));
76
    TRACE("(%p) ref was %d\n", This, ref - 1);
77
    return ref;
78 79
}

80 81 82 83
static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
{
    IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
    ULONG ref = InterlockedDecrement(&(This->ref));
84
    TRACE("(%p) ref was %d\n", This, ref + 1);
85 86 87

    if (!ref) {
        This->dsb->notify = NULL;
88
        IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
89 90 91 92
        HeapFree(GetProcessHeap(), 0, This);
        TRACE("(%p) released\n", This);
    }
    return ref;
93 94 95 96 97
}

static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
	LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
) {
98
	IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
99
	TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
100

101
        if (howmuch > 0 && notify == NULL) {
102
	    WARN("invalid parameter: notify == NULL\n");
103 104
	    return DSERR_INVALIDPARAM;
	}
105 106

	if (TRACE_ON(dsound)) {
107
	    unsigned int	i;
108
	    for (i=0;i<howmuch;i++)
109
		TRACE("notify at %d to %p\n",
110
		    notify[i].dwOffset,notify[i].hEventNotify);
111 112
	}

113
	if (This->dsb->hwnotify) {
114
	    HRESULT hres;
115
	    hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
116 117 118
	    if (hres != DS_OK)
		    WARN("IDsDriverNotify_SetNotificationPositions failed\n");
	    return hres;
119
        } else if (howmuch > 0) {
120 121
	    /* Make an internal copy of the caller-supplied array.
	     * Replace the existing copy if one is already present. */
122
	    HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
123
	    This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
124 125
			howmuch * sizeof(DSBPOSITIONNOTIFY));

126
	    if (This->dsb->notifies == NULL) {
127 128 129
		    WARN("out of memory\n");
		    return DSERR_OUTOFMEMORY;
	    }
130
	    CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
131
	    This->dsb->nrofnotifies = howmuch;
132
        } else {
133 134
           HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
           This->dsb->notifies = NULL;
135 136
           This->dsb->nrofnotifies = 0;
        }
137 138 139 140

	return S_OK;
}

141
static const IDirectSoundNotifyVtbl dsnvt =
142
{
143 144 145 146
    IDirectSoundNotifyImpl_QueryInterface,
    IDirectSoundNotifyImpl_AddRef,
    IDirectSoundNotifyImpl_Release,
    IDirectSoundNotifyImpl_SetNotificationPositions,
147 148
};

149
static HRESULT IDirectSoundNotifyImpl_Create(
150 151 152 153 154
    IDirectSoundBufferImpl * dsb,
    IDirectSoundNotifyImpl **pdsn)
{
    IDirectSoundNotifyImpl * dsn;
    TRACE("(%p,%p)\n",dsb,pdsn);
155

156
    dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn));
157

158 159 160 161 162 163 164 165 166 167
    if (dsn == NULL) {
        WARN("out of memory\n");
        return DSERR_OUTOFMEMORY;
    }

    dsn->ref = 0;
    dsn->lpVtbl = &dsnvt;
    dsn->dsb = dsb;
    dsb->notify = dsn;
    IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
168

169 170 171
    *pdsn = dsn;
    return DS_OK;
}
172

173
static HRESULT IDirectSoundNotifyImpl_Destroy(
174 175 176 177 178 179 180 181 182
    IDirectSoundNotifyImpl *pdsn)
{
    TRACE("(%p)\n",pdsn);

    while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);

    return DS_OK;
}

183 184 185 186 187
/*******************************************************************************
 *		IDirectSoundBuffer
 */

static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
188
	LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
189
) {
190
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
191 192 193

	TRACE("(%p,%p)\n",This,wfex);
	/* This method is not available on secondary buffers */
194
	WARN("invalid call\n");
195 196 197 198 199 200
	return DSERR_INVALIDCALL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LONG vol
) {
201
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
202
	LONG oldVol;
203
	HRESULT hres = DS_OK;
204

205
	TRACE("(%p,%d)\n",This,vol);
206

207
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
208
		WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
209
		return DSERR_CONTROLUNAVAIL;
210
	}
211

212
	if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
213
		WARN("invalid parameter: vol = %d\n", vol);
214
		return DSERR_INVALIDPARAM;
215
	}
216 217

	/* **** */
218
	RtlAcquireResourceExclusive(&This->lock, TRUE);
219 220

	if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
221 222
		oldVol = This->ds3db_lVolume;
		This->ds3db_lVolume = vol;
223 224 225
		if (vol != oldVol)
			/* recalc 3d volume, which in turn recalcs the pans */
			DSOUND_Calc3DBuffer(This);
226 227 228
	} else {
		oldVol = This->volpan.lVolume;
		This->volpan.lVolume = vol;
229
		if (vol != oldVol)
230
			DSOUND_RecalcVolPan(&(This->volpan));
231 232 233 234
	}

	if (vol != oldVol) {
		if (This->hwbuf) {
235 236 237
			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
	    		if (hres != DS_OK)
		    		WARN("IDsDriverBuffer_SetVolumePan failed\n");
238
		}
239 240
	}

241
	RtlReleaseResource(&This->lock);
242 243
	/* **** */

244
	return hres;
245 246 247 248 249
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
) {
250
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
251 252
	TRACE("(%p,%p)\n",This,vol);

253 254 255 256 257
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

258 259
	if (vol == NULL) {
		WARN("invalid parameter: vol == NULL\n");
260
		return DSERR_INVALIDPARAM;
261
	}
262

263 264
	*vol = This->volpan.lVolume;

265 266 267 268 269 270
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,DWORD freq
) {
271
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
272 273
	DWORD oldFreq;

274
	TRACE("(%p,%d)\n",This,freq);
275

276 277
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
		WARN("control unavailable\n");
278
		return DSERR_CONTROLUNAVAIL;
279
	}
280 281

	if (freq == DSBFREQUENCY_ORIGINAL)
282
		freq = This->pwfx->nSamplesPerSec;
283

284
	if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
285
		WARN("invalid parameter: freq = %d\n", freq);
286
		return DSERR_INVALIDPARAM;
287
	}
288 289

	/* **** */
290
	RtlAcquireResourceExclusive(&This->lock, TRUE);
291 292 293 294

	oldFreq = This->freq;
	This->freq = freq;
	if (freq != oldFreq) {
295
		This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
296
		This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
297
		DSOUND_RecalcFormat(This);
298
		DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
299 300
	}

301
	RtlReleaseResource(&This->lock);
302 303 304 305 306 307 308 309
	/* **** */

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Play(
	LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
) {
310
	HRESULT hres = DS_OK;
311
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
312
	TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
313 314

	/* **** */
315
	RtlAcquireResourceExclusive(&This->lock, TRUE);
316 317

	This->playflags = flags;
318
	if (This->state == STATE_STOPPED && !This->hwbuf) {
319 320 321 322 323
		This->leadin = TRUE;
		This->state = STATE_STARTING;
	} else if (This->state == STATE_STOPPING)
		This->state = STATE_PLAYING;
	if (This->hwbuf) {
324 325 326 327 328
		hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_Play failed\n");
		else
			This->state = STATE_PLAYING;
329 330
	}

331
	RtlReleaseResource(&This->lock);
332 333
	/* **** */

334
	return hres;
335 336 337 338
}

static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
{
339
	HRESULT hres = DS_OK;
340
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
341 342 343
	TRACE("(%p)\n",This);

	/* **** */
344
	RtlAcquireResourceExclusive(&This->lock, TRUE);
345 346 347 348

	if (This->state == STATE_PLAYING)
		This->state = STATE_STOPPING;
	else if (This->state == STATE_STARTING)
349
	{
350
		This->state = STATE_STOPPED;
351 352
		DSOUND_CheckEvent(This, 0, 0);
	}
353
	if (This->hwbuf) {
354 355 356 357 358
		hres = IDsDriverBuffer_Stop(This->hwbuf);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_Stop failed\n");
		else
			This->state = STATE_STOPPED;
359 360
	}

361
	RtlReleaseResource(&This->lock);
362 363
	/* **** */

364
	return hres;
365 366
}

367 368
static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
{
369 370
    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
    ULONG ref = InterlockedIncrement(&(This->ref));
371
    TRACE("(%p) ref was %d\n", This, ref - 1);
372
    return ref;
373
}
374

375
static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
376
{
377 378
    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
    ULONG ref = InterlockedDecrement(&(This->ref));
379
    TRACE("(%p) ref was %d\n", This, ref + 1);
380

381
    if (!ref) {
382
	DirectSoundDevice_RemoveBuffer(This->device, This);
383
	RtlDeleteResource(&This->lock);
384

385
	if (This->hwbuf)
386
		IDsDriverBuffer_Release(This->hwbuf);
387
	if (!This->hwbuf || (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)) {
388
		This->buffer->ref--;
389
		list_remove(&This->entry);
390 391
		if (This->buffer->ref==0) {
			HeapFree(GetProcessHeap(),0,This->buffer->memory);
392
			HeapFree(GetProcessHeap(),0,This->buffer);
393
		}
394
	}
395

396
	HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
397 398
	HeapFree(GetProcessHeap(), 0, This->notifies);
	HeapFree(GetProcessHeap(), 0, This->pwfx);
399
	HeapFree(GetProcessHeap(), 0, This);
400

401 402 403
	TRACE("(%p) released\n", This);
    }
    return ref;
404 405 406 407 408 409
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
) {
	HRESULT	hres;
410
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
411
	TRACE("(%p,%p,%p)\n",This,playpos,writepos);
412 413

	RtlAcquireResourceShared(&This->lock, TRUE);
414 415
	if (This->hwbuf) {
		hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
416 417
		if (hres != DS_OK) {
		    WARN("IDsDriverBuffer_GetPosition failed\n");
418
		    return hres;
419
		}
420
	} else {
421 422 423 424 425 426 427 428 429 430
		DWORD pos = This->sec_mixpos;

		/* sanity */
		if (pos >= This->buflen){
			FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
			pos %= This->buflen;
		}

		if (playpos)
			*playpos = pos;
431
		if (writepos)
432
			*writepos = pos;
433
	}
434 435 436
	if (writepos && This->state != STATE_STOPPED && (!This->hwbuf || !(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDWRITELEAD))) {
		/* apply the documented 10ms lead to writepos */
		*writepos += This->writelead;
437
		*writepos %= This->buflen;
438
	}
439
	RtlReleaseResource(&This->lock);
440 441

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

444 445 446 447 448 449
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
) {
450
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
451
	TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
452

453 454
	if (status == NULL) {
		WARN("invalid parameter: status = NULL\n");
455
		return DSERR_INVALIDPARAM;
456
	}
457 458

	*status = 0;
459
	RtlAcquireResourceShared(&This->lock, TRUE);
460 461 462 463 464
	if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
		*status |= DSBSTATUS_PLAYING;
		if (This->playflags & DSBPLAY_LOOPING)
			*status |= DSBSTATUS_LOOPING;
	}
465
	RtlReleaseResource(&This->lock);
466

467
	TRACE("status=%x\n", *status);
468 469 470 471 472
	return DS_OK;
}


static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
473 474 475 476 477 478
    LPDIRECTSOUNDBUFFER8 iface,
    LPWAVEFORMATEX lpwf,
    DWORD wfsize,
    LPDWORD wfwritten)
{
    DWORD size;
479
    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
480
    TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
481

482
    size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
483

484 485
    if (lpwf) { /* NULL is valid */
        if (wfsize >= size) {
486
            CopyMemory(lpwf,This->pwfx,size);
487 488 489
            if (wfwritten)
                *wfwritten = size;
        } else {
490
            WARN("invalid parameter: wfsize too small\n");
491
            CopyMemory(lpwf,This->pwfx,wfsize);
492
            if (wfwritten)
493
                *wfwritten = wfsize;
494 495 496 497 498 499 500 501 502 503 504 505
            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;
506 507 508
}

static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
509
	LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID *lplpaudioptr1,LPDWORD audiobytes1,LPVOID *lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
510
) {
511
	HRESULT hres = DS_OK;
512
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
513

514
	TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n",
515 516 517 518 519 520 521 522 523 524 525
		This,
		writecursor,
		writebytes,
		lplpaudioptr1,
		audiobytes1,
		lplpaudioptr2,
		audiobytes2,
		flags,
		GetTickCount()
	);

526 527 528
        if (!audiobytes1)
            return DSERR_INVALIDPARAM;

529
        /* when this flag is set, writecursor is meaningless and must be calculated */
530 531
	if (flags & DSBLOCK_FROMWRITECURSOR) {
		/* GetCurrentPosition does too much magic to duplicate here */
532
		hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
533 534 535 536
		if (hres != DS_OK) {
			WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
			return hres;
		}
537
	}
538 539

        /* when this flag is set, writebytes is meaningless and must be set */
540 541
	if (flags & DSBLOCK_ENTIREBUFFER)
		writebytes = This->buflen;
542 543

	if (writecursor >= This->buflen) {
544
		WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
545 546 547 548 549
		     writecursor, This->buflen);
		return DSERR_INVALIDPARAM;
        }

	if (writebytes > This->buflen) {
550
		WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
551 552 553
		     writebytes, This->buflen);
		return DSERR_INVALIDPARAM;
        }
554

555
	/* **** */
556
	RtlAcquireResourceShared(&This->lock, TRUE);
557

Robert Reif's avatar
Robert Reif committed
558
	if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
559
		hres = IDsDriverBuffer_Lock(This->hwbuf,
560 561 562 563
				     lplpaudioptr1, audiobytes1,
				     lplpaudioptr2, audiobytes2,
				     writecursor, writebytes,
				     0);
564 565
		if (hres != DS_OK) {
			WARN("IDsDriverBuffer_Lock failed\n");
566
			RtlReleaseResource(&This->lock);
567 568 569
			return hres;
		}
	} else {
570
		if (writecursor+writebytes <= This->buflen) {
571
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
572 573
			if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
				WARN("Overwriting mixing position, case 1\n");
574 575 576 577 578
			*audiobytes1 = writebytes;
			if (lplpaudioptr2)
				*(LPBYTE*)lplpaudioptr2 = NULL;
			if (audiobytes2)
				*audiobytes2 = 0;
579 580
			TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
			  *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
581
			TRACE("->%d.0\n",writebytes);
582
		} else {
583
			DWORD remainder = writebytes + writecursor - This->buflen;
584
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
585
			*audiobytes1 = This->buflen-writecursor;
586 587
			if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
				WARN("Overwriting mixing position, case 2\n");
588
			if (lplpaudioptr2)
589
				*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
590 591
			if (audiobytes2)
				*audiobytes2 = writebytes-(This->buflen-writecursor);
592 593
			if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
				WARN("Overwriting mixing position, case 3\n");
594
			TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
595 596
		}
	}
597

598
	RtlReleaseResource(&This->lock);
599
	/* **** */
600

601 602 603 604 605 606
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
) {
607
	HRESULT hres = DS_OK;
608
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
609
	DWORD oldpos;
610
	TRACE("(%p,%d)\n",This,newpos);
611 612

	/* **** */
613
	RtlAcquireResourceExclusive(&This->lock, TRUE);
614

615 616
	oldpos = This->sec_mixpos;

617
	/* start mixing from this new location instead */
618
	newpos %= This->buflen;
619
	newpos -= newpos%This->pwfx->nBlockAlign;
620
	This->sec_mixpos = newpos;
621 622 623 624

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

625
	/* position HW buffer if applicable, else just start mixing from new location instead */
626 627 628 629 630
	if (This->hwbuf) {
		hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_SetPosition failed\n");
	}
631 632 633
	else if (oldpos != newpos)
		/* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
		This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
634

635
	RtlReleaseResource(&This->lock);
636 637
	/* **** */

638
	return hres;
639 640 641 642 643
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
	LPDIRECTSOUNDBUFFER8 iface,LONG pan
) {
644
	HRESULT hres = DS_OK;
645
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
646

647
	TRACE("(%p,%d)\n",This,pan);
648

649
	if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
650
		WARN("invalid parameter: pan = %d\n", pan);
651
		return DSERR_INVALIDPARAM;
652
	}
653 654 655

	/* You cannot use both pan and 3D controls */
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
656 657
	    (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
		WARN("control unavailable\n");
658
		return DSERR_CONTROLUNAVAIL;
659
	}
660 661

	/* **** */
662
	RtlAcquireResourceExclusive(&This->lock, TRUE);
663

664 665
	if (This->volpan.lPan != pan) {
		This->volpan.lPan = pan;
666 667 668
		DSOUND_RecalcVolPan(&(This->volpan));

		if (This->hwbuf) {
669 670 671
			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
			if (hres != DS_OK)
				WARN("IDsDriverBuffer_SetVolumePan failed\n");
672
		}
673 674
	}

675
	RtlReleaseResource(&This->lock);
676 677
	/* **** */

678
	return hres;
679 680 681 682 683
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
) {
684
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
685 686
	TRACE("(%p,%p)\n",This,pan);

687 688 689 690 691
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

692 693
	if (pan == NULL) {
		WARN("invalid parameter: pan = NULL\n");
694
		return DSERR_INVALIDPARAM;
695
	}
696 697 698 699 700 701 702 703 704

	*pan = This->volpan.lPan;

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
	LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
) {
705
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface, *iter;
706
	HRESULT hres = DS_OK;
707

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

710
	/* **** */
711
	RtlAcquireResourceShared(&This->lock, TRUE);
712

Robert Reif's avatar
Robert Reif committed
713
	if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
714
		hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
715
		if (hres != DS_OK)
716
			WARN("IDsDriverBuffer_Unlock failed\n");
717 718
	}

719
	RtlReleaseResource(&This->lock);
720 721
	/* **** */

722 723 724
	if (!p2)
		x2 = 0;

725
	if (!This->hwbuf && (x1 || x2))
726 727 728 729 730 731
	{
		RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
		LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
		{
			RtlAcquireResourceShared(&iter->lock, TRUE);
			if (x1)
732 733 734 735 736 737
                        {
			    if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
			      hres = DSERR_INVALIDPARAM;
			    else
			      DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
                        }
738
			if (x2)
739
				DSOUND_MixToTemporary(iter, 0, x2, FALSE);
740 741 742 743 744
			RtlReleaseResource(&iter->lock);
		}
		RtlReleaseResource(&This->device->buffer_list_lock);
	}

745
	return hres;
746 747 748 749 750
}

static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
	LPDIRECTSOUNDBUFFER8 iface
) {
751
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
752 753 754 755 756 757 758
	FIXME("(%p):stub\n",This);
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
) {
759
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
760 761
	TRACE("(%p,%p)\n",This,freq);

762 763
	if (freq == NULL) {
		WARN("invalid parameter: freq = NULL\n");
764
		return DSERR_INVALIDPARAM;
765
	}
766 767

	*freq = This->freq;
768
	TRACE("-> %d\n", *freq);
769 770 771 772 773 774 775

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
) {
776
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
777 778
	DWORD u;

779
	FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
780 781 782 783

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

784
	WARN("control unavailable\n");
785 786 787 788 789 790
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
) {
791
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
792 793
	DWORD u;

794
	FIXME("(%p,%08u,%u,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
795 796 797 798

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

799
	WARN("control unavailable\n");
800 801 802 803 804 805
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
	LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
) {
806
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
807

808
	FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
809

810
	WARN("control unavailable\n");
811 812 813 814
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
815
	LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
816
) {
817
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
818
	WARN("(%p) already initialized\n", This);
819 820 821 822 823 824
	return DSERR_ALREADYINITIALIZED;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
	LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
) {
825
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
826 827
  	TRACE("(%p)->(%p)\n",This,caps);

828 829
	if (caps == NULL) {
		WARN("invalid parameter: caps == NULL\n");
830
		return DSERR_INVALIDPARAM;
831 832 833
	}

	if (caps->dwSize < sizeof(*caps)) {
834
		WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
835 836
		return DSERR_INVALIDPARAM;
	}
837 838 839 840 841 842 843

	caps->dwFlags = This->dsbd.dwFlags;
	if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
	else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;

	caps->dwBufferBytes = This->buflen;

844 845
	/* According to windows, this is zero*/
	caps->dwUnlockTransferRate = 0;
846 847 848 849 850 851 852 853
	caps->dwPlayCpuOverhead = 0;

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
	LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
) {
854
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
855 856 857

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

858 859 860 861 862
	if (ppobj == NULL) {
		WARN("invalid parameter\n");
		return E_INVALIDARG;
	}

863 864
	*ppobj = NULL;	/* assume failure */

865 866
	if ( IsEqualGUID(riid, &IID_IUnknown) ||
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
867
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
868 869 870 871 872
		if (!This->secondary)
			SecondaryBufferImpl_Create(This, &(This->secondary));
		if (This->secondary) {
			IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
			*ppobj = This->secondary;
873 874 875 876
			return S_OK;
		}
		WARN("IID_IDirectSoundBuffer\n");
		return E_NOINTERFACE;
877 878
	}

879
	if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
880 881
		if (!This->notify)
			IDirectSoundNotifyImpl_Create(This, &(This->notify));
882 883
		if (This->notify) {
			IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
884
			*ppobj = This->notify;
885 886
			return S_OK;
		}
887
		WARN("IID_IDirectSoundNotify\n");
888
		return E_NOINTERFACE;
889 890 891 892
	}

	if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
		if (!This->ds3db)
893 894 895 896
			IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
		if (This->ds3db) {
			IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
			*ppobj = This->ds3db;
897 898
			return S_OK;
		}
899
		WARN("IID_IDirectSound3DBuffer\n");
900
		return E_NOINTERFACE;
901 902
	}

903
	if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
904
		ERR("app requested IDirectSound3DListener on secondary buffer\n");
905
		return E_NOINTERFACE;
906 907 908
	}

	if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
909 910 911 912 913 914
		if (!This->iks)
			IKsBufferPropertySetImpl_Create(This, &(This->iks));
		if (This->iks) {
			IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
	    		*ppobj = This->iks;
			return S_OK;
915
		}
916
		WARN("IID_IKsPropertySet\n");
917
		return E_NOINTERFACE;
918 919
	}

920 921 922 923 924
	FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );

	return E_NOINTERFACE;
}

925
static const IDirectSoundBuffer8Vtbl dsbvt =
926 927 928 929 930 931 932 933 934
{
	IDirectSoundBufferImpl_QueryInterface,
	IDirectSoundBufferImpl_AddRef,
	IDirectSoundBufferImpl_Release,
	IDirectSoundBufferImpl_GetCaps,
	IDirectSoundBufferImpl_GetCurrentPosition,
	IDirectSoundBufferImpl_GetFormat,
	IDirectSoundBufferImpl_GetVolume,
	IDirectSoundBufferImpl_GetPan,
935
	IDirectSoundBufferImpl_GetFrequency,
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
	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
};

953
HRESULT IDirectSoundBufferImpl_Create(
Robert Reif's avatar
Robert Reif committed
954
	DirectSoundDevice * device,
955
	IDirectSoundBufferImpl **pdsb,
956
	LPCDSBUFFERDESC dsbd)
957 958 959 960 961
{
	IDirectSoundBufferImpl *dsb;
	LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
	HRESULT err = DS_OK;
	DWORD capf = 0;
962
	int use_hw;
Robert Reif's avatar
Robert Reif committed
963
	TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
964 965

	if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
966
		WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
967
		*pdsb = NULL;
968 969 970
		return DSERR_INVALIDPARAM; /* FIXME: which error? */
	}

971
	dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
972 973 974 975 976 977

	if (dsb == 0) {
		WARN("out of memory\n");
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}
978 979 980

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

981
	dsb->ref = 0;
982
	dsb->secondary = 0;
Robert Reif's avatar
Robert Reif committed
983
	dsb->device = device;
984
	dsb->lpVtbl = &dsbvt;
985
	dsb->iks = NULL;
986

987
	/* size depends on version */
988
	CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
989

990
	dsb->pwfx = DSOUND_CopyFormat(wfex);
991 992 993 994 995 996
	if (dsb->pwfx == NULL) {
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}

997 998 999 1000 1001 1002
	if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
		dsb->buflen = dsbd->dwBufferBytes + 
			(dsbd->lpwfxFormat->nBlockAlign - 
			(dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
	else
		dsb->buflen = dsbd->dwBufferBytes;
1003

1004
	dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1005 1006 1007 1008 1009
	dsb->notify = NULL;
	dsb->notifies = NULL;
	dsb->nrofnotifies = 0;
	dsb->hwnotify = 0;

1010 1011 1012 1013 1014
	/* 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;
1015

1016 1017
	use_hw = !!(dsbd->dwFlags & DSBCAPS_LOCHARDWARE);
	TRACE("use_hw = %d, capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", use_hw, capf, device->drvcaps.dwFlags);
1018
	if (use_hw && ((device->drvcaps.dwFlags & capf) != capf || !device->driver))
1019
	{
1020 1021
		if (device->driver)
			WARN("Format not supported for hardware buffer\n");
1022 1023 1024
		HeapFree(GetProcessHeap(),0,dsb->pwfx);
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
1025 1026 1027
		if ((device->drvcaps.dwFlags & capf) != capf)
			return DSERR_BADFORMAT;
		return DSERR_GENERIC;
1028
	}
1029 1030 1031 1032 1033 1034

	/* FIXME: check hardware sample rate mixing capabilities */
	/* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
	/* FIXME: check whether any hardware buffers are left */
	/* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */

1035 1036 1037 1038 1039 1040 1041 1042 1043
	/* 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;
	}
1044

1045
	/* Allocate system memory for buffer if applicable */
Robert Reif's avatar
Robert Reif committed
1046
	if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1047
		dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1048 1049
		if (dsb->buffer->memory == NULL) {
			WARN("out of memory\n");
1050
			HeapFree(GetProcessHeap(),0,dsb->pwfx);
1051 1052 1053 1054 1055
			HeapFree(GetProcessHeap(),0,dsb->buffer);
			HeapFree(GetProcessHeap(),0,dsb);
			*pdsb = NULL;
			return DSERR_OUTOFMEMORY;
		}
1056 1057 1058
	}

	/* Allocate the hardware buffer */
1059
	if (use_hw) {
Robert Reif's avatar
Robert Reif committed
1060
		err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1061
						  &(dsb->buflen),&(dsb->buffer->memory),
1062
						  (LPVOID*)&(dsb->hwbuf));
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
		if (FAILED(err))
		{
			WARN("Failed to create hardware secondary buffer: %08x\n", err);
			if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY)
				HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
			HeapFree(GetProcessHeap(),0,dsb->buffer);
			HeapFree(GetProcessHeap(),0,dsb->pwfx);
			HeapFree(GetProcessHeap(),0,dsb);
			*pdsb = NULL;
			return DSERR_GENERIC;
1073
		}
1074 1075
	}

1076 1077 1078 1079 1080
	dsb->buffer->ref = 1;
	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);

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

1086
	dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
1087 1088 1089
	dsb->nAvgBytesPerSec = dsb->freq *
		dsbd->lpwfxFormat->nBlockAlign;

1090 1091 1092
	/* calculate fragment size and write lead */
	DSOUND_RecalcFormat(dsb);

1093 1094
	if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
		dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1095 1096 1097 1098 1099 1100
		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;
1101 1102
		dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
		dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1103 1104 1105
		dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1106 1107 1108 1109 1110 1111 1112
		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);
1113
	} else
1114 1115
		DSOUND_RecalcVolPan(&(dsb->volpan));

1116
	RtlInitializeResource(&dsb->lock);
1117

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

1131
	*pdsb = dsb;
1132
	return err;
1133
}
1134

1135
HRESULT IDirectSoundBufferImpl_Destroy(
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
    IDirectSoundBufferImpl *pdsb)
{
    TRACE("(%p)\n",pdsb);

    /* This keeps the *_Destroy functions from possibly deleting
     * this object until it is ready to be deleted */
    IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);

    if (pdsb->iks) {
        WARN("iks not NULL\n");
        IKsBufferPropertySetImpl_Destroy(pdsb->iks);
        pdsb->iks = NULL;
    }

    if (pdsb->ds3db) {
        WARN("ds3db not NULL\n");
        IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
        pdsb->ds3db = NULL;
    }

    if (pdsb->notify) {
        WARN("notify not NULL\n");
        IDirectSoundNotifyImpl_Destroy(pdsb->notify);
        pdsb->notify = NULL;
    }

1162
    if (pdsb->secondary) {
1163
        WARN("dsb not NULL\n");
1164 1165
        SecondaryBufferImpl_Destroy(pdsb->secondary);
        pdsb->secondary = NULL;
1166 1167 1168 1169 1170 1171 1172
    }

    while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);

    return S_OK;
}

1173 1174 1175 1176 1177 1178 1179 1180 1181
HRESULT IDirectSoundBufferImpl_Duplicate(
    DirectSoundDevice *device,
    IDirectSoundBufferImpl **ppdsb,
    IDirectSoundBufferImpl *pdsb)
{
    IDirectSoundBufferImpl *dsb;
    HRESULT hres = DS_OK;
    TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);

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

1190 1191 1192 1193 1194 1195
    dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
    if (dsb->pwfx == NULL) {
        HeapFree(GetProcessHeap(),0,dsb);
        *ppdsb = NULL;
        return DSERR_OUTOFMEMORY;
    }
1196 1197 1198 1199 1200 1201

    if (pdsb->hwbuf) {
        TRACE("duplicating hardware buffer\n");

        hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
                                              (LPVOID *)&dsb->hwbuf);
1202 1203
        if (FAILED(hres)) {
            WARN("IDsDriver_DuplicateSoundBuffer failed (%08x)\n", hres);
1204
            HeapFree(GetProcessHeap(),0,dsb->pwfx);
1205 1206 1207
            HeapFree(GetProcessHeap(),0,dsb);
            *ppdsb = NULL;
            return hres;
1208 1209 1210
        }
    }

1211 1212
    dsb->buffer->ref++;
    list_add_head(&dsb->buffer->buffers, &dsb->entry);
1213 1214
    dsb->ref = 0;
    dsb->state = STATE_STOPPED;
1215
    dsb->buf_mixpos = dsb->sec_mixpos = 0;
1216 1217 1218 1219
    dsb->device = device;
    dsb->ds3db = NULL;
    dsb->iks = NULL; /* FIXME? */
    dsb->secondary = NULL;
1220 1221
    dsb->tmp_buffer = NULL;
    DSOUND_RecalcFormat(dsb);
1222
    DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
1223

1224
    RtlInitializeResource(&dsb->lock);
1225 1226 1227 1228

    /* register buffer */
    hres = DirectSoundDevice_AddBuffer(device, dsb);
    if (hres != DS_OK) {
1229
        RtlDeleteResource(&dsb->lock);
1230
        HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
1231 1232
        list_remove(&dsb->entry);
        dsb->buffer->ref--;
1233 1234
        HeapFree(GetProcessHeap(),0,dsb->pwfx);
        HeapFree(GetProcessHeap(),0,dsb);
1235
        dsb = NULL;
1236 1237 1238 1239 1240 1241
    }

    *ppdsb = dsb;
    return hres;
}

1242 1243 1244 1245 1246
/*******************************************************************************
 *		SecondaryBuffer
 */

static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1247
	LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1248
{
1249
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1250 1251 1252 1253 1254
	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);

	return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
}

1255
static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1256
{
1257
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1258
    ULONG ref = InterlockedIncrement(&(This->ref));
1259
    TRACE("(%p) ref was %d\n", This, ref - 1);
1260
    return ref;
1261 1262
}

1263
static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1264
{
1265
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
Robert Reif's avatar
Robert Reif committed
1266 1267 1268
    ULONG ref;
    TRACE("(%p)\n", This);
    ref = InterlockedDecrement(&(This->ref));
1269
    TRACE("ref was %d\n", ref + 1);
1270 1271

    if (!ref) {
1272
        This->dsb->secondary = NULL;
1273 1274 1275 1276 1277
        IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
        HeapFree(GetProcessHeap(), 0, This);
        TRACE("(%p) released\n", This);
    }
    return ref;
1278 1279 1280 1281 1282
}

static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
	LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
{
1283
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1284 1285 1286 1287 1288 1289 1290 1291
  	TRACE("(%p)->(%p)\n",This,caps);

	return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
}

static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
{
1292
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1293 1294 1295 1296 1297 1298 1299 1300
	TRACE("(%p,%p,%p)\n",This,playpos,writepos);

	return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
}

static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
	LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
{
1301
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1302
	TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
1303 1304 1305 1306 1307 1308 1309

	return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
}

static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
{
1310
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1311 1312 1313 1314 1315 1316 1317 1318
	TRACE("(%p,%p)\n",This,vol);

	return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
}

static HRESULT WINAPI SecondaryBufferImpl_GetPan(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
{
1319
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1320 1321 1322 1323 1324 1325 1326 1327
	TRACE("(%p,%p)\n",This,pan);

	return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
}

static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
{
1328
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1329 1330 1331 1332 1333 1334 1335 1336
	TRACE("(%p,%p)\n",This,freq);

	return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
}

static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
{
1337
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1338 1339 1340 1341 1342 1343
	TRACE("(%p,%p)\n",This,status);

	return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
}

static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1344
	LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1345
{
1346
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1347 1348 1349 1350 1351 1352
	TRACE("(%p,%p,%p)\n",This,dsound,dbsd);

	return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
}

static HRESULT WINAPI SecondaryBufferImpl_Lock(
1353 1354 1355
    LPDIRECTSOUNDBUFFER8 iface,
    DWORD writecursor,
    DWORD writebytes,
1356
    LPVOID *lplpaudioptr1,
1357
    LPDWORD audiobytes1,
1358
    LPVOID *lplpaudioptr2,
1359 1360
    LPDWORD audiobytes2,
    DWORD dwFlags)
1361
{
1362
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1363
    TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x)\n",
1364
        This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1365

1366 1367
    return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
        writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1368 1369 1370 1371 1372
}

static HRESULT WINAPI SecondaryBufferImpl_Play(
	LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
{
1373
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1374
	TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
1375 1376 1377 1378 1379 1380 1381

	return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
}

static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
{
1382
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1383
	TRACE("(%p,%d)\n",This,newpos);
1384 1385 1386 1387 1388

	return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
}

static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1389
	LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1390
{
1391
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1392 1393 1394 1395 1396 1397 1398 1399
	TRACE("(%p,%p)\n",This,wfex);

	return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
}

static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LONG vol)
{
1400
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1401
	TRACE("(%p,%d)\n",This,vol);
1402 1403 1404 1405 1406 1407 1408

	return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
}

static HRESULT WINAPI SecondaryBufferImpl_SetPan(
	LPDIRECTSOUNDBUFFER8 iface,LONG pan)
{
1409
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1410
	TRACE("(%p,%d)\n",This,pan);
1411 1412 1413 1414 1415 1416 1417

	return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
}

static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
{
1418
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1419
	TRACE("(%p,%d)\n",This,freq);
1420 1421 1422 1423 1424 1425

	return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
}

static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
{
1426
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1427 1428 1429 1430 1431 1432
	TRACE("(%p)\n",This);

	return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
}

static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1433 1434 1435 1436 1437
    LPDIRECTSOUNDBUFFER8 iface,
    LPVOID lpvAudioPtr1,
    DWORD dwAudioBytes1,
    LPVOID lpvAudioPtr2,
    DWORD dwAudioBytes2)
1438
{
1439
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1440
    TRACE("(%p,%p,%d,%p,%d)\n",
1441
        This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1442

1443 1444
    return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
        lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1445 1446 1447 1448 1449
}

static HRESULT WINAPI SecondaryBufferImpl_Restore(
	LPDIRECTSOUNDBUFFER8 iface)
{
1450
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1451 1452 1453 1454 1455 1456 1457 1458
	TRACE("(%p)\n",This);

	return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
}

static HRESULT WINAPI SecondaryBufferImpl_SetFX(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
{
1459
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1460
	TRACE("(%p,%u,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1461 1462 1463 1464 1465 1466 1467

	return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
}

static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
{
1468
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1469
	TRACE("(%p,%08u,%u,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1470 1471 1472 1473 1474 1475 1476

	return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
}

static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
	LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
{
1477
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1478
	TRACE("(%p,%s,%u,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1479 1480 1481 1482

	return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
}

1483
static const IDirectSoundBuffer8Vtbl sbvt =
1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
{
	SecondaryBufferImpl_QueryInterface,
	SecondaryBufferImpl_AddRef,
	SecondaryBufferImpl_Release,
	SecondaryBufferImpl_GetCaps,
	SecondaryBufferImpl_GetCurrentPosition,
	SecondaryBufferImpl_GetFormat,
	SecondaryBufferImpl_GetVolume,
	SecondaryBufferImpl_GetPan,
	SecondaryBufferImpl_GetFrequency,
	SecondaryBufferImpl_GetStatus,
	SecondaryBufferImpl_Initialize,
	SecondaryBufferImpl_Lock,
	SecondaryBufferImpl_Play,
	SecondaryBufferImpl_SetCurrentPosition,
	SecondaryBufferImpl_SetFormat,
	SecondaryBufferImpl_SetVolume,
	SecondaryBufferImpl_SetPan,
	SecondaryBufferImpl_SetFrequency,
	SecondaryBufferImpl_Stop,
	SecondaryBufferImpl_Unlock,
	SecondaryBufferImpl_Restore,
	SecondaryBufferImpl_SetFX,
	SecondaryBufferImpl_AcquireResources,
	SecondaryBufferImpl_GetObjectInPath
};

1511
HRESULT SecondaryBufferImpl_Create(
1512 1513 1514 1515 1516 1517
	IDirectSoundBufferImpl *dsb,
	SecondaryBufferImpl **psb)
{
	SecondaryBufferImpl *sb;
	TRACE("(%p,%p)\n",dsb,psb);

1518
	sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532

	if (sb == 0) {
		WARN("out of memory\n");
		*psb = NULL;
		return DSERR_OUTOFMEMORY;
	}
	sb->ref = 0;
	sb->dsb = dsb;
	sb->lpVtbl = &sbvt;

	IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
	*psb = sb;
	return S_OK;
}
1533

1534
static HRESULT SecondaryBufferImpl_Destroy(
1535 1536 1537 1538 1539 1540 1541 1542
    SecondaryBufferImpl *pdsb)
{
    TRACE("(%p)\n",pdsb);

    while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);

    return S_OK;
}
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727

/*******************************************************************************
 *              IKsBufferPropertySet
 */

/* IUnknown methods */
static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
    LPKSPROPERTYSET iface,
    REFIID riid,
    LPVOID *ppobj )
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);

    return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
}

static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    ULONG ref = InterlockedIncrement(&(This->ref));
    TRACE("(%p) ref was %d\n", This, ref - 1);
    return ref;
}

static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    ULONG ref = InterlockedDecrement(&(This->ref));
    TRACE("(%p) ref was %d\n", This, ref + 1);

    if (!ref) {
    This->dsb->iks = 0;
    IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
    HeapFree(GetProcessHeap(), 0, This);
    TRACE("(%p) released\n", This);
    }
    return ref;
}

static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
    LPKSPROPERTYSET iface,
    REFGUID guidPropSet,
    ULONG dwPropID,
    LPVOID pInstanceData,
    ULONG cbInstanceData,
    LPVOID pPropData,
    ULONG cbPropData,
    PULONG pcbReturned )
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    PIDSDRIVERPROPERTYSET ps;
    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);

    if (This->dsb->hwbuf) {
        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);

        if (ps) {
        DSPROPERTY prop;
        HRESULT hres;

        prop.s.Set = *guidPropSet;
        prop.s.Id = dwPropID;
        prop.s.Flags = 0;  /* unused */
        prop.s.InstanceId = (ULONG)This->dsb->device;


        hres = IDsDriverPropertySet_Get(ps, &prop, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned);

        IDsDriverPropertySet_Release(ps);

        return hres;
        }
    }

    return E_PROP_ID_UNSUPPORTED;
}

static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
    LPKSPROPERTYSET iface,
    REFGUID guidPropSet,
    ULONG dwPropID,
    LPVOID pInstanceData,
    ULONG cbInstanceData,
    LPVOID pPropData,
    ULONG cbPropData )
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    PIDSDRIVERPROPERTYSET ps;
    TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);

    if (This->dsb->hwbuf) {
        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);

        if (ps) {
        DSPROPERTY prop;
        HRESULT hres;

        prop.s.Set = *guidPropSet;
        prop.s.Id = dwPropID;
        prop.s.Flags = 0;  /* unused */
        prop.s.InstanceId = (ULONG)This->dsb->device;
        hres = IDsDriverPropertySet_Set(ps,&prop,pInstanceData,cbInstanceData,pPropData,cbPropData);

        IDsDriverPropertySet_Release(ps);

        return hres;
        }
    }

    return E_PROP_ID_UNSUPPORTED;
}

static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
    LPKSPROPERTYSET iface,
    REFGUID guidPropSet,
    ULONG dwPropID,
    PULONG pTypeSupport )
{
    IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
    PIDSDRIVERPROPERTYSET ps;
    TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);

    if (This->dsb->hwbuf) {
        IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps);

        if (ps) {
            HRESULT hres;

            hres = IDsDriverPropertySet_QuerySupport(ps,guidPropSet, dwPropID,pTypeSupport);

            IDsDriverPropertySet_Release(ps);

            return hres;
        }
    }

    return E_PROP_ID_UNSUPPORTED;
}

static const IKsPropertySetVtbl iksbvt = {
    IKsBufferPropertySetImpl_QueryInterface,
    IKsBufferPropertySetImpl_AddRef,
    IKsBufferPropertySetImpl_Release,
    IKsBufferPropertySetImpl_Get,
    IKsBufferPropertySetImpl_Set,
    IKsBufferPropertySetImpl_QuerySupport
};

HRESULT IKsBufferPropertySetImpl_Create(
    IDirectSoundBufferImpl *dsb,
    IKsBufferPropertySetImpl **piks)
{
    IKsBufferPropertySetImpl *iks;
    TRACE("(%p,%p)\n",dsb,piks);
    *piks = NULL;

    iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
    if (iks == 0) {
        WARN("out of memory\n");
        *piks = NULL;
        return DSERR_OUTOFMEMORY;
    }

    iks->ref = 0;
    iks->dsb = dsb;
    dsb->iks = iks;
    iks->lpVtbl = &iksbvt;

    IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);

    *piks = iks;
    return S_OK;
}

HRESULT IKsBufferPropertySetImpl_Destroy(
    IKsBufferPropertySetImpl *piks)
{
    TRACE("(%p)\n",piks);

    while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);

    return S_OK;
}