Delete buffer array when releasing last buffer.
[wine/dcerpc.git] / dlls / dsound / buffer.c
blob16a9c639bb34fa5a7113844149c5140ffa50e549
1 /* DirectSound
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998 Rob Riggs
5 * Copyright 2000-2002 TransGaming Technologies, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <sys/fcntl.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
35 #define NONAMELESSSTRUCT
36 #define NONAMELESSUNION
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "winerror.h"
42 #include "mmsystem.h"
43 #include "winreg.h"
44 #include "winternl.h"
45 #include "mmddk.h"
46 #include "wine/windef16.h"
47 #include "wine/debug.h"
48 #include "dsound.h"
49 #include "dsdriver.h"
50 #include "dsound_private.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
54 /*******************************************************************************
55 * IDirectSoundNotify
57 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
58 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
59 ) {
60 ICOM_THIS(IDirectSoundNotifyImpl,iface);
61 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
63 if (This->dsb == NULL) {
64 WARN("invalid parameter\n");
65 return E_INVALIDARG;
68 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
71 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) {
72 ICOM_THIS(IDirectSoundNotifyImpl,iface);
73 DWORD ref;
75 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
77 ref = InterlockedIncrement(&(This->ref));
78 return ref;
81 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) {
82 ICOM_THIS(IDirectSoundNotifyImpl,iface);
83 DWORD ref;
85 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
87 ref = InterlockedDecrement(&(This->ref));
88 if (ref == 0) {
89 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
90 This->dsb->notify = NULL;
91 HeapFree(GetProcessHeap(),0,This);
92 TRACE("(%p) released\n",This);
94 return ref;
97 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
98 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
99 ) {
100 ICOM_THIS(IDirectSoundNotifyImpl,iface);
101 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
103 if (howmuch > 0 && notify == NULL) {
104 WARN("invalid parameter: notify == NULL\n");
105 return DSERR_INVALIDPARAM;
108 if (TRACE_ON(dsound)) {
109 int i;
110 for (i=0;i<howmuch;i++)
111 TRACE("notify at %ld to 0x%08lx\n",
112 notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
115 if (This->dsb->hwnotify) {
116 HRESULT hres;
117 hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify);
118 if (hres != DS_OK)
119 WARN("IDsDriverNotify_SetNotificationPositions failed\n");
120 return hres;
121 } else if (howmuch > 0) {
122 /* Make an internal copy of the caller-supplied array.
123 * Replace the existing copy if one is already present. */
124 if (This->dsb->notifies)
125 This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
126 This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY));
127 else
128 This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
129 howmuch * sizeof(DSBPOSITIONNOTIFY));
131 if (This->dsb->notifies == NULL) {
132 WARN("out of memory\n");
133 return DSERR_OUTOFMEMORY;
135 memcpy(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
136 This->dsb->nrofnotifies = howmuch;
137 } else {
138 if (This->dsb->notifies) {
139 HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
140 This->dsb->notifies = NULL;
142 This->dsb->nrofnotifies = 0;
145 return S_OK;
148 IDirectSoundNotifyVtbl dsnvt =
150 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
151 IDirectSoundNotifyImpl_QueryInterface,
152 IDirectSoundNotifyImpl_AddRef,
153 IDirectSoundNotifyImpl_Release,
154 IDirectSoundNotifyImpl_SetNotificationPositions,
157 HRESULT WINAPI IDirectSoundNotifyImpl_Create(
158 IDirectSoundBufferImpl * dsb,
159 IDirectSoundNotifyImpl **pdsn)
161 IDirectSoundNotifyImpl * dsn;
162 TRACE("(%p,%p)\n",dsb,pdsn);
164 dsn = (IDirectSoundNotifyImpl*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn));
166 if (dsn == NULL) {
167 WARN("out of memory\n");
168 return DSERR_OUTOFMEMORY;
171 dsn->ref = 0;
172 dsn->lpVtbl = &dsnvt;
173 dsn->dsb = dsb;
174 dsb->notify = dsn;
175 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
177 *pdsn = dsn;
178 return DS_OK;
181 HRESULT WINAPI IDirectSoundNotifyImpl_Destroy(
182 IDirectSoundNotifyImpl *pdsn)
184 TRACE("(%p)\n",pdsn);
186 while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
188 return DS_OK;
191 /*******************************************************************************
192 * IDirectSoundBuffer
195 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
196 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex
198 ICOM_THIS(IDirectSoundBufferImpl,iface);
200 TRACE("(%p,%p)\n",This,wfex);
201 /* This method is not available on secondary buffers */
202 WARN("invalid call\n");
203 return DSERR_INVALIDCALL;
206 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(
207 LPDIRECTSOUNDBUFFER8 iface,LONG vol
209 ICOM_THIS(IDirectSoundBufferImpl,iface);
210 LONG oldVol;
212 TRACE("(%p,%ld)\n",This,vol);
214 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
215 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
216 return DSERR_CONTROLUNAVAIL;
219 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
220 WARN("invalid parameter: vol = %ld\n", vol);
221 return DSERR_INVALIDPARAM;
224 /* **** */
225 EnterCriticalSection(&(This->lock));
227 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
228 oldVol = This->ds3db_lVolume;
229 This->ds3db_lVolume = vol;
230 } else {
231 oldVol = This->volpan.lVolume;
232 This->volpan.lVolume = vol;
233 if (vol != oldVol)
234 DSOUND_RecalcVolPan(&(This->volpan));
237 if (vol != oldVol) {
238 if (This->hwbuf) {
239 HRESULT hres;
240 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
241 if (hres != DS_OK)
242 WARN("IDsDriverBuffer_SetVolumePan failed\n");
243 } else
244 DSOUND_ForceRemix(This);
247 LeaveCriticalSection(&(This->lock));
248 /* **** */
250 return DS_OK;
253 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(
254 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol
256 ICOM_THIS(IDirectSoundBufferImpl,iface);
257 TRACE("(%p,%p)\n",This,vol);
259 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
260 WARN("control unavailable\n");
261 return DSERR_CONTROLUNAVAIL;
264 if (vol == NULL) {
265 WARN("invalid parameter: vol == NULL\n");
266 return DSERR_INVALIDPARAM;
269 *vol = This->volpan.lVolume;
271 return DS_OK;
274 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(
275 LPDIRECTSOUNDBUFFER8 iface,DWORD freq
277 ICOM_THIS(IDirectSoundBufferImpl,iface);
278 DWORD oldFreq;
280 TRACE("(%p,%ld)\n",This,freq);
282 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
283 WARN("control unavailable\n");
284 return DSERR_CONTROLUNAVAIL;
287 if (freq == DSBFREQUENCY_ORIGINAL)
288 freq = This->wfx.nSamplesPerSec;
290 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
291 WARN("invalid parameter: freq = %ld\n", freq);
292 return DSERR_INVALIDPARAM;
295 /* **** */
296 EnterCriticalSection(&(This->lock));
298 oldFreq = This->freq;
299 This->freq = freq;
300 if (freq != oldFreq) {
301 This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->wfx.nSamplesPerSec;
302 This->nAvgBytesPerSec = freq * This->wfx.nBlockAlign;
303 DSOUND_RecalcFormat(This);
304 if (!This->hwbuf)
305 DSOUND_ForceRemix(This);
308 LeaveCriticalSection(&(This->lock));
309 /* **** */
311 return DS_OK;
314 static HRESULT WINAPI IDirectSoundBufferImpl_Play(
315 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags
317 HRESULT hres = DS_OK;
318 ICOM_THIS(IDirectSoundBufferImpl,iface);
319 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
321 /* **** */
322 EnterCriticalSection(&(This->lock));
324 This->playflags = flags;
325 if (This->state == STATE_STOPPED) {
326 This->leadin = TRUE;
327 This->startpos = This->buf_mixpos;
328 This->state = STATE_STARTING;
329 } else if (This->state == STATE_STOPPING)
330 This->state = STATE_PLAYING;
331 if (This->hwbuf) {
332 hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags);
333 if (hres != DS_OK)
334 WARN("IDsDriverBuffer_Play failed\n");
335 else
336 This->state = STATE_PLAYING;
339 LeaveCriticalSection(&(This->lock));
340 /* **** */
342 return hres;
345 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
347 HRESULT hres = DS_OK;
348 ICOM_THIS(IDirectSoundBufferImpl,iface);
349 TRACE("(%p)\n",This);
351 /* **** */
352 EnterCriticalSection(&(This->lock));
354 if (This->state == STATE_PLAYING)
355 This->state = STATE_STOPPING;
356 else if (This->state == STATE_STARTING)
357 This->state = STATE_STOPPED;
358 if (This->hwbuf) {
359 hres = IDsDriverBuffer_Stop(This->hwbuf);
360 if (hres != DS_OK)
361 WARN("IDsDriverBuffer_Stop failed\n");
362 else
363 This->state = STATE_STOPPED;
365 DSOUND_CheckEvent(This, 0);
367 LeaveCriticalSection(&(This->lock));
368 /* **** */
370 return hres;
373 static DWORD WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) {
374 ICOM_THIS(IDirectSoundBufferImpl,iface);
375 DWORD ref;
377 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
379 ref = InterlockedIncrement(&(This->ref));
380 if (!ref) {
381 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
383 return ref;
386 static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) {
387 ICOM_THIS(IDirectSoundBufferImpl,iface);
388 int i;
389 DWORD ref;
391 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
393 ref = InterlockedDecrement(&(This->ref));
394 if (ref) return ref;
396 RtlAcquireResourceExclusive(&(This->dsound->lock), TRUE);
397 for (i=0;i<This->dsound->nrofbuffers;i++)
398 if (This->dsound->buffers[i] == This)
399 break;
400 if (i < This->dsound->nrofbuffers) {
401 /* Put the last buffer of the list in the (now empty) position */
402 This->dsound->buffers[i] = This->dsound->buffers[This->dsound->nrofbuffers - 1];
403 This->dsound->nrofbuffers--;
404 This->dsound->buffers = HeapReAlloc(GetProcessHeap(),0,This->dsound->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*This->dsound->nrofbuffers);
405 TRACE("(%p) buffer count is now %d\n", This, This->dsound->nrofbuffers);
407 if (This->dsound->nrofbuffers == 0) {
408 HeapFree(GetProcessHeap(),0,This->dsound->buffers);
409 This->dsound->buffers = NULL;
411 RtlReleaseResource(&(This->dsound->lock));
413 DeleteCriticalSection(&(This->lock));
415 if (This->hwbuf) {
416 IDsDriverBuffer_Release(This->hwbuf);
417 if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
418 This->buffer->ref--;
419 if (This->buffer->ref==0) {
420 HeapFree(GetProcessHeap(),0,This->buffer->memory);
421 HeapFree(GetProcessHeap(),0,This->buffer);
424 } else {
425 This->buffer->ref--;
426 if (This->buffer->ref==0) {
427 HeapFree(GetProcessHeap(),0,This->buffer->memory);
428 HeapFree(GetProcessHeap(),0,This->buffer);
432 if (This->notifies != NULL)
433 HeapFree(GetProcessHeap(), 0, This->notifies);
435 HeapFree(GetProcessHeap(),0,This);
437 TRACE("(%p) released\n",This);
438 return 0;
441 DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
442 DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
444 DWORD bplay;
446 TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix);
447 TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount());
449 /* the actual primary play position (pplay) is always behind last mixed (pmix),
450 * unless the computer is too slow or something */
451 /* we need to know how far away we are from there */
452 #if 0 /* we'll never fill the primary entirely */
453 if (pmix == pplay) {
454 if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) {
455 /* wow, the software mixer is really doing well,
456 * seems the entire primary buffer is filled! */
457 pmix += This->dsound->buflen;
459 /* else: the primary buffer is not playing, so probably empty */
461 #endif
462 if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */
463 pmix -= pplay;
464 /* detect buffer underrun */
465 if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */
466 pwrite -= pplay;
467 if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) {
468 WARN("detected an underrun: primary queue was %ld\n",pmix);
469 pmix = 0;
471 /* divide the offset by its sample size */
472 pmix /= This->dsound->wfx.nBlockAlign;
473 TRACE("primary back-samples=%ld\n",pmix);
474 /* adjust for our frequency */
475 pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT;
476 /* multiply by our own sample size */
477 pmix *= This->wfx.nBlockAlign;
478 TRACE("this back-offset=%ld\n", pmix);
479 /* subtract from our last mixed position */
480 bplay = bmix;
481 while (bplay < pmix) bplay += This->buflen; /* wraparound */
482 bplay -= pmix;
483 if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) {
484 /* seems we haven't started playing yet */
485 TRACE("this still in lead-in phase\n");
486 bplay = This->startpos;
488 /* return the result */
489 return bplay;
492 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
493 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos
495 HRESULT hres;
496 ICOM_THIS(IDirectSoundBufferImpl,iface);
497 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
498 if (This->hwbuf) {
499 hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos);
500 if (hres != DS_OK) {
501 WARN("IDsDriverBuffer_GetPosition failed\n");
502 return hres;
505 else {
506 if (playpos && (This->state != STATE_PLAYING)) {
507 /* we haven't been merged into the primary buffer (yet) */
508 *playpos = This->buf_mixpos;
510 else if (playpos) {
511 DWORD pplay, pwrite, lplay, splay, pstate;
512 /* let's get this exact; first, recursively call GetPosition on the primary */
513 EnterCriticalSection(&(This->dsound->mixlock));
514 if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK)
515 WARN("DSOUND_PrimaryGetPosition failed\n");
516 /* detect HEL mode underrun */
517 pstate = This->dsound->state;
518 if (!(This->dsound->hwbuf || This->dsound->pwqueue)) {
519 TRACE("detected an underrun\n");
520 /* pplay = ? */
521 if (pstate == STATE_PLAYING)
522 pstate = STATE_STARTING;
523 else if (pstate == STATE_STOPPING)
524 pstate = STATE_STOPPED;
526 /* get data for ourselves while we still have the lock */
527 pstate &= This->state;
528 lplay = This->primary_mixpos;
529 splay = This->buf_mixpos;
530 if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) {
531 /* calculate play position using this */
532 *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
533 } else {
534 /* (unless the app isn't using GETCURRENTPOSITION2) */
535 /* don't know exactly how this should be handled...
536 * the docs says that play cursor is reported as directly
537 * behind write cursor, hmm... */
538 /* let's just do what might work for Half-Life */
539 DWORD wp;
540 wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen;
541 while (wp >= This->dsound->buflen)
542 wp -= This->dsound->buflen;
543 *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay);
545 LeaveCriticalSection(&(This->dsound->mixlock));
547 if (writepos) *writepos = This->buf_mixpos;
549 if (writepos) {
550 if (This->state != STATE_STOPPED)
551 /* apply the documented 10ms lead to writepos */
552 *writepos += This->writelead;
553 while (*writepos >= This->buflen) *writepos -= This->buflen;
555 if (playpos) This->last_playpos = *playpos;
556 TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount());
557 return DS_OK;
560 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(
561 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status
563 ICOM_THIS(IDirectSoundBufferImpl,iface);
564 TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId());
566 if (status == NULL) {
567 WARN("invalid parameter: status = NULL\n");
568 return DSERR_INVALIDPARAM;
571 *status = 0;
572 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
573 *status |= DSBSTATUS_PLAYING;
574 if (This->playflags & DSBPLAY_LOOPING)
575 *status |= DSBSTATUS_LOOPING;
578 TRACE("status=%lx\n", *status);
579 return DS_OK;
583 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(
584 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
586 ICOM_THIS(IDirectSoundBufferImpl,iface);
587 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
589 if (wfsize>sizeof(This->wfx))
590 wfsize = sizeof(This->wfx);
591 if (lpwf) { /* NULL is valid */
592 memcpy(lpwf,&(This->wfx),wfsize);
593 if (wfwritten)
594 *wfwritten = wfsize;
595 } else {
596 if (wfwritten)
597 *wfwritten = sizeof(This->wfx);
598 else {
599 WARN("invalid parameter: wfwritten == NULL\n");
600 return DSERR_INVALIDPARAM;
604 return DS_OK;
607 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(
608 LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags
610 HRESULT hres = DS_OK;
611 ICOM_THIS(IDirectSoundBufferImpl,iface);
613 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n",
614 This,
615 writecursor,
616 writebytes,
617 lplpaudioptr1,
618 audiobytes1,
619 lplpaudioptr2,
620 audiobytes2,
621 flags,
622 GetTickCount()
625 if (flags & DSBLOCK_FROMWRITECURSOR) {
626 DWORD writepos;
627 /* GetCurrentPosition does too much magic to duplicate here */
628 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos);
629 if (hres != DS_OK) {
630 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
631 return hres;
633 writecursor += writepos;
635 while (writecursor >= This->buflen)
636 writecursor -= This->buflen;
637 if (flags & DSBLOCK_ENTIREBUFFER)
638 writebytes = This->buflen;
639 if (writebytes > This->buflen)
640 writebytes = This->buflen;
642 EnterCriticalSection(&(This->lock));
644 if ((writebytes == This->buflen) &&
645 ((This->state == STATE_STARTING) ||
646 (This->state == STATE_PLAYING)))
647 /* some games, like Half-Life, try to be clever (not) and
648 * keep one secondary buffer, and mix sounds into it itself,
649 * locking the entire buffer every time... so we can just forget
650 * about tracking the last-written-to-position... */
651 This->probably_valid_to = (DWORD)-1;
652 else
653 This->probably_valid_to = writecursor;
655 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
656 hres = IDsDriverBuffer_Lock(This->hwbuf,
657 lplpaudioptr1, audiobytes1,
658 lplpaudioptr2, audiobytes2,
659 writecursor, writebytes,
661 if (hres != DS_OK) {
662 WARN("IDsDriverBuffer_Lock failed\n");
663 LeaveCriticalSection(&(This->lock));
664 return hres;
666 } else {
667 BOOL remix = FALSE;
668 if (writecursor+writebytes <= This->buflen) {
669 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
670 *audiobytes1 = writebytes;
671 if (lplpaudioptr2)
672 *(LPBYTE*)lplpaudioptr2 = NULL;
673 if (audiobytes2)
674 *audiobytes2 = 0;
675 TRACE("->%ld.0\n",writebytes);
676 } else {
677 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
678 *audiobytes1 = This->buflen-writecursor;
679 if (lplpaudioptr2)
680 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
681 if (audiobytes2)
682 *audiobytes2 = writebytes-(This->buflen-writecursor);
683 TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0);
685 if (This->state == STATE_PLAYING) {
686 /* if the segment between playpos and buf_mixpos is touched,
687 * we need to cancel some mixing */
688 /* we'll assume that the app always calls GetCurrentPosition before
689 * locking a playing buffer, so that last_playpos is up-to-date */
690 if (This->buf_mixpos >= This->last_playpos) {
691 if (This->buf_mixpos > writecursor &&
692 This->last_playpos < writecursor+writebytes)
693 remix = TRUE;
695 else {
696 if (This->buf_mixpos > writecursor ||
697 This->last_playpos < writecursor+writebytes)
698 remix = TRUE;
700 if (remix) {
701 TRACE("locking prebuffered region, ouch\n");
702 DSOUND_MixCancelAt(This, writecursor);
707 LeaveCriticalSection(&(This->lock));
708 return DS_OK;
711 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(
712 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos
714 HRESULT hres = DS_OK;
715 ICOM_THIS(IDirectSoundBufferImpl,iface);
716 TRACE("(%p,%ld)\n",This,newpos);
718 /* **** */
719 EnterCriticalSection(&(This->lock));
721 while (newpos >= This->buflen)
722 newpos -= This->buflen;
723 This->buf_mixpos = newpos;
724 if (This->hwbuf) {
725 hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos);
726 if (hres != DS_OK)
727 WARN("IDsDriverBuffer_SetPosition failed\n");
730 LeaveCriticalSection(&(This->lock));
731 /* **** */
733 return hres;
736 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(
737 LPDIRECTSOUNDBUFFER8 iface,LONG pan
739 HRESULT hres = DS_OK;
740 ICOM_THIS(IDirectSoundBufferImpl,iface);
742 TRACE("(%p,%ld)\n",This,pan);
744 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
745 WARN("invalid parameter: pan = %ld\n", pan);
746 return DSERR_INVALIDPARAM;
749 /* You cannot use both pan and 3D controls */
750 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
751 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
752 WARN("control unavailable\n");
753 return DSERR_CONTROLUNAVAIL;
756 /* **** */
757 EnterCriticalSection(&(This->lock));
759 if (This->volpan.lPan != pan) {
760 This->volpan.lPan = pan;
761 DSOUND_RecalcVolPan(&(This->volpan));
763 if (This->hwbuf) {
764 hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan));
765 if (hres != DS_OK)
766 WARN("IDsDriverBuffer_SetVolumePan failed\n");
767 } else
768 DSOUND_ForceRemix(This);
771 LeaveCriticalSection(&(This->lock));
772 /* **** */
774 return hres;
777 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(
778 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan
780 ICOM_THIS(IDirectSoundBufferImpl,iface);
781 TRACE("(%p,%p)\n",This,pan);
783 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
784 WARN("control unavailable\n");
785 return DSERR_CONTROLUNAVAIL;
788 if (pan == NULL) {
789 WARN("invalid parameter: pan = NULL\n");
790 return DSERR_INVALIDPARAM;
793 *pan = This->volpan.lPan;
795 return DS_OK;
798 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(
799 LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
801 ICOM_THIS(IDirectSoundBufferImpl,iface);
802 DWORD probably_valid_to;
804 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
806 if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) {
807 HRESULT hres;
808 hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2);
809 if (hres != DS_OK) {
810 WARN("IDsDriverBuffer_Unlock failed\n");
811 return hres;
815 if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2;
816 else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1;
817 while (probably_valid_to >= This->buflen)
818 probably_valid_to -= This->buflen;
819 if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) &&
820 ((This->state == STATE_STARTING) ||
821 (This->state == STATE_PLAYING)))
822 /* see IDirectSoundBufferImpl_Lock */
823 probably_valid_to = (DWORD)-1;
824 This->probably_valid_to = probably_valid_to;
826 return DS_OK;
829 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(
830 LPDIRECTSOUNDBUFFER8 iface
832 ICOM_THIS(IDirectSoundBufferImpl,iface);
833 FIXME("(%p):stub\n",This);
834 return DS_OK;
837 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(
838 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq
840 ICOM_THIS(IDirectSoundBufferImpl,iface);
841 TRACE("(%p,%p)\n",This,freq);
843 if (freq == NULL) {
844 WARN("invalid parameter: freq = NULL\n");
845 return DSERR_INVALIDPARAM;
848 *freq = This->freq;
849 TRACE("-> %ld\n", *freq);
851 return DS_OK;
854 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(
855 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes
857 ICOM_THIS(IDirectSoundBufferImpl,iface);
858 DWORD u;
860 FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
862 if (pdwResultCodes)
863 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
865 WARN("control unavailable\n");
866 return DSERR_CONTROLUNAVAIL;
869 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
870 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
872 ICOM_THIS(IDirectSoundBufferImpl,iface);
873 DWORD u;
875 FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
877 if (pdwResultCodes)
878 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
880 WARN("control unavailable\n");
881 return DSERR_CONTROLUNAVAIL;
884 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
885 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
887 ICOM_THIS(IDirectSoundBufferImpl,iface);
889 FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
891 WARN("control unavailable\n");
892 return DSERR_CONTROLUNAVAIL;
895 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
896 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
898 ICOM_THIS(IDirectSoundBufferImpl,iface);
899 FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
900 DPRINTF("Re-Init!!!\n");
901 WARN("already initialized\n");
902 return DSERR_ALREADYINITIALIZED;
905 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
906 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
908 ICOM_THIS(IDirectSoundBufferImpl,iface);
909 TRACE("(%p)->(%p)\n",This,caps);
911 if (caps == NULL) {
912 WARN("invalid parameter: caps == NULL\n");
913 return DSERR_INVALIDPARAM;
916 if (caps->dwSize < sizeof(*caps)) {
917 WARN("invalid parameter: caps->dwSize = %ld < %d\n",caps->dwSize, sizeof(*caps));
918 return DSERR_INVALIDPARAM;
921 caps->dwFlags = This->dsbd.dwFlags;
922 if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE;
923 else caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
925 caps->dwBufferBytes = This->buflen;
927 /* This value represents the speed of the "unlock" command.
928 As unlock is quite fast (it does not do anything), I put
929 4096 ko/s = 4 Mo / s */
930 /* FIXME: hwbuf speed */
931 caps->dwUnlockTransferRate = 4096;
932 caps->dwPlayCpuOverhead = 0;
934 return DS_OK;
937 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(
938 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj
940 ICOM_THIS(IDirectSoundBufferImpl,iface);
942 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
944 if (ppobj == NULL) {
945 WARN("invalid parameter\n");
946 return E_INVALIDARG;
949 *ppobj = NULL; /* assume failure */
951 if ( IsEqualGUID(riid, &IID_IUnknown) ||
952 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
953 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
954 if (!This->dsb)
955 SecondaryBufferImpl_Create(This, &(This->dsb));
956 if (This->dsb) {
957 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb);
958 *ppobj = This->dsb;
959 return S_OK;
961 WARN("IID_IDirectSoundBuffer\n");
962 return E_NOINTERFACE;
965 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ||
966 IsEqualGUID( &IID_IDirectSoundNotify8, riid ) ) {
967 if (!This->notify)
968 IDirectSoundNotifyImpl_Create(This, &(This->notify));
969 if (This->notify) {
970 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
971 *ppobj = This->notify;
972 return S_OK;
974 WARN("IID_IDirectSoundNotify\n");
975 return E_NOINTERFACE;
978 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
979 if (!This->ds3db)
980 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
981 if (This->ds3db) {
982 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
983 *ppobj = This->ds3db;
984 return S_OK;
986 WARN("IID_IDirectSound3DBuffer\n");
987 return E_NOINTERFACE;
990 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
991 ERR("app requested IDirectSound3DListener on secondary buffer\n");
992 return E_NOINTERFACE;
995 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
996 /* only supported on hardware 3D secondary buffers */
997 if (!(This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) &&
998 (This->dsbd.dwFlags & DSBCAPS_CTRL3D) &&
999 (This->hwbuf != NULL) ) {
1000 if (!This->iks)
1001 IKsBufferPropertySetImpl_Create(This, &(This->iks));
1002 if (This->iks) {
1003 IKsPropertySet_AddRef((LPKSPROPERTYSET)*ppobj);
1004 *ppobj = This->iks;
1005 return S_OK;
1008 WARN("IID_IKsPropertySet\n");
1009 return E_NOINTERFACE;
1012 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1014 return E_NOINTERFACE;
1017 static IDirectSoundBuffer8Vtbl dsbvt =
1019 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1020 IDirectSoundBufferImpl_QueryInterface,
1021 IDirectSoundBufferImpl_AddRef,
1022 IDirectSoundBufferImpl_Release,
1023 IDirectSoundBufferImpl_GetCaps,
1024 IDirectSoundBufferImpl_GetCurrentPosition,
1025 IDirectSoundBufferImpl_GetFormat,
1026 IDirectSoundBufferImpl_GetVolume,
1027 IDirectSoundBufferImpl_GetPan,
1028 IDirectSoundBufferImpl_GetFrequency,
1029 IDirectSoundBufferImpl_GetStatus,
1030 IDirectSoundBufferImpl_Initialize,
1031 IDirectSoundBufferImpl_Lock,
1032 IDirectSoundBufferImpl_Play,
1033 IDirectSoundBufferImpl_SetCurrentPosition,
1034 IDirectSoundBufferImpl_SetFormat,
1035 IDirectSoundBufferImpl_SetVolume,
1036 IDirectSoundBufferImpl_SetPan,
1037 IDirectSoundBufferImpl_SetFrequency,
1038 IDirectSoundBufferImpl_Stop,
1039 IDirectSoundBufferImpl_Unlock,
1040 IDirectSoundBufferImpl_Restore,
1041 IDirectSoundBufferImpl_SetFX,
1042 IDirectSoundBufferImpl_AcquireResources,
1043 IDirectSoundBufferImpl_GetObjectInPath
1046 HRESULT WINAPI IDirectSoundBufferImpl_Create(
1047 IDirectSoundImpl *ds,
1048 IDirectSoundBufferImpl **pdsb,
1049 LPCDSBUFFERDESC dsbd)
1051 IDirectSoundBufferImpl *dsb;
1052 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1053 HRESULT err = DS_OK;
1054 DWORD capf = 0;
1055 int use_hw;
1056 TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd);
1058 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1059 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1060 *pdsb = NULL;
1061 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1064 dsb = (IDirectSoundBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1066 if (dsb == 0) {
1067 WARN("out of memory\n");
1068 *pdsb = NULL;
1069 return DSERR_OUTOFMEMORY;
1071 dsb->ref = 0;
1072 dsb->dsb = 0;
1073 dsb->dsound = ds;
1074 dsb->lpVtbl = &dsbvt;
1075 dsb->iks = NULL;
1077 memcpy(&dsb->dsbd, dsbd, sizeof(*dsbd));
1078 if (wfex)
1079 memcpy(&dsb->wfx, wfex, sizeof(dsb->wfx));
1081 TRACE("Created buffer at %p\n", dsb);
1083 dsb->buflen = dsbd->dwBufferBytes;
1084 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1086 dsb->notify = NULL;
1087 dsb->notifies = NULL;
1088 dsb->nrofnotifies = 0;
1089 dsb->hwnotify = 0;
1091 /* Check necessary hardware mixing capabilities */
1092 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1093 else capf |= DSCAPS_SECONDARYMONO;
1094 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1095 else capf |= DSCAPS_SECONDARY8BIT;
1097 use_hw = (ds->drvcaps.dwFlags & capf) == capf;
1098 TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->drvcaps.dwFlags);
1100 /* FIXME: check hardware sample rate mixing capabilities */
1101 /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */
1102 /* FIXME: check whether any hardware buffers are left */
1103 /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */
1105 /* Allocate system memory if applicable */
1106 if ((ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) {
1107 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1108 if (dsb->buffer == NULL) {
1109 WARN("out of memory\n");
1110 HeapFree(GetProcessHeap(),0,dsb);
1111 *pdsb = NULL;
1112 return DSERR_OUTOFMEMORY;
1115 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1116 if (dsb->buffer->memory == NULL) {
1117 WARN("out of memory\n");
1118 HeapFree(GetProcessHeap(),0,dsb->buffer);
1119 HeapFree(GetProcessHeap(),0,dsb);
1120 *pdsb = NULL;
1121 return DSERR_OUTOFMEMORY;
1123 dsb->buffer->ref = 1;
1126 /* Allocate the hardware buffer */
1127 if (use_hw) {
1128 err = IDsDriver_CreateSoundBuffer(ds->driver,wfex,dsbd->dwFlags,0,
1129 &(dsb->buflen),&(dsb->buffer->memory),
1130 (LPVOID*)&(dsb->hwbuf));
1131 /* fall back to software buffer on failure */
1132 if (err != DS_OK) {
1133 TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n");
1134 use_hw = 0;
1135 if (ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) {
1136 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
1137 if (dsb->buffer == NULL) {
1138 WARN("out of memory\n");
1139 HeapFree(GetProcessHeap(),0,dsb);
1140 *pdsb = NULL;
1141 return DSERR_OUTOFMEMORY;
1144 dsb->buffer->memory = (LPBYTE)HeapAlloc(GetProcessHeap(),0,dsb->buflen);
1145 if (dsb->buffer->memory == NULL) {
1146 WARN("out of memory\n");
1147 HeapFree(GetProcessHeap(),0,dsb->buffer);
1148 HeapFree(GetProcessHeap(),0,dsb);
1149 *pdsb = NULL;
1150 return DSERR_OUTOFMEMORY;
1152 dsb->buffer->ref = 1;
1157 /* calculate fragment size and write lead */
1158 DSOUND_RecalcFormat(dsb);
1160 /* It's not necessary to initialize values to zero since */
1161 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1162 dsb->playpos = 0;
1163 dsb->buf_mixpos = 0;
1164 dsb->state = STATE_STOPPED;
1166 dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) /
1167 ds->wfx.nSamplesPerSec;
1168 dsb->nAvgBytesPerSec = dsb->freq *
1169 dsbd->lpwfxFormat->nBlockAlign;
1171 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1172 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1173 dsb->ds3db_ds3db.vPosition.x = 0.0;
1174 dsb->ds3db_ds3db.vPosition.y = 0.0;
1175 dsb->ds3db_ds3db.vPosition.z = 0.0;
1176 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1177 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1178 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1179 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1180 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1181 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1182 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1183 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1184 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1185 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1186 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1187 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1189 dsb->ds3db_need_recalc = FALSE;
1190 DSOUND_Calc3DBuffer(dsb);
1191 } else
1192 DSOUND_RecalcVolPan(&(dsb->volpan));
1194 InitializeCriticalSection(&(dsb->lock));
1195 dsb->lock.DebugInfo->Spare[1] = (DWORD)"DSOUNDBUFFER_lock";
1197 /* register buffer */
1198 RtlAcquireResourceExclusive(&(ds->lock), TRUE);
1199 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1200 IDirectSoundBufferImpl **newbuffers;
1201 if (ds->buffers)
1202 newbuffers = (IDirectSoundBufferImpl**)HeapReAlloc(GetProcessHeap(),0,ds->buffers,sizeof(IDirectSoundBufferImpl*)*(ds->nrofbuffers+1));
1203 else
1204 newbuffers = (IDirectSoundBufferImpl**)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(ds->nrofbuffers+1));
1206 if (newbuffers) {
1207 ds->buffers = newbuffers;
1208 ds->buffers[ds->nrofbuffers] = dsb;
1209 ds->nrofbuffers++;
1210 TRACE("buffer count is now %d\n", ds->nrofbuffers);
1211 } else {
1212 ERR("out of memory for buffer list! Current buffer count is %d\n", ds->nrofbuffers);
1213 if (dsb->buffer->memory)
1214 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1215 if (dsb->buffer)
1216 HeapFree(GetProcessHeap(),0,dsb->buffer);
1217 DeleteCriticalSection(&(dsb->lock));
1218 RtlReleaseResource(&(ds->lock));
1219 HeapFree(GetProcessHeap(),0,dsb);
1220 *pdsb = NULL;
1221 return DSERR_OUTOFMEMORY;
1224 RtlReleaseResource(&(ds->lock));
1225 *pdsb = dsb;
1226 return S_OK;
1229 HRESULT WINAPI IDirectSoundBufferImpl_Destroy(
1230 IDirectSoundBufferImpl *pdsb)
1232 TRACE("(%p)\n",pdsb);
1234 /* This keeps the *_Destroy functions from possibly deleting
1235 * this object until it is ready to be deleted */
1236 IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb);
1238 if (pdsb->iks) {
1239 WARN("iks not NULL\n");
1240 IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1241 pdsb->iks = NULL;
1244 if (pdsb->ds3db) {
1245 WARN("ds3db not NULL\n");
1246 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1247 pdsb->ds3db = NULL;
1250 if (pdsb->notify) {
1251 WARN("notify not NULL\n");
1252 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1253 pdsb->notify = NULL;
1256 if (pdsb->dsb) {
1257 WARN("dsb not NULL\n");
1258 SecondaryBufferImpl_Destroy(pdsb->dsb);
1259 pdsb->dsb = NULL;
1262 while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1264 return S_OK;
1267 /*******************************************************************************
1268 * SecondaryBuffer
1271 static HRESULT WINAPI SecondaryBufferImpl_QueryInterface(
1272 LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj)
1274 ICOM_THIS(SecondaryBufferImpl,iface);
1275 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1277 return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj);
1280 static DWORD WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface)
1282 ICOM_THIS(IDirectSoundBufferImpl,iface);
1283 DWORD ref;
1284 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1286 ref = InterlockedIncrement(&(This->ref));
1287 if (!ref) {
1288 FIXME("thread-safety alert! AddRef-ing with a zero refcount!\n");
1290 return ref;
1293 static DWORD WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface)
1295 ICOM_THIS(IDirectSoundBufferImpl,iface);
1296 DWORD ref;
1297 TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId());
1299 ref = InterlockedDecrement(&(This->ref));
1300 if (!ref) {
1301 This->dsb->dsb = NULL;
1302 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb);
1303 HeapFree(GetProcessHeap(),0,This);
1304 TRACE("(%p) released\n",This);
1306 return ref;
1309 static HRESULT WINAPI SecondaryBufferImpl_GetCaps(
1310 LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps)
1312 ICOM_THIS(SecondaryBufferImpl,iface);
1313 TRACE("(%p)->(%p)\n",This,caps);
1315 return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps);
1318 static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition(
1319 LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos)
1321 ICOM_THIS(SecondaryBufferImpl,iface);
1322 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
1324 return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos);
1327 static HRESULT WINAPI SecondaryBufferImpl_GetFormat(
1328 LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten)
1330 ICOM_THIS(SecondaryBufferImpl,iface);
1331 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
1333 return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten);
1336 static HRESULT WINAPI SecondaryBufferImpl_GetVolume(
1337 LPDIRECTSOUNDBUFFER8 iface,LPLONG vol)
1339 ICOM_THIS(SecondaryBufferImpl,iface);
1340 TRACE("(%p,%p)\n",This,vol);
1342 return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1345 static HRESULT WINAPI SecondaryBufferImpl_GetPan(
1346 LPDIRECTSOUNDBUFFER8 iface,LPLONG pan)
1348 ICOM_THIS(SecondaryBufferImpl,iface);
1349 TRACE("(%p,%p)\n",This,pan);
1351 return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1354 static HRESULT WINAPI SecondaryBufferImpl_GetFrequency(
1355 LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq)
1357 ICOM_THIS(SecondaryBufferImpl,iface);
1358 TRACE("(%p,%p)\n",This,freq);
1360 return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1363 static HRESULT WINAPI SecondaryBufferImpl_GetStatus(
1364 LPDIRECTSOUNDBUFFER8 iface,LPDWORD status)
1366 ICOM_THIS(SecondaryBufferImpl,iface);
1367 TRACE("(%p,%p)\n",This,status);
1369 return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status);
1372 static HRESULT WINAPI SecondaryBufferImpl_Initialize(
1373 LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd)
1375 ICOM_THIS(SecondaryBufferImpl,iface);
1376 TRACE("(%p,%p,%p)\n",This,dsound,dbsd);
1378 return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd);
1381 static HRESULT WINAPI SecondaryBufferImpl_Lock(
1382 LPDIRECTSOUNDBUFFER8 iface,
1383 DWORD writecursor,
1384 DWORD writebytes,
1385 LPVOID lplpaudioptr1,
1386 LPDWORD audiobytes1,
1387 LPVOID lplpaudioptr2,
1388 LPDWORD audiobytes2,
1389 DWORD dwFlags)
1391 ICOM_THIS(SecondaryBufferImpl,iface);
1392 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n",
1393 This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1395 return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb,
1396 writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags);
1399 static HRESULT WINAPI SecondaryBufferImpl_Play(
1400 LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags)
1402 ICOM_THIS(SecondaryBufferImpl,iface);
1403 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
1405 return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags);
1408 static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition(
1409 LPDIRECTSOUNDBUFFER8 iface,DWORD newpos)
1411 ICOM_THIS(SecondaryBufferImpl,iface);
1412 TRACE("(%p,%ld)\n",This,newpos);
1414 return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos);
1417 static HRESULT WINAPI SecondaryBufferImpl_SetFormat(
1418 LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex)
1420 ICOM_THIS(SecondaryBufferImpl,iface);
1421 TRACE("(%p,%p)\n",This,wfex);
1423 return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex);
1426 static HRESULT WINAPI SecondaryBufferImpl_SetVolume(
1427 LPDIRECTSOUNDBUFFER8 iface,LONG vol)
1429 ICOM_THIS(SecondaryBufferImpl,iface);
1430 TRACE("(%p,%ld)\n",This,vol);
1432 return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol);
1435 static HRESULT WINAPI SecondaryBufferImpl_SetPan(
1436 LPDIRECTSOUNDBUFFER8 iface,LONG pan)
1438 ICOM_THIS(SecondaryBufferImpl,iface);
1439 TRACE("(%p,%ld)\n",This,pan);
1441 return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan);
1444 static HRESULT WINAPI SecondaryBufferImpl_SetFrequency(
1445 LPDIRECTSOUNDBUFFER8 iface,DWORD freq)
1447 ICOM_THIS(SecondaryBufferImpl,iface);
1448 TRACE("(%p,%ld)\n",This,freq);
1450 return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq);
1453 static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface)
1455 ICOM_THIS(SecondaryBufferImpl,iface);
1456 TRACE("(%p)\n",This);
1458 return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb);
1461 static HRESULT WINAPI SecondaryBufferImpl_Unlock(
1462 LPDIRECTSOUNDBUFFER8 iface,
1463 LPVOID lpvAudioPtr1,
1464 DWORD dwAudioBytes1,
1465 LPVOID lpvAudioPtr2,
1466 DWORD dwAudioBytes2)
1468 ICOM_THIS(SecondaryBufferImpl,iface);
1469 TRACE("(%p,%p,%ld,%p,%ld)\n",
1470 This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2);
1472 return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb,
1473 lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2);
1476 static HRESULT WINAPI SecondaryBufferImpl_Restore(
1477 LPDIRECTSOUNDBUFFER8 iface)
1479 ICOM_THIS(SecondaryBufferImpl,iface);
1480 TRACE("(%p)\n",This);
1482 return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb);
1485 static HRESULT WINAPI SecondaryBufferImpl_SetFX(
1486 LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes)
1488 ICOM_THIS(SecondaryBufferImpl,iface);
1489 TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1491 return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes);
1494 static HRESULT WINAPI SecondaryBufferImpl_AcquireResources(
1495 LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes)
1497 ICOM_THIS(SecondaryBufferImpl,iface);
1498 TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
1500 return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes);
1503 static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath(
1504 LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject)
1506 ICOM_THIS(SecondaryBufferImpl,iface);
1507 TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
1509 return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject);
1512 static IDirectSoundBuffer8Vtbl sbvt =
1514 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1515 SecondaryBufferImpl_QueryInterface,
1516 SecondaryBufferImpl_AddRef,
1517 SecondaryBufferImpl_Release,
1518 SecondaryBufferImpl_GetCaps,
1519 SecondaryBufferImpl_GetCurrentPosition,
1520 SecondaryBufferImpl_GetFormat,
1521 SecondaryBufferImpl_GetVolume,
1522 SecondaryBufferImpl_GetPan,
1523 SecondaryBufferImpl_GetFrequency,
1524 SecondaryBufferImpl_GetStatus,
1525 SecondaryBufferImpl_Initialize,
1526 SecondaryBufferImpl_Lock,
1527 SecondaryBufferImpl_Play,
1528 SecondaryBufferImpl_SetCurrentPosition,
1529 SecondaryBufferImpl_SetFormat,
1530 SecondaryBufferImpl_SetVolume,
1531 SecondaryBufferImpl_SetPan,
1532 SecondaryBufferImpl_SetFrequency,
1533 SecondaryBufferImpl_Stop,
1534 SecondaryBufferImpl_Unlock,
1535 SecondaryBufferImpl_Restore,
1536 SecondaryBufferImpl_SetFX,
1537 SecondaryBufferImpl_AcquireResources,
1538 SecondaryBufferImpl_GetObjectInPath
1541 HRESULT WINAPI SecondaryBufferImpl_Create(
1542 IDirectSoundBufferImpl *dsb,
1543 SecondaryBufferImpl **psb)
1545 SecondaryBufferImpl *sb;
1546 TRACE("(%p,%p)\n",dsb,psb);
1548 sb = (SecondaryBufferImpl*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb));
1550 if (sb == 0) {
1551 WARN("out of memory\n");
1552 *psb = NULL;
1553 return DSERR_OUTOFMEMORY;
1555 sb->ref = 0;
1556 sb->dsb = dsb;
1557 sb->lpVtbl = &sbvt;
1559 IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb);
1560 *psb = sb;
1561 return S_OK;
1564 HRESULT WINAPI SecondaryBufferImpl_Destroy(
1565 SecondaryBufferImpl *pdsb)
1567 TRACE("(%p)\n",pdsb);
1569 while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0);
1571 return S_OK;