buffer.c 48.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 NONAMELESSSTRUCT
#define NONAMELESSUNION
26 27
#include "windef.h"
#include "winbase.h"
28
#include "winuser.h"
29
#include "mmsystem.h"
30
#include "winreg.h"
31
#include "winternl.h"
32 33 34 35 36 37 38
#include "wine/debug.h"
#include "dsound.h"
#include "dsdriver.h"
#include "dsound_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dsound);

39 40
static HRESULT SecondaryBufferImpl_Destroy(SecondaryBufferImpl *pdsb);

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

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);

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

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

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

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

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

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

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

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

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

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

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

	return S_OK;
}

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

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

158
    dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
159

160 161 162 163 164 165 166 167 168 169
    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);
170

171 172 173
    *pdsn = dsn;
    return DS_OK;
}
174

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

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

    return DS_OK;
}

185 186 187 188 189
/*******************************************************************************
 *		IDirectSoundBuffer
 */

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

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

static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LONG vol
) {
203
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
204
	LONG oldVol;
205
	HRESULT hres = DS_OK;
206 207 208

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

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

214 215
	if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
		WARN("invalid parameter: vol = %ld\n", vol);
216
		return DSERR_INVALIDPARAM;
217
	}
218 219 220 221 222

	/* **** */
	EnterCriticalSection(&(This->lock));

	if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
223 224
		oldVol = This->ds3db_lVolume;
		This->ds3db_lVolume = vol;
225 226 227
	} else {
		oldVol = This->volpan.lVolume;
		This->volpan.lVolume = vol;
228
		if (vol != oldVol)
229
			DSOUND_RecalcVolPan(&(This->volpan));
230 231 232 233
	}

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

	LeaveCriticalSection(&(This->lock));
	/* **** */

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 274 275
	DWORD oldFreq;

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

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 285
	if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
		WARN("invalid parameter: freq = %ld\n", freq);
286
		return DSERR_INVALIDPARAM;
287
	}
288 289 290 291 292 293 294

	/* **** */
	EnterCriticalSection(&(This->lock));

	oldFreq = This->freq;
	This->freq = freq;
	if (freq != oldFreq) {
Robert Reif's avatar
Robert Reif committed
295
		This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
296
		This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
297
		DSOUND_RecalcFormat(This);
298
		if (!This->hwbuf)
299
			DSOUND_ForceRemix(This);
300 301 302 303 304 305 306 307 308 309 310
	}

	LeaveCriticalSection(&(This->lock));
	/* **** */

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Play(
	LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
) {
311
	HRESULT hres = DS_OK;
312
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
313
	TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
314 315 316 317 318 319 320 321 322 323 324 325

	/* **** */
	EnterCriticalSection(&(This->lock));

	This->playflags = flags;
	if (This->state == STATE_STOPPED) {
		This->leadin = TRUE;
		This->startpos = This->buf_mixpos;
		This->state = STATE_STARTING;
	} else if (This->state == STATE_STOPPING)
		This->state = STATE_PLAYING;
	if (This->hwbuf) {
326 327 328 329 330
		hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_Play failed\n");
		else
			This->state = STATE_PLAYING;
331 332 333 334 335
	}

	LeaveCriticalSection(&(This->lock));
	/* **** */

336
	return hres;
337 338 339 340
}

static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
{
341
	HRESULT hres = DS_OK;
342
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
343 344 345 346 347 348 349 350 351 352
	TRACE("(%p)\n",This);

	/* **** */
	EnterCriticalSection(&(This->lock));

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

	LeaveCriticalSection(&(This->lock));
	/* **** */

364
	return hres;
365 366
}

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

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

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

384
	This->lock.DebugInfo->Spare[0] = 0;
385
	DeleteCriticalSection(&(This->lock));
386

387 388
	if (This->hwbuf) {
		IDsDriverBuffer_Release(This->hwbuf);
Robert Reif's avatar
Robert Reif committed
389
		if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
390 391 392 393 394 395 396 397 398 399
			This->buffer->ref--;
			if (This->buffer->ref==0) {
				HeapFree(GetProcessHeap(),0,This->buffer->memory);
				HeapFree(GetProcessHeap(),0,This->buffer);
			}
		}
	} else {
		This->buffer->ref--;
		if (This->buffer->ref==0) {
			HeapFree(GetProcessHeap(),0,This->buffer->memory);
400
			HeapFree(GetProcessHeap(),0,This->buffer);
401
		}
402
	}
403

404 405
	HeapFree(GetProcessHeap(), 0, This->notifies);
	HeapFree(GetProcessHeap(), 0, This->pwfx);
406
	HeapFree(GetProcessHeap(), 0, This);
407

408 409 410
	TRACE("(%p) released\n", This);
    }
    return ref;
411 412
}

413
DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite)
414
{
415 416
	DWORD bplay = This->buf_mixpos;
	DWORD pmix = This->primary_mixpos;
Robert Reif's avatar
Robert Reif committed
417
        DirectSoundDevice * device = This->device;
418
	TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite);
419 420 421 422

	/* the actual primary play position (pplay) is always behind last mixed (pmix),
	 * unless the computer is too slow or something */
	/* we need to know how far away we are from there */
Robert Reif's avatar
Robert Reif committed
423
	if (pmix < pplay) pmix += device->buflen; /* wraparound */
424 425
	pmix -= pplay;
	/* detect buffer underrun */
Robert Reif's avatar
Robert Reif committed
426
	if (pwrite < pplay) pwrite += device->buflen; /* wraparound */
427
	pwrite -= pplay;
Robert Reif's avatar
Robert Reif committed
428
	if (pmix > (ds_snd_queue_max * device->fraglen + pwrite + device->writelead)) {
429 430 431 432
		WARN("detected an underrun: primary queue was %ld\n",pmix);
		pmix = 0;
	}
	/* divide the offset by its sample size */
Robert Reif's avatar
Robert Reif committed
433
	pmix /= device->pwfx->nBlockAlign;
434 435 436 437
	TRACE("primary back-samples=%ld\n",pmix);
	/* adjust for our frequency */
	pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
	/* multiply by our own sample size */
438
	pmix *= This->pwfx->nBlockAlign;
439 440 441 442
	TRACE("this back-offset=%ld\n", pmix);
	/* subtract from our last mixed position */
	while (bplay < pmix) bplay += This->buflen; /* wraparound */
	bplay -= pmix;
443
	if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) {
444 445 446 447 448 449 450 451 452 453 454 455
		/* seems we haven't started playing yet */
		TRACE("this still in lead-in phase\n");
		bplay = This->startpos;
	}
	/* return the result */
	return bplay;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
) {
	HRESULT	hres;
456
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
457 458 459
	TRACE("(%p,%p,%p)\n",This,playpos,writepos);
	if (This->hwbuf) {
		hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
460 461
		if (hres != DS_OK) {
		    WARN("IDsDriverBuffer_GetPosition failed\n");
462
		    return hres;
463
		}
464
	} else {
465 466 467
		if (playpos && (This->state != STATE_PLAYING)) {
			/* we haven't been merged into the primary buffer (yet) */
			*playpos = This->buf_mixpos;
468
		} else if (playpos) {
469
			DWORD pplay, pwrite;
470
			/* let's get this exact; first, recursively call GetPosition on the primary */
Robert Reif's avatar
Robert Reif committed
471 472
			EnterCriticalSection(&(This->device->mixlock));
			if (DSOUND_PrimaryGetPosition(This->device, &pplay, &pwrite) != DS_OK)
473
				WARN("DSOUND_PrimaryGetPosition failed\n");
474
			/* detect HEL mode underrun */
Robert Reif's avatar
Robert Reif committed
475
			if (!(This->device->hwbuf || This->device->pwqueue))
476
				TRACE("detected an underrun\n");
Robert Reif's avatar
Robert Reif committed
477
			if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->device->hwbuf) {
478
				/* calculate play position using this */
479
				*playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite);
480 481 482 483 484 485 486
			} else {
				/* (unless the app isn't using GETCURRENTPOSITION2) */
				/* don't know exactly how this should be handled...
				 * the docs says that play cursor is reported as directly
				 * behind write cursor, hmm... */
				/* let's just do what might work for Half-Life */
				DWORD wp;
Robert Reif's avatar
Robert Reif committed
487 488
				wp = (This->device->pwplay + ds_hel_margin) * This->device->fraglen;
				wp %= This->device->buflen;
489
				*playpos = DSOUND_CalcPlayPosition(This, wp, pwrite);
490
			}
Robert Reif's avatar
Robert Reif committed
491
			LeaveCriticalSection(&(This->device->mixlock));
492
		}
493 494
		if (writepos)
                    *writepos = This->buf_mixpos;
495 496
	}
	if (writepos) {
497
		if (This->state != STATE_STOPPED) {
498 499
			/* apply the documented 10ms lead to writepos */
			*writepos += This->writelead;
500 501
		}
		*writepos %= This->buflen;
502
	}
503 504
	if (playpos)
            This->last_playpos = *playpos;
505 506 507 508 509 510 511
	TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
) {
512
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
513
	TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
514

515 516
	if (status == NULL) {
		WARN("invalid parameter: status = NULL\n");
517
		return DSERR_INVALIDPARAM;
518
	}
519 520 521 522 523 524 525 526 527 528 529 530 531 532

	*status = 0;
	if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
		*status |= DSBSTATUS_PLAYING;
		if (This->playflags & DSBPLAY_LOOPING)
			*status |= DSBSTATUS_LOOPING;
	}

	TRACE("status=%lx\n", *status);
	return DS_OK;
}


static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
533 534 535 536 537 538
    LPDIRECTSOUNDBUFFER8 iface,
    LPWAVEFORMATEX lpwf,
    DWORD wfsize,
    LPDWORD wfwritten)
{
    DWORD size;
539
    IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
540
    TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
541

542
    size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
543

544 545
    if (lpwf) { /* NULL is valid */
        if (wfsize >= size) {
546
            CopyMemory(lpwf,This->pwfx,size);
547 548 549
            if (wfwritten)
                *wfwritten = size;
        } else {
550
            WARN("invalid parameter: wfsize too small\n");
551 552 553 554 555 556 557 558 559 560 561 562 563 564
            if (wfwritten)
                *wfwritten = 0;
            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;
565 566 567 568 569
}

static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
	LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
) {
570
	HRESULT hres = DS_OK;
571
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
572 573 574 575 576 577 578 579 580 581 582 583 584

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

585
        /* when this flag is set, writecursor is meaningless and must be calculated */
586 587
	if (flags & DSBLOCK_FROMWRITECURSOR) {
		/* GetCurrentPosition does too much magic to duplicate here */
588
		hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
589 590 591 592
		if (hres != DS_OK) {
			WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
			return hres;
		}
593
	}
594 595

        /* when this flag is set, writebytes is meaningless and must be set */
596 597
	if (flags & DSBLOCK_ENTIREBUFFER)
		writebytes = This->buflen;
598 599 600 601 602 603 604 605 606 607 608 609

	if (writecursor >= This->buflen) {
		WARN("Invalid parameter, writecursor: %lu >= buflen: %lu\n",
		     writecursor, This->buflen);
		return DSERR_INVALIDPARAM;
        }

	if (writebytes > This->buflen) {
		WARN("Invalid parameter, writebytes: %lu > buflen: %lu\n",
		     writebytes, This->buflen);
		return DSERR_INVALIDPARAM;
        }
610

611 612
	EnterCriticalSection(&(This->lock));

613 614 615 616 617 618 619 620 621 622 623
	if ((writebytes == This->buflen) &&
	    ((This->state == STATE_STARTING) ||
	     (This->state == STATE_PLAYING)))
		/* some games, like Half-Life, try to be clever (not) and
		 * keep one secondary buffer, and mix sounds into it itself,
		 * locking the entire buffer every time... so we can just forget
		 * about tracking the last-written-to-position... */
		This->probably_valid_to = (DWORD)-1;
	else
		This->probably_valid_to = writecursor;

Robert Reif's avatar
Robert Reif committed
624
	if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
625
		hres = IDsDriverBuffer_Lock(This->hwbuf,
626 627 628 629
				     lplpaudioptr1, audiobytes1,
				     lplpaudioptr2, audiobytes2,
				     writecursor, writebytes,
				     0);
630 631 632 633 634 635
		if (hres != DS_OK) {
			WARN("IDsDriverBuffer_Lock failed\n");
			LeaveCriticalSection(&(This->lock));
			return hres;
		}
	} else {
636 637
		BOOL remix = FALSE;
		if (writecursor+writebytes <= This->buflen) {
638
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
639 640 641 642 643 644 645
			*audiobytes1 = writebytes;
			if (lplpaudioptr2)
				*(LPBYTE*)lplpaudioptr2 = NULL;
			if (audiobytes2)
				*audiobytes2 = 0;
			TRACE("->%ld.0\n",writebytes);
		} else {
646
			*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
647 648
			*audiobytes1 = This->buflen-writecursor;
			if (lplpaudioptr2)
649
				*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
650 651 652 653 654 655 656 657 658 659 660 661 662
			if (audiobytes2)
				*audiobytes2 = writebytes-(This->buflen-writecursor);
			TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
		}
		if (This->state == STATE_PLAYING) {
			/* if the segment between playpos and buf_mixpos is touched,
			 * we need to cancel some mixing */
			/* we'll assume that the app always calls GetCurrentPosition before
			 * locking a playing buffer, so that last_playpos is up-to-date */
			if (This->buf_mixpos >= This->last_playpos) {
				if (This->buf_mixpos > writecursor &&
				    This->last_playpos < writecursor+writebytes)
					remix = TRUE;
663
			} else {
664 665 666 667 668 669 670 671 672 673
				if (This->buf_mixpos > writecursor ||
				    This->last_playpos < writecursor+writebytes)
					remix = TRUE;
			}
			if (remix) {
				TRACE("locking prebuffered region, ouch\n");
				DSOUND_MixCancelAt(This, writecursor);
			}
		}
	}
674 675

	LeaveCriticalSection(&(This->lock));
676

677 678 679 680 681 682
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
) {
683
	HRESULT hres = DS_OK;
684
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
685 686 687 688 689
	TRACE("(%p,%ld)\n",This,newpos);

	/* **** */
	EnterCriticalSection(&(This->lock));

690
	newpos %= This->buflen;
691
	This->buf_mixpos = newpos;
692 693 694 695 696
	if (This->hwbuf) {
		hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
		if (hres != DS_OK)
			WARN("IDsDriverBuffer_SetPosition failed\n");
	}
697 698 699 700

	LeaveCriticalSection(&(This->lock));
	/* **** */

701
	return hres;
702 703 704 705 706
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
	LPDIRECTSOUNDBUFFER8 iface,LONG pan
) {
707
	HRESULT hres = DS_OK;
708
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
709 710 711

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

712 713
	if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
		WARN("invalid parameter: pan = %ld\n", pan);
714
		return DSERR_INVALIDPARAM;
715
	}
716 717 718

	/* You cannot use both pan and 3D controls */
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
719 720
	    (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
		WARN("control unavailable\n");
721
		return DSERR_CONTROLUNAVAIL;
722
	}
723 724 725 726

	/* **** */
	EnterCriticalSection(&(This->lock));

727 728
	if (This->volpan.lPan != pan) {
		This->volpan.lPan = pan;
729 730 731
		DSOUND_RecalcVolPan(&(This->volpan));

		if (This->hwbuf) {
732 733 734
			hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
			if (hres != DS_OK)
				WARN("IDsDriverBuffer_SetVolumePan failed\n");
735
		} else
736
			DSOUND_ForceRemix(This);
737 738 739 740 741
	}

	LeaveCriticalSection(&(This->lock));
	/* **** */

742
	return hres;
743 744 745 746 747
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
) {
748
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
749 750
	TRACE("(%p,%p)\n",This,pan);

751 752 753 754 755
	if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
		WARN("control unavailable\n");
		return DSERR_CONTROLUNAVAIL;
	}

756 757
	if (pan == NULL) {
		WARN("invalid parameter: pan = NULL\n");
758
		return DSERR_INVALIDPARAM;
759
	}
760 761 762 763 764 765 766 767 768

	*pan = This->volpan.lPan;

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
	LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
) {
769
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
770
	DWORD probably_valid_to;
771
	HRESULT hres = DS_OK;
772

773
	TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
774

775 776 777
	/* **** */
	EnterCriticalSection(&(This->lock));

Robert Reif's avatar
Robert Reif committed
778
	if (!(This->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
779
		hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
780
		if (hres != DS_OK)
781
			WARN("IDsDriverBuffer_Unlock failed\n");
782 783
	}

784 785 786 787 788 789 790 791 792 793 794
        if (hres == DS_OK) {
		if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
		else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
		probably_valid_to %= This->buflen;
		if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
		    ((This->state == STATE_STARTING) ||
		     (This->state == STATE_PLAYING)))
			/* see IDirectSoundBufferImpl_Lock */
			probably_valid_to = (DWORD)-1;
		This->probably_valid_to = probably_valid_to;
	}
795

796 797 798 799
	LeaveCriticalSection(&(This->lock));
	/* **** */

	TRACE("probably_valid_to=%ld\n", This->probably_valid_to);
800
	return hres;
801 802 803 804 805
}

static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
	LPDIRECTSOUNDBUFFER8 iface
) {
806
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
807 808 809 810 811 812 813
	FIXME("(%p):stub\n",This);
	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
) {
814
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
815 816
	TRACE("(%p,%p)\n",This,freq);

817 818
	if (freq == NULL) {
		WARN("invalid parameter: freq = NULL\n");
819
		return DSERR_INVALIDPARAM;
820
	}
821 822 823 824 825 826 827 828 829 830

	*freq = This->freq;
	TRACE("-> %ld\n", *freq);

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
) {
831
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
832 833 834 835 836 837 838
	DWORD u;

	FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);

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

839
	WARN("control unavailable\n");
840 841 842 843 844 845
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
) {
846
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
847 848 849 850 851 852 853
	DWORD u;

	FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);

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

854
	WARN("control unavailable\n");
855 856 857 858 859 860
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
	LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
) {
861
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
862 863 864

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

865
	WARN("control unavailable\n");
866 867 868 869
	return DSERR_CONTROLUNAVAIL;
}

static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
870
	LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
871
) {
872
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
873 874
	FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
	DPRINTF("Re-Init!!!\n");
875
	WARN("already initialized\n");
876 877 878 879 880 881
	return DSERR_ALREADYINITIALIZED;
}

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

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

	if (caps->dwSize < sizeof(*caps)) {
891
		WARN("invalid parameter: caps->dwSize = %ld\n",caps->dwSize);
892 893
		return DSERR_INVALIDPARAM;
	}
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913

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

	caps->dwBufferBytes = This->buflen;

	/* This value represents the speed of the "unlock" command.
	   As unlock is quite fast (it does not do anything), I put
	   4096 ko/s = 4 Mo / s */
	/* FIXME: hwbuf speed */
	caps->dwUnlockTransferRate = 4096;
	caps->dwPlayCpuOverhead = 0;

	return DS_OK;
}

static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
	LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
) {
914
	IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
915 916 917

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

918 919 920 921 922
	if (ppobj == NULL) {
		WARN("invalid parameter\n");
		return E_INVALIDARG;
	}

923 924
	*ppobj = NULL;	/* assume failure */

925 926
	if ( IsEqualGUID(riid, &IID_IUnknown) ||
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
927
	     IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
928 929 930 931 932
		if (!This->secondary)
			SecondaryBufferImpl_Create(This, &(This->secondary));
		if (This->secondary) {
			IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->secondary);
			*ppobj = This->secondary;
933 934 935 936
			return S_OK;
		}
		WARN("IID_IDirectSoundBuffer\n");
		return E_NOINTERFACE;
937 938
	}

939
	if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
940 941
		if (!This->notify)
			IDirectSoundNotifyImpl_Create(This, &(This->notify));
942 943
		if (This->notify) {
			IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
944
			*ppobj = This->notify;
945 946
			return S_OK;
		}
947
		WARN("IID_IDirectSoundNotify\n");
948
		return E_NOINTERFACE;
949 950 951 952
	}

	if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
		if (!This->ds3db)
953 954 955 956
			IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
		if (This->ds3db) {
			IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
			*ppobj = This->ds3db;
957 958
			return S_OK;
		}
959
		WARN("IID_IDirectSound3DBuffer\n");
960
		return E_NOINTERFACE;
961 962
	}

963
	if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
964
		ERR("app requested IDirectSound3DListener on secondary buffer\n");
965
		return E_NOINTERFACE;
966 967 968
	}

	if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
969 970 971 972 973 974
		if (!This->iks)
			IKsBufferPropertySetImpl_Create(This, &(This->iks));
		if (This->iks) {
			IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
	    		*ppobj = This->iks;
			return S_OK;
975
		}
976
		WARN("IID_IKsPropertySet\n");
977
		return E_NOINTERFACE;
978 979
	}

980 981 982 983 984
	FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );

	return E_NOINTERFACE;
}

985
static const IDirectSoundBuffer8Vtbl dsbvt =
986 987 988 989 990 991 992 993 994
{
	IDirectSoundBufferImpl_QueryInterface,
	IDirectSoundBufferImpl_AddRef,
	IDirectSoundBufferImpl_Release,
	IDirectSoundBufferImpl_GetCaps,
	IDirectSoundBufferImpl_GetCurrentPosition,
	IDirectSoundBufferImpl_GetFormat,
	IDirectSoundBufferImpl_GetVolume,
	IDirectSoundBufferImpl_GetPan,
995
	IDirectSoundBufferImpl_GetFrequency,
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
	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
};

1013
HRESULT IDirectSoundBufferImpl_Create(
Robert Reif's avatar
Robert Reif committed
1014
	DirectSoundDevice * device,
1015
	IDirectSoundBufferImpl **pdsb,
1016
	LPCDSBUFFERDESC dsbd)
1017 1018 1019 1020 1021
{
	IDirectSoundBufferImpl *dsb;
	LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
	HRESULT err = DS_OK;
	DWORD capf = 0;
1022
	int use_hw, alloc_size, cp_size;
Robert Reif's avatar
Robert Reif committed
1023
	TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
1024 1025

	if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1026
		WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1027
		*pdsb = NULL;
1028 1029 1030
		return DSERR_INVALIDPARAM; /* FIXME: which error? */
	}

1031
	dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1032 1033 1034 1035 1036 1037

	if (dsb == 0) {
		WARN("out of memory\n");
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}
1038 1039 1040

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

1041
	dsb->ref = 0;
1042
	dsb->secondary = 0;
Robert Reif's avatar
Robert Reif committed
1043
	dsb->device = device;
1044
	dsb->lpVtbl = &dsbvt;
1045
	dsb->iks = NULL;
1046

1047
	/* size depends on version */
1048
	CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1049

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
	/* variable sized struct so calculate size based on format */
	if (wfex->wFormatTag == WAVE_FORMAT_PCM) {
		alloc_size = sizeof(WAVEFORMATEX);
		cp_size = sizeof(PCMWAVEFORMAT);
	} else 
		alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize;

	dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size);
	if (dsb->pwfx == NULL) {
		WARN("out of memory\n");
		HeapFree(GetProcessHeap(),0,dsb);
		*pdsb = NULL;
		return DSERR_OUTOFMEMORY;
	}

1065
	CopyMemory(dsb->pwfx, wfex, cp_size);
1066

1067 1068 1069 1070 1071 1072
	if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
		dsb->buflen = dsbd->dwBufferBytes + 
			(dsbd->lpwfxFormat->nBlockAlign - 
			(dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
	else
		dsb->buflen = dsbd->dwBufferBytes;
1073

1074
	dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1075 1076 1077 1078 1079
	dsb->notify = NULL;
	dsb->notifies = NULL;
	dsb->nrofnotifies = 0;
	dsb->hwnotify = 0;

1080 1081 1082 1083 1084
	/* 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;
1085

Robert Reif's avatar
Robert Reif committed
1086 1087
	use_hw = (device->drvcaps.dwFlags & capf) == capf;
	TRACE("use_hw = 0x%08x, capf = 0x%08lx, device->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, device->drvcaps.dwFlags);
1088 1089 1090 1091 1092 1093

	/* 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 */

1094 1095 1096 1097 1098 1099 1100 1101 1102
	/* 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;
	}
1103

1104
	/* Allocate system memory for buffer if applicable */
Robert Reif's avatar
Robert Reif committed
1105
	if ((device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1106
		dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1107 1108
		if (dsb->buffer->memory == NULL) {
			WARN("out of memory\n");
1109
			HeapFree(GetProcessHeap(),0,dsb->pwfx);
1110 1111 1112 1113 1114
			HeapFree(GetProcessHeap(),0,dsb->buffer);
			HeapFree(GetProcessHeap(),0,dsb);
			*pdsb = NULL;
			return DSERR_OUTOFMEMORY;
		}
1115
		dsb->buffer->ref = 1;
1116
		FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1117 1118 1119
	}

	/* Allocate the hardware buffer */
1120
	if (use_hw) {
Robert Reif's avatar
Robert Reif committed
1121
		err = IDsDriver_CreateSoundBuffer(device->driver,wfex,dsbd->dwFlags,0,
1122
						  &(dsb->buflen),&(dsb->buffer->memory),
1123
						  (LPVOID*)&(dsb->hwbuf));
1124
                /* fall back to software buffer on failure */
1125
		if (err != DS_OK) {
1126 1127
			TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
			use_hw = 0;
Robert Reif's avatar
Robert Reif committed
1128
			if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1129
				dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1130 1131 1132
				if (dsb->buffer->memory == NULL) {
					WARN("out of memory\n");
					HeapFree(GetProcessHeap(),0,dsb->buffer);
1133
					HeapFree(GetProcessHeap(),0,dsb->pwfx);
1134 1135 1136 1137 1138
					HeapFree(GetProcessHeap(),0,dsb);
					*pdsb = NULL;
					return DSERR_OUTOFMEMORY;
				}
				dsb->buffer->ref = 1;
1139
				FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1140
			}
1141
			err = DS_OK;
1142
		}
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
	}

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

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

	dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
Robert Reif's avatar
Robert Reif committed
1155
		device->pwfx->nSamplesPerSec;
1156 1157 1158
	dsb->nAvgBytesPerSec = dsb->freq *
		dsbd->lpwfxFormat->nBlockAlign;

1159 1160
	if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
		dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1161 1162 1163 1164 1165 1166
		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;
1167 1168
		dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
		dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1169 1170 1171
		dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
		dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1172 1173 1174 1175 1176 1177 1178
		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);
1179
	} else
1180 1181 1182
		DSOUND_RecalcVolPan(&(dsb->volpan));

	InitializeCriticalSection(&(dsb->lock));
1183
        dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";
1184

1185
	/* register buffer if not primary */
1186
	if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1187
		err = DirectSoundDevice_AddBuffer(device, dsb);
1188
		if (err != DS_OK) {
1189 1190
			HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
			HeapFree(GetProcessHeap(),0,dsb->buffer);
1191
        		dsb->lock.DebugInfo->Spare[0] = 0;
1192
			DeleteCriticalSection(&(dsb->lock));
1193
			HeapFree(GetProcessHeap(),0,dsb->pwfx);
1194
			HeapFree(GetProcessHeap(),0,dsb);
1195
			dsb = NULL;
1196 1197
		}
	}
1198

1199
	*pdsb = dsb;
1200
	return err;
1201
}
1202

1203
HRESULT IDirectSoundBufferImpl_Destroy(
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
    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;
    }

1230
    if (pdsb->secondary) {
1231
        WARN("dsb not NULL\n");
1232 1233
        SecondaryBufferImpl_Destroy(pdsb->secondary);
        pdsb->secondary = NULL;
1234 1235 1236 1237 1238 1239 1240
    }

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

    return S_OK;
}

1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
HRESULT IDirectSoundBufferImpl_Duplicate(
    DirectSoundDevice *device,
    IDirectSoundBufferImpl **ppdsb,
    IDirectSoundBufferImpl *pdsb)
{
    IDirectSoundBufferImpl *dsb;
    HRESULT hres = DS_OK;
    int size;
    TRACE("(%p,%p,%p)\n", device, pdsb, pdsb);

    dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));

    if (dsb == NULL) {
        WARN("out of memory\n");
        *ppdsb = NULL;
        return DSERR_OUTOFMEMORY;
    }

    CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl));

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

        hres = IDsDriver_DuplicateSoundBuffer(device->driver, pdsb->hwbuf,
                                              (LPVOID *)&dsb->hwbuf);
        if (hres != DS_OK) {
            TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to "
                  "software buffer\n");
            dsb->hwbuf = NULL;
            /* allocate buffer */
            if (device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
                dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
                if (dsb->buffer == NULL) {
                    WARN("out of memory\n");
                    HeapFree(GetProcessHeap(),0,dsb);
                    *ppdsb = NULL;
                    return DSERR_OUTOFMEMORY;
                }

                dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
                if (dsb->buffer->memory == NULL) {
                    WARN("out of memory\n");
                    HeapFree(GetProcessHeap(),0,dsb->buffer);
                    HeapFree(GetProcessHeap(),0,dsb);
                    *ppdsb = NULL;
                    return DSERR_OUTOFMEMORY;
                }
                dsb->buffer->ref = 1;

                /* FIXME: copy buffer ? */
            }
        }
    } else {
        dsb->hwbuf = NULL;
        dsb->buffer->ref++;
    }

    dsb->ref = 0;
    dsb->state = STATE_STOPPED;
    dsb->playpos = 0;
    dsb->buf_mixpos = 0;
    dsb->device = device;
    dsb->ds3db = NULL;
    dsb->iks = NULL; /* FIXME? */
    dsb->secondary = NULL;

    /* variable sized struct so calculate size based on format */
    size = sizeof(WAVEFORMATEX) + pdsb->pwfx->cbSize;

    dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
    if (dsb->pwfx == NULL) {
            WARN("out of memory\n");
            HeapFree(GetProcessHeap(),0,dsb->buffer);
            HeapFree(GetProcessHeap(),0,dsb);
            *ppdsb = NULL;
            return DSERR_OUTOFMEMORY;
    }

    CopyMemory(dsb->pwfx, pdsb->pwfx, size);

    InitializeCriticalSection(&(dsb->lock));
    dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock";

    /* register buffer */
    hres = DirectSoundDevice_AddBuffer(device, dsb);
    if (hres != DS_OK) {
        dsb->lock.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&(dsb->lock));
        HeapFree(GetProcessHeap(),0,dsb->buffer);
        HeapFree(GetProcessHeap(),0,dsb->pwfx);
        HeapFree(GetProcessHeap(),0,dsb);
        *ppdsb = 0;
    }

    *ppdsb = dsb;
    return hres;
}

1339 1340 1341 1342 1343
/*******************************************************************************
 *		SecondaryBuffer
 */

static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1344
	LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1345
{
1346
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1347 1348 1349 1350 1351
	TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);

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

1352
static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1353
{
1354
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1355 1356 1357
    ULONG ref = InterlockedIncrement(&(This->ref));
    TRACE("(%p) ref was %ld\n", This, ref - 1);
    return ref;
1358 1359
}

1360
static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1361
{
1362
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
Robert Reif's avatar
Robert Reif committed
1363 1364 1365 1366
    ULONG ref;
    TRACE("(%p)\n", This);
    ref = InterlockedDecrement(&(This->ref));
    TRACE("ref was %ld\n", ref + 1);
1367 1368

    if (!ref) {
1369
        This->dsb->secondary = NULL;
1370 1371 1372 1373 1374
        IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
        HeapFree(GetProcessHeap(), 0, This);
        TRACE("(%p) released\n", This);
    }
    return ref;
1375 1376 1377 1378 1379
}

static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
	LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
{
1380
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1381 1382 1383 1384 1385 1386 1387 1388
  	TRACE("(%p)->(%p)\n",This,caps);

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

static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
{
1389
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1390 1391 1392 1393 1394 1395 1396 1397
	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)
{
1398
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1399 1400 1401 1402 1403 1404 1405 1406
	TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);

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

static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
{
1407
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1408 1409 1410 1411 1412 1413 1414 1415
	TRACE("(%p,%p)\n",This,vol);

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

static HRESULT WINAPI SecondaryBufferImpl_GetPan(
	LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
{
1416
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1417 1418 1419 1420 1421 1422 1423 1424
	TRACE("(%p,%p)\n",This,pan);

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

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

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

static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
	LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
{
1434
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1435 1436 1437 1438 1439 1440
	TRACE("(%p,%p)\n",This,status);

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

static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1441
	LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1442
{
1443
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1444 1445 1446 1447 1448 1449
	TRACE("(%p,%p,%p)\n",This,dsound,dbsd);

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

static HRESULT WINAPI SecondaryBufferImpl_Lock(
1450 1451 1452 1453 1454 1455 1456 1457
    LPDIRECTSOUNDBUFFER8 iface,
    DWORD writecursor,
    DWORD writebytes,
    LPVOID lplpaudioptr1,
    LPDWORD audiobytes1,
    LPVOID lplpaudioptr2,
    LPDWORD audiobytes2,
    DWORD dwFlags)
1458
{
1459
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1460 1461
    TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
        This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1462

1463 1464
    return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
        writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1465 1466 1467 1468 1469
}

static HRESULT WINAPI SecondaryBufferImpl_Play(
	LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
{
1470
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1471 1472 1473 1474 1475 1476 1477 1478
	TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);

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

static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
	LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
{
1479
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1480 1481 1482 1483 1484 1485
	TRACE("(%p,%ld)\n",This,newpos);

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

static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1486
	LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1487
{
1488
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1489 1490 1491 1492 1493 1494 1495 1496
	TRACE("(%p,%p)\n",This,wfex);

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

static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
	LPDIRECTSOUNDBUFFER8 iface,LONG vol)
{
1497
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1498 1499 1500 1501 1502 1503 1504 1505
	TRACE("(%p,%ld)\n",This,vol);

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

static HRESULT WINAPI SecondaryBufferImpl_SetPan(
	LPDIRECTSOUNDBUFFER8 iface,LONG pan)
{
1506
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1507 1508 1509 1510 1511 1512 1513 1514
	TRACE("(%p,%ld)\n",This,pan);

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

static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
	LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
{
1515
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1516 1517 1518 1519 1520 1521 1522
	TRACE("(%p,%ld)\n",This,freq);

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

static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
{
1523
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1524 1525 1526 1527 1528 1529
	TRACE("(%p)\n",This);

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

static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1530 1531 1532 1533 1534
    LPDIRECTSOUNDBUFFER8 iface,
    LPVOID lpvAudioPtr1,
    DWORD dwAudioBytes1,
    LPVOID lpvAudioPtr2,
    DWORD dwAudioBytes2)
1535
{
1536
    SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1537 1538
    TRACE("(%p,%p,%ld,%p,%ld)\n",
        This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1539

1540 1541
    return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
        lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1542 1543 1544 1545 1546
}

static HRESULT WINAPI SecondaryBufferImpl_Restore(
	LPDIRECTSOUNDBUFFER8 iface)
{
1547
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1548 1549 1550 1551 1552 1553 1554 1555
	TRACE("(%p)\n",This);

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

static HRESULT WINAPI SecondaryBufferImpl_SetFX(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
{
1556
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1557 1558 1559 1560 1561 1562 1563 1564
	TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);

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

static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
	LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
{
1565
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1566 1567 1568 1569 1570 1571 1572 1573
	TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);

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

static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
	LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
{
1574
	SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface;
1575 1576 1577 1578 1579
	TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);

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

1580
static const IDirectSoundBuffer8Vtbl sbvt =
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
{
	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
};

1608
HRESULT SecondaryBufferImpl_Create(
1609 1610 1611 1612 1613 1614
	IDirectSoundBufferImpl *dsb,
	SecondaryBufferImpl **psb)
{
	SecondaryBufferImpl *sb;
	TRACE("(%p,%p)\n",dsb,psb);

1615
	sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629

	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;
}
1630

1631
static HRESULT SecondaryBufferImpl_Destroy(
1632 1633 1634 1635 1636 1637 1638 1639
    SecondaryBufferImpl *pdsb)
{
    TRACE("(%p)\n",pdsb);

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

    return S_OK;
}