maintainers: Update the Direct3D section.
[wine.git] / dlls / dsound / buffer.c
blobeb87479b7df6df62b5723f4108b81fb6dee43f98
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "mmsystem.h"
30 #include "vfwmsgs.h"
31 #include "wine/debug.h"
32 #include "dsound.h"
33 #include "dsound_private.h"
34 #include "dsconf.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
38 /*******************************************************************************
39 * IDirectSoundNotify
42 static inline struct IDirectSoundBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
44 return CONTAINING_RECORD(iface, struct IDirectSoundBufferImpl, IDirectSoundNotify_iface);
47 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
48 void **ppobj)
50 IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
52 TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
54 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
57 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
59 IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
60 ULONG ref = InterlockedIncrement(&This->refn);
62 TRACE("(%p) ref %ld\n", This, ref);
64 if(ref == 1)
65 InterlockedIncrement(&This->numIfaces);
67 return ref;
70 static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
72 IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
73 ULONG ref = InterlockedDecrement(&This->refn);
75 TRACE("(%p) ref %ld\n", This, ref);
77 if (!ref && !InterlockedDecrement(&This->numIfaces))
78 secondarybuffer_destroy(This);
80 return ref;
83 static int __cdecl notify_compar(const void *l, const void *r)
85 const DSBPOSITIONNOTIFY *left = l;
86 const DSBPOSITIONNOTIFY *right = r;
88 /* place DSBPN_OFFSETSTOP at the start of the sorted array */
89 if(left->dwOffset == DSBPN_OFFSETSTOP){
90 if(right->dwOffset != DSBPN_OFFSETSTOP)
91 return -1;
92 }else if(right->dwOffset == DSBPN_OFFSETSTOP)
93 return 1;
95 if(left->dwOffset == right->dwOffset)
96 return 0;
98 if(left->dwOffset < right->dwOffset)
99 return -1;
101 return 1;
104 static void commit_next_chunk(IDirectSoundBufferImpl *dsb)
106 void *dstbuff = dsb->committedbuff, *srcbuff = dsb->buffer->memory;
107 DWORD srcoff = dsb->sec_mixpos, srcsize = dsb->buflen, cpysize = dsb->writelead;
109 if(dsb->state != STATE_PLAYING)
110 return;
112 if(cpysize > srcsize - srcoff) {
113 DWORD overflow = cpysize - (srcsize - srcoff);
114 memcpy(dstbuff, (BYTE*)srcbuff + srcoff, srcsize - srcoff);
115 memcpy((BYTE*)dstbuff + (srcsize - srcoff), srcbuff, overflow);
116 }else{
117 memcpy(dstbuff, (BYTE*)srcbuff + srcoff, cpysize);
120 dsb->use_committed = TRUE;
121 dsb->committed_mixpos = 0;
122 TRACE("committing %lu bytes from offset %lu\n", dsb->writelead, dsb->sec_mixpos);
125 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
126 DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
128 IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
130 TRACE("(%p,0x%08lx,%p)\n",This,howmuch,notify);
132 if (howmuch > 0 && notify == NULL) {
133 WARN("invalid parameter: notify == NULL\n");
134 return DSERR_INVALIDPARAM;
137 if (TRACE_ON(dsound)) {
138 unsigned int i;
139 for (i=0;i<howmuch;i++)
140 TRACE("notify at %ld to %p\n",
141 notify[i].dwOffset,notify[i].hEventNotify);
144 if (howmuch > 0) {
145 /* Make an internal copy of the caller-supplied array.
146 * Replace the existing copy if one is already present. */
147 HeapFree(GetProcessHeap(), 0, This->notifies);
148 This->notifies = HeapAlloc(GetProcessHeap(), 0,
149 howmuch * sizeof(DSBPOSITIONNOTIFY));
151 if (This->notifies == NULL) {
152 WARN("out of memory\n");
153 return DSERR_OUTOFMEMORY;
155 CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
156 This->nrofnotifies = howmuch;
157 qsort(This->notifies, howmuch, sizeof(DSBPOSITIONNOTIFY), notify_compar);
158 } else {
159 HeapFree(GetProcessHeap(), 0, This->notifies);
160 This->notifies = NULL;
161 This->nrofnotifies = 0;
164 return S_OK;
167 static const IDirectSoundNotifyVtbl dsnvt =
169 IDirectSoundNotifyImpl_QueryInterface,
170 IDirectSoundNotifyImpl_AddRef,
171 IDirectSoundNotifyImpl_Release,
172 IDirectSoundNotifyImpl_SetNotificationPositions,
175 /*******************************************************************************
176 * IDirectSoundBuffer
179 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
181 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
184 static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
186 return (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) != 0;
189 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
190 LPCWAVEFORMATEX wfex)
192 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
194 TRACE("(%p,%p)\n", iface, wfex);
196 if (is_primary_buffer(This))
197 return primarybuffer_SetFormat(This->device, wfex);
198 else {
199 WARN("not available for secondary buffers.\n");
200 return DSERR_INVALIDCALL;
204 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
206 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
207 LONG oldVol;
209 HRESULT hres = DS_OK;
211 TRACE("(%p,%ld)\n",This,vol);
213 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
214 WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags);
215 return DSERR_CONTROLUNAVAIL;
218 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
219 WARN("invalid parameter: vol = %ld\n", vol);
220 return DSERR_INVALIDPARAM;
223 AcquireSRWLockExclusive(&This->lock);
225 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
226 oldVol = This->ds3db_lVolume;
227 This->ds3db_lVolume = vol;
228 if (vol != oldVol)
229 /* recalc 3d volume, which in turn recalcs the pans */
230 DSOUND_Calc3DBuffer(This);
231 } else {
232 oldVol = This->volpan.lVolume;
233 This->volpan.lVolume = vol;
234 if (vol != oldVol)
235 DSOUND_RecalcVolPan(&(This->volpan));
238 ReleaseSRWLockExclusive(&This->lock);
240 return hres;
243 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
245 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
247 TRACE("(%p,%p)\n",This,vol);
249 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
250 WARN("control unavailable\n");
251 return DSERR_CONTROLUNAVAIL;
254 if (vol == NULL) {
255 WARN("invalid parameter: vol == NULL\n");
256 return DSERR_INVALIDPARAM;
259 *vol = This->volpan.lVolume;
261 return DS_OK;
264 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
266 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
267 DWORD oldFreq;
268 void *newcommitted;
270 TRACE("(%p,%ld)\n",This,freq);
272 if (is_primary_buffer(This)) {
273 WARN("not available for primary buffers.\n");
274 return DSERR_CONTROLUNAVAIL;
277 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
278 WARN("control unavailable\n");
279 return DSERR_CONTROLUNAVAIL;
282 if (freq == DSBFREQUENCY_ORIGINAL)
283 freq = This->pwfx->nSamplesPerSec;
285 if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
286 WARN("invalid parameter: freq = %ld\n", freq);
287 return DSERR_INVALIDPARAM;
290 AcquireSRWLockExclusive(&This->lock);
292 oldFreq = This->freq;
293 This->freq = freq;
294 if (freq != oldFreq) {
295 This->freqAdjustNum = This->freq;
296 This->freqAdjustDen = This->device->pwfx->nSamplesPerSec;
297 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
298 DSOUND_RecalcFormat(This);
300 newcommitted = HeapReAlloc(GetProcessHeap(), 0, This->committedbuff, This->writelead);
301 if(!newcommitted) {
302 ReleaseSRWLockExclusive(&This->lock);
303 return DSERR_OUTOFMEMORY;
305 This->committedbuff = newcommitted;
308 ReleaseSRWLockExclusive(&This->lock);
310 return DS_OK;
313 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
314 DWORD reserved2, DWORD flags)
316 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
317 HRESULT hres = DS_OK;
318 int i;
320 TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags);
322 AcquireSRWLockExclusive(&This->lock);
324 This->playflags = flags;
325 if (This->state == STATE_STOPPED) {
326 This->leadin = TRUE;
327 This->state = STATE_STARTING;
330 for (i = 0; i < This->num_filters; i++) {
331 IMediaObject_Discontinuity(This->filters[i].obj, 0);
334 ReleaseSRWLockExclusive(&This->lock);
336 return hres;
339 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
341 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
342 HRESULT hres = DS_OK;
344 TRACE("(%p)\n",This);
346 AcquireSRWLockExclusive(&This->lock);
348 if (This->state == STATE_PLAYING || This->state == STATE_STARTING)
350 This->state = STATE_STOPPED;
351 This->use_committed = FALSE;
352 This->committed_mixpos = 0;
353 DSOUND_CheckEvent(This, 0, 0);
356 ReleaseSRWLockExclusive(&This->lock);
358 return hres;
361 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
363 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
364 ULONG ref = InterlockedIncrement(&This->ref);
366 TRACE("(%p) ref %ld\n", This, ref);
368 if(ref == 1)
369 InterlockedIncrement(&This->numIfaces);
371 return ref;
374 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
376 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
377 ULONG ref;
379 if (is_primary_buffer(This)){
380 ref = capped_refcount_dec(&This->ref);
381 if(!ref)
382 capped_refcount_dec(&This->numIfaces);
383 TRACE("(%p) ref %ld\n", This, ref);
384 return ref;
387 ref = InterlockedDecrement(&This->ref);
388 if (!ref && !InterlockedDecrement(&This->numIfaces))
389 secondarybuffer_destroy(This);
391 TRACE("(%p) ref %ld\n", This, ref);
393 return ref;
396 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
397 DWORD *playpos, DWORD *writepos)
399 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
400 DWORD pos;
402 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
404 AcquireSRWLockShared(&This->lock);
406 pos = This->sec_mixpos;
408 /* sanity */
409 if (pos >= This->buflen){
410 FIXME("Bad play position. playpos: %ld, buflen: %ld\n", pos, This->buflen);
411 pos %= This->buflen;
414 if (playpos)
415 *playpos = pos;
416 if (writepos)
417 *writepos = pos;
419 if (writepos && This->state != STATE_STOPPED) {
420 /* apply the documented 10ms lead to writepos */
421 *writepos += This->writelead;
422 *writepos %= This->buflen;
425 ReleaseSRWLockShared(&This->lock);
427 TRACE("playpos = %ld, writepos = %ld, buflen=%ld (%p, time=%ld)\n",
428 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
430 return DS_OK;
433 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
435 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
437 TRACE("(%p,%p)\n",This,status);
439 if (status == NULL) {
440 WARN("invalid parameter: status = NULL\n");
441 return DSERR_INVALIDPARAM;
444 *status = 0;
445 AcquireSRWLockShared(&This->lock);
446 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
447 *status |= DSBSTATUS_PLAYING;
448 if (This->playflags & DSBPLAY_LOOPING)
449 *status |= DSBSTATUS_LOOPING;
451 if (This->dsbd.dwFlags & DSBCAPS_LOCDEFER)
452 *status |= DSBSTATUS_LOCSOFTWARE;
453 ReleaseSRWLockShared(&This->lock);
455 TRACE("status=%lx\n", *status);
456 return DS_OK;
460 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
461 LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
463 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
464 DWORD size;
466 TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten);
468 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
470 if (lpwf) { /* NULL is valid */
471 if (wfsize >= size) {
472 CopyMemory(lpwf,This->pwfx,size);
473 if (wfwritten)
474 *wfwritten = size;
475 } else {
476 WARN("invalid parameter: wfsize too small\n");
477 CopyMemory(lpwf,This->pwfx,wfsize);
478 if (wfwritten)
479 *wfwritten = wfsize;
480 return DSERR_INVALIDPARAM;
482 } else {
483 if (wfwritten)
484 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
485 else {
486 WARN("invalid parameter: wfwritten == NULL\n");
487 return DSERR_INVALIDPARAM;
491 return DS_OK;
494 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
495 DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
496 DWORD *audiobytes2, DWORD flags)
498 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
499 HRESULT hres = DS_OK;
501 TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", This, writecursor, writebytes, lplpaudioptr1,
502 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
504 if (!audiobytes1)
505 return DSERR_INVALIDPARAM;
507 /* when this flag is set, writecursor is meaningless and must be calculated */
508 if (flags & DSBLOCK_FROMWRITECURSOR) {
509 /* GetCurrentPosition does too much magic to duplicate here */
510 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
511 if (hres != DS_OK) {
512 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
513 return hres;
517 /* when this flag is set, writebytes is meaningless and must be set */
518 if (flags & DSBLOCK_ENTIREBUFFER)
519 writebytes = This->buflen;
521 if (writecursor >= This->buflen) {
522 WARN("Invalid parameter, writecursor: %lu >= buflen: %lu\n",
523 writecursor, This->buflen);
524 return DSERR_INVALIDPARAM;
527 if (writebytes > This->buflen) {
528 WARN("Invalid parameter, writebytes: %lu > buflen: %lu\n",
529 writebytes, This->buflen);
530 return DSERR_INVALIDPARAM;
533 AcquireSRWLockShared(&This->lock);
535 if (writecursor+writebytes <= This->buflen) {
536 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
537 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) {
538 WARN("Overwriting mixing position, case 1\n");
539 commit_next_chunk(This);
541 *audiobytes1 = writebytes;
542 if (lplpaudioptr2)
543 *(LPBYTE*)lplpaudioptr2 = NULL;
544 if (audiobytes2)
545 *audiobytes2 = 0;
546 TRACE("Locked %p(%li bytes) and %p(%li bytes) writecursor=%ld\n",
547 *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
548 TRACE("->%ld.0\n",writebytes);
549 This->buffer->lockedbytes += writebytes;
550 } else {
551 DWORD remainder = writebytes + writecursor - This->buflen;
552 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
553 *audiobytes1 = This->buflen-writecursor;
554 This->buffer->lockedbytes += *audiobytes1;
555 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) {
556 WARN("Overwriting mixing position, case 2\n");
557 commit_next_chunk(This);
559 if (lplpaudioptr2)
560 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
561 if (audiobytes2) {
562 *audiobytes2 = writebytes-(This->buflen-writecursor);
563 This->buffer->lockedbytes += *audiobytes2;
565 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING) {
566 WARN("Overwriting mixing position, case 3\n");
567 commit_next_chunk(This);
569 TRACE("Locked %p(%li bytes) and %p(%li bytes) writecursor=%ld\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
572 ReleaseSRWLockShared(&This->lock);
574 return DS_OK;
577 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
578 DWORD newpos)
580 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
581 HRESULT hres = DS_OK;
583 TRACE("(%p,%ld)\n",This,newpos);
585 AcquireSRWLockExclusive(&This->lock);
587 /* start mixing from this new location instead */
588 newpos %= This->buflen;
589 newpos -= newpos%This->pwfx->nBlockAlign;
590 This->sec_mixpos = newpos;
592 This->use_committed = FALSE;
593 This->committed_mixpos = 0;
595 /* at this point, do not attempt to reset buffers, mess with primary mix position,
596 or anything like that to reduce latency. The data already prebuffered cannot be changed */
598 ReleaseSRWLockExclusive(&This->lock);
600 return hres;
603 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
605 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
606 HRESULT hres = DS_OK;
608 TRACE("(%p,%ld)\n",This,pan);
610 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
611 WARN("invalid parameter: pan = %ld\n", pan);
612 return DSERR_INVALIDPARAM;
615 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
616 WARN("control unavailable\n");
617 return DSERR_CONTROLUNAVAIL;
620 AcquireSRWLockExclusive(&This->lock);
622 if (This->volpan.lPan != pan) {
623 This->volpan.lPan = pan;
624 DSOUND_RecalcVolPan(&(This->volpan));
627 ReleaseSRWLockExclusive(&This->lock);
629 return hres;
632 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
634 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
636 TRACE("(%p,%p)\n",This,pan);
638 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
639 WARN("control unavailable\n");
640 return DSERR_CONTROLUNAVAIL;
643 if (pan == NULL) {
644 WARN("invalid parameter: pan = NULL\n");
645 return DSERR_INVALIDPARAM;
648 *pan = This->volpan.lPan;
650 return DS_OK;
653 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
654 void *p2, DWORD x2)
656 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
657 HRESULT hres = DS_OK;
659 TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2);
661 if (!p2)
662 x2 = 0;
664 if((p1 && ((BYTE*)p1 < This->buffer->memory || (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
665 (p2 && ((BYTE*)p2 < This->buffer->memory || (BYTE*)p2 >= This->buffer->memory + This->buflen)))
666 return DSERR_INVALIDPARAM;
668 if (x1 || x2)
670 AcquireSRWLockShared(&This->device->buffer_list_lock);
671 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
673 AcquireSRWLockShared(&iter->lock);
674 if (x1)
676 if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
677 hres = DSERR_INVALIDPARAM;
678 else
679 iter->buffer->lockedbytes -= x1;
682 if (x2)
684 if(x2 + (DWORD_PTR)p2 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
685 hres = DSERR_INVALIDPARAM;
686 else
687 iter->buffer->lockedbytes -= x2;
689 ReleaseSRWLockShared(&iter->lock);
691 ReleaseSRWLockShared(&This->device->buffer_list_lock);
694 return hres;
697 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
699 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
701 FIXME("(%p):stub\n",This);
702 return DS_OK;
705 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
707 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
709 TRACE("(%p,%p)\n",This,freq);
711 if (freq == NULL) {
712 WARN("invalid parameter: freq = NULL\n");
713 return DSERR_INVALIDPARAM;
716 *freq = This->freq;
717 TRACE("-> %ld\n", *freq);
719 return DS_OK;
722 static const char* dump_DSFX_guid(const DSEFFECTDESC *desc)
724 #define FE(guid) if (IsEqualGUID(&guid, &desc->guidDSFXClass)) return #guid
725 FE(GUID_DSFX_STANDARD_GARGLE);
726 FE(GUID_DSFX_STANDARD_CHORUS);
727 FE(GUID_DSFX_STANDARD_FLANGER);
728 FE(GUID_DSFX_STANDARD_ECHO);
729 FE(GUID_DSFX_STANDARD_DISTORTION);
730 FE(GUID_DSFX_STANDARD_COMPRESSOR);
731 FE(GUID_DSFX_STANDARD_PARAMEQ);
732 FE(GUID_DSFX_STANDARD_I3DL2REVERB);
733 FE(GUID_DSFX_WAVES_REVERB);
734 #undef FE
736 return debugstr_guid(&desc->guidDSFXClass);
739 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
740 LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
742 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
743 DWORD u;
744 DSFilter *filters;
745 HRESULT hr, hr2;
746 DMO_MEDIA_TYPE dmt;
747 WAVEFORMATEX wfx;
749 TRACE("(%p,%lu,%p,%p)\n", This, dwEffectsCount, pDSFXDesc, pdwResultCodes);
751 if (pdwResultCodes)
752 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
754 if ((dwEffectsCount > 0 && !pDSFXDesc) ||
755 (dwEffectsCount == 0 && (pDSFXDesc || pdwResultCodes))
757 return E_INVALIDARG;
759 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFX)) {
760 WARN("attempted to call SetFX on buffer without DSBCAPS_CTRLFX\n");
761 return DSERR_CONTROLUNAVAIL;
764 if (This->state != STATE_STOPPED)
765 return DSERR_INVALIDCALL;
767 if (This->buffer->lockedbytes > 0)
768 return DSERR_INVALIDCALL;
770 if (dwEffectsCount == 0) {
771 if (This->num_filters > 0) {
772 for (u = 0; u < This->num_filters; u++) {
773 IMediaObject_Release(This->filters[u].obj);
775 HeapFree(GetProcessHeap(), 0, This->filters);
777 This->filters = NULL;
778 This->num_filters = 0;
781 return DS_OK;
784 filters = HeapAlloc(GetProcessHeap(), 0, dwEffectsCount * sizeof(DSFilter));
785 if (!filters) {
786 WARN("out of memory\n");
787 return DSERR_OUTOFMEMORY;
790 hr = DS_OK;
792 wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
793 wfx.nChannels = This->pwfx->nChannels;
794 wfx.nSamplesPerSec = This->pwfx->nSamplesPerSec;
795 wfx.wBitsPerSample = sizeof(float) * 8;
796 wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample)/8;
797 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
798 wfx.cbSize = sizeof(wfx);
800 dmt.majortype = KSDATAFORMAT_TYPE_AUDIO;
801 dmt.subtype = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
802 dmt.bFixedSizeSamples = TRUE;
803 dmt.bTemporalCompression = FALSE;
804 dmt.lSampleSize = sizeof(float) * This->pwfx->nChannels / 8;
805 dmt.formattype = FORMAT_WaveFormatEx;
806 dmt.pUnk = NULL;
807 dmt.cbFormat = sizeof(WAVEFORMATEX);
808 dmt.pbFormat = (BYTE*)&wfx;
810 for (u = 0; u < dwEffectsCount; u++) {
811 TRACE("%ld: 0x%08lx, %s\n", u, pDSFXDesc[u].dwFlags, dump_DSFX_guid(&pDSFXDesc[u]));
813 hr2 = CoCreateInstance(&pDSFXDesc[u].guidDSFXClass, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (LPVOID*)&filters[u].obj);
815 if (SUCCEEDED(hr2)) {
816 hr2 = IMediaObject_SetInputType(filters[u].obj, 0, &dmt, 0);
817 if (FAILED(hr2))
818 WARN("Could not set DMO input type\n");
821 if (SUCCEEDED(hr2)) {
822 hr2 = IMediaObject_SetOutputType(filters[u].obj, 0, &dmt, 0);
823 if (FAILED(hr2))
824 WARN("Could not set DMO output type\n");
827 if (FAILED(hr2)) {
828 if (hr == DS_OK)
829 hr = hr2;
831 if (pdwResultCodes)
832 pdwResultCodes[u] = (hr2 == REGDB_E_CLASSNOTREG) ? DSFXR_UNKNOWN : DSFXR_FAILED;
833 } else {
834 if (pdwResultCodes)
835 pdwResultCodes[u] = DSFXR_LOCSOFTWARE;
839 if (FAILED(hr)) {
840 for (u = 0; u < dwEffectsCount; u++) {
841 if (pdwResultCodes)
842 pdwResultCodes[u] = (pdwResultCodes[u] != DSFXR_UNKNOWN) ? DSFXR_PRESENT : DSFXR_UNKNOWN;
844 if (filters[u].obj)
845 IMediaObject_Release(filters[u].obj);
848 HeapFree(GetProcessHeap(), 0, filters);
849 } else {
850 if (This->num_filters > 0) {
851 for (u = 0; u < This->num_filters; u++) {
852 IMediaObject_Release(This->filters[u].obj);
853 if (This->filters[u].inplace) IMediaObjectInPlace_Release(This->filters[u].inplace);
855 HeapFree(GetProcessHeap(), 0, This->filters);
858 for (u = 0; u < dwEffectsCount; u++) {
859 memcpy(&filters[u].guid, &pDSFXDesc[u].guidDSFXClass, sizeof(GUID));
860 if (FAILED(IMediaObject_QueryInterface(filters[u].obj, &IID_IMediaObjectInPlace, (void*)&filters[u].inplace)))
861 filters[u].inplace = NULL;
864 This->filters = filters;
865 This->num_filters = dwEffectsCount;
868 return hr;
871 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
872 DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
874 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
875 DWORD u;
877 FIXME("(%p,%08lu,%lu,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
879 if (pdwResultCodes)
880 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
882 WARN("control unavailable\n");
883 return DS_OK;
886 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
887 REFGUID clsid, DWORD index, REFGUID iid, void **out)
889 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
890 DWORD i, count = 0;
892 TRACE("(%p,%s,%lu,%s,%p)\n", This, debugstr_guid(clsid), index, debugstr_guid(iid), out);
894 if (!out)
895 return E_INVALIDARG;
897 for (i = 0; i < This->num_filters; i++)
899 if (IsEqualGUID(clsid, &This->filters[i].guid) || IsEqualGUID(clsid, &GUID_All_Objects))
901 if (count++ == index)
902 return IMediaObject_QueryInterface(This->filters[i].obj, iid, out);
905 return DSERR_OBJECTNOTFOUND;
908 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
909 IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
911 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
913 WARN("(%p) already initialized\n", This);
914 return DSERR_ALREADYINITIALIZED;
917 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
919 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
921 TRACE("(%p)->(%p)\n",This,caps);
923 if (caps == NULL) {
924 WARN("invalid parameter: caps == NULL\n");
925 return DSERR_INVALIDPARAM;
928 if (caps->dwSize < sizeof(*caps)) {
929 WARN("invalid parameter: caps->dwSize = %ld\n",caps->dwSize);
930 return DSERR_INVALIDPARAM;
933 caps->dwFlags = This->dsbd.dwFlags;
934 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
936 caps->dwBufferBytes = This->buflen;
938 /* According to windows, this is zero*/
939 caps->dwUnlockTransferRate = 0;
940 caps->dwPlayCpuOverhead = 0;
942 return DS_OK;
945 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
946 void **ppobj)
948 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
950 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
952 if (ppobj == NULL) {
953 WARN("invalid parameter\n");
954 return E_INVALIDARG;
957 *ppobj = NULL; /* assume failure */
959 if ( IsEqualGUID(riid, &IID_IUnknown) ||
960 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
961 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
962 IDirectSoundBuffer8_AddRef(iface);
963 *ppobj = iface;
964 return S_OK;
967 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
968 if(This->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY) {
969 IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
970 *ppobj = &This->IDirectSoundNotify_iface;
971 return S_OK;
974 TRACE( "App requested IDirectSoundNotify without DSBCAPS_CTRLPOSITIONNOTIFY flag.\n");
975 return E_NOINTERFACE;
978 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
979 if(This->dsbd.dwFlags & DSBCAPS_CTRL3D){
980 IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
981 *ppobj = &This->IDirectSound3DBuffer_iface;
982 return S_OK;
984 TRACE("app requested IDirectSound3DBuffer on non-3D secondary buffer\n");
985 return E_NOINTERFACE;
988 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
989 ERR("app requested IDirectSound3DListener on secondary buffer\n");
990 return E_NOINTERFACE;
993 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
994 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
995 *ppobj = &This->IKsPropertySet_iface;
996 return S_OK;
999 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
1001 return E_NOINTERFACE;
1004 static const IDirectSoundBuffer8Vtbl dsbvt =
1006 IDirectSoundBufferImpl_QueryInterface,
1007 IDirectSoundBufferImpl_AddRef,
1008 IDirectSoundBufferImpl_Release,
1009 IDirectSoundBufferImpl_GetCaps,
1010 IDirectSoundBufferImpl_GetCurrentPosition,
1011 IDirectSoundBufferImpl_GetFormat,
1012 IDirectSoundBufferImpl_GetVolume,
1013 IDirectSoundBufferImpl_GetPan,
1014 IDirectSoundBufferImpl_GetFrequency,
1015 IDirectSoundBufferImpl_GetStatus,
1016 IDirectSoundBufferImpl_Initialize,
1017 IDirectSoundBufferImpl_Lock,
1018 IDirectSoundBufferImpl_Play,
1019 IDirectSoundBufferImpl_SetCurrentPosition,
1020 IDirectSoundBufferImpl_SetFormat,
1021 IDirectSoundBufferImpl_SetVolume,
1022 IDirectSoundBufferImpl_SetPan,
1023 IDirectSoundBufferImpl_SetFrequency,
1024 IDirectSoundBufferImpl_Stop,
1025 IDirectSoundBufferImpl_Unlock,
1026 IDirectSoundBufferImpl_Restore,
1027 IDirectSoundBufferImpl_SetFX,
1028 IDirectSoundBufferImpl_AcquireResources,
1029 IDirectSoundBufferImpl_GetObjectInPath
1032 HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *dsbd,
1033 IDirectSoundBuffer **buffer)
1035 IDirectSoundBufferImpl *dsb;
1036 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
1037 HRESULT err = DS_OK;
1038 DWORD capf = 0;
1039 size_t bufsize;
1041 TRACE("(%p,%p,%p)\n", device, dsbd, buffer);
1043 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
1044 WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes);
1045 return DSERR_INVALIDPARAM; /* FIXME: which error? */
1048 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
1050 if (!dsb)
1051 return DSERR_OUTOFMEMORY;
1053 TRACE("Created buffer at %p\n", dsb);
1055 dsb->ref = 1;
1056 dsb->refn = 0;
1057 dsb->ref3D = 0;
1058 dsb->refiks = 0;
1059 dsb->numIfaces = 1;
1060 dsb->device = device;
1061 dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
1062 dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
1063 dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
1064 dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
1066 /* size depends on version */
1067 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
1069 dsb->pwfx = DSOUND_CopyFormat(wfex);
1070 if (!dsb->pwfx) {
1071 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
1072 return DSERR_OUTOFMEMORY;
1075 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
1076 dsb->buflen = dsbd->dwBufferBytes +
1077 (dsbd->lpwfxFormat->nBlockAlign -
1078 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
1079 else
1080 dsb->buflen = dsbd->dwBufferBytes;
1082 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
1083 dsb->notifies = NULL;
1084 dsb->nrofnotifies = 0;
1086 /* Check necessary hardware mixing capabilities */
1087 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
1088 else capf |= DSCAPS_SECONDARYMONO;
1089 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
1090 else capf |= DSCAPS_SECONDARY8BIT;
1092 TRACE("capf = 0x%08lx, device->drvcaps.dwFlags = 0x%08lx\n", capf, device->drvcaps.dwFlags);
1094 /* Allocate an empty buffer */
1095 bufsize = (sizeof(*(dsb->buffer)) + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
1096 dsb->buffer = HeapAlloc(GetProcessHeap(),0,bufsize + dsb->buflen);
1097 if (!dsb->buffer) {
1098 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
1099 return DSERR_OUTOFMEMORY;
1102 /* Allocate system memory for buffer */
1103 dsb->buffer->memory = (BYTE *)dsb->buffer + bufsize;
1105 dsb->buffer->ref = 1;
1106 dsb->buffer->lockedbytes = 0;
1107 list_init(&dsb->buffer->buffers);
1108 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1109 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
1111 /* It's not necessary to initialize values to zero since */
1112 /* we allocated this structure with HEAP_ZERO_MEMORY... */
1113 dsb->sec_mixpos = 0;
1114 dsb->state = STATE_STOPPED;
1116 dsb->freqAdjustNum = dsb->freq;
1117 dsb->freqAdjustDen = device->pwfx->nSamplesPerSec;
1118 dsb->nAvgBytesPerSec = dsb->freq *
1119 dsbd->lpwfxFormat->nBlockAlign;
1121 /* calculate fragment size and write lead */
1122 DSOUND_RecalcFormat(dsb);
1124 dsb->committedbuff = HeapAlloc(GetProcessHeap(), 0, dsb->writelead);
1125 if(!dsb->committedbuff) {
1126 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
1127 return DSERR_OUTOFMEMORY;
1130 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
1131 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
1132 dsb->ds3db_ds3db.vPosition.x = 0.0;
1133 dsb->ds3db_ds3db.vPosition.y = 0.0;
1134 dsb->ds3db_ds3db.vPosition.z = 0.0;
1135 dsb->ds3db_ds3db.vVelocity.x = 0.0;
1136 dsb->ds3db_ds3db.vVelocity.y = 0.0;
1137 dsb->ds3db_ds3db.vVelocity.z = 0.0;
1138 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
1139 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
1140 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
1141 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
1142 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
1143 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
1144 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
1145 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
1146 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1148 dsb->ds3db_need_recalc = FALSE;
1149 DSOUND_Calc3DBuffer(dsb);
1150 } else
1151 DSOUND_RecalcVolPan(&(dsb->volpan));
1153 InitializeSRWLock(&dsb->lock);
1155 /* register buffer */
1156 err = DirectSoundDevice_AddBuffer(device, dsb);
1157 if (err == DS_OK)
1158 *buffer = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
1159 else
1160 IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
1162 return err;
1165 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1167 ULONG ref = InterlockedIncrement(&This->numIfaces);
1169 if (ref > 1)
1170 WARN("Destroying buffer with %lu in use interfaces\n", ref - 1);
1172 if (This->dsbd.dwFlags & DSBCAPS_LOCHARDWARE)
1173 This->device->drvcaps.dwFreeHwMixingAllBuffers++;
1175 DirectSoundDevice_RemoveBuffer(This->device, This);
1177 This->buffer->ref--;
1178 list_remove(&This->entry);
1179 if (This->buffer->ref == 0)
1180 HeapFree(GetProcessHeap(), 0, This->buffer);
1182 HeapFree(GetProcessHeap(), 0, This->notifies);
1183 HeapFree(GetProcessHeap(), 0, This->pwfx);
1184 HeapFree(GetProcessHeap(), 0, This->committedbuff);
1186 if (This->filters) {
1187 int i;
1188 for (i = 0; i < This->num_filters; i++) {
1189 IMediaObject_Release(This->filters[i].obj);
1190 if (This->filters[i].inplace) IMediaObjectInPlace_Release(This->filters[i].inplace);
1192 HeapFree(GetProcessHeap(), 0, This->filters);
1195 HeapFree(GetProcessHeap(), 0, This);
1197 TRACE("(%p) released\n", This);
1200 BOOL secondarybuffer_is_audible(IDirectSoundBufferImpl *This)
1202 UINT i;
1203 for (i = 0; i < This->device->pwfx->nChannels; i++) {
1204 if (This->volpan.dwTotalAmpFactor[i] != 0)
1205 return TRUE;
1208 return FALSE;
1211 HRESULT IDirectSoundBufferImpl_Duplicate(
1212 DirectSoundDevice *device,
1213 IDirectSoundBufferImpl **ppdsb,
1214 IDirectSoundBufferImpl *pdsb)
1216 IDirectSoundBufferImpl *dsb;
1217 HRESULT hres = DS_OK;
1218 VOID *committedbuff;
1219 TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1221 dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1222 if (dsb == NULL) {
1223 WARN("out of memory\n");
1224 *ppdsb = NULL;
1225 return DSERR_OUTOFMEMORY;
1228 committedbuff = HeapAlloc(GetProcessHeap(),0,pdsb->writelead);
1229 if (committedbuff == NULL) {
1230 HeapFree(GetProcessHeap(),0,dsb);
1231 *ppdsb = NULL;
1232 return DSERR_OUTOFMEMORY;
1235 AcquireSRWLockShared(&pdsb->lock);
1237 CopyMemory(dsb, pdsb, sizeof(*dsb));
1239 dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1241 ReleaseSRWLockShared(&pdsb->lock);
1243 if (dsb->pwfx == NULL) {
1244 HeapFree(GetProcessHeap(),0,committedbuff);
1245 HeapFree(GetProcessHeap(),0,dsb);
1246 *ppdsb = NULL;
1247 return DSERR_OUTOFMEMORY;
1250 dsb->buffer->ref++;
1251 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1252 dsb->ref = 0;
1253 dsb->refn = 0;
1254 dsb->ref3D = 0;
1255 dsb->refiks = 0;
1256 dsb->numIfaces = 0;
1257 dsb->state = STATE_STOPPED;
1258 dsb->sec_mixpos = 0;
1259 dsb->notifies = NULL;
1260 dsb->nrofnotifies = 0;
1261 dsb->device = device;
1262 dsb->committedbuff = committedbuff;
1263 dsb->use_committed = FALSE;
1264 dsb->committed_mixpos = 0;
1265 DSOUND_RecalcFormat(dsb);
1267 InitializeSRWLock(&dsb->lock);
1269 /* register buffer */
1270 hres = DirectSoundDevice_AddBuffer(device, dsb);
1271 if (hres != DS_OK) {
1272 list_remove(&dsb->entry);
1273 dsb->buffer->ref--;
1274 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1275 HeapFree(GetProcessHeap(),0,dsb->committedbuff);
1276 HeapFree(GetProcessHeap(),0,dsb);
1277 dsb = NULL;
1278 }else
1279 IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1281 *ppdsb = dsb;
1282 return hres;
1285 /*******************************************************************************
1286 * IKsPropertySet
1289 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1291 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1294 /* IUnknown methods */
1295 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1296 void **ppobj)
1298 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1300 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1302 return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1305 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1307 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1308 ULONG ref = InterlockedIncrement(&This->refiks);
1310 TRACE("(%p) ref %ld\n", This, ref);
1312 if(ref == 1)
1313 InterlockedIncrement(&This->numIfaces);
1315 return ref;
1318 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1320 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1321 ULONG ref;
1323 if (is_primary_buffer(This)){
1324 ref = capped_refcount_dec(&This->refiks);
1325 if(!ref)
1326 capped_refcount_dec(&This->numIfaces);
1327 TRACE("(%p) ref %ld\n", This, ref);
1328 return ref;
1331 ref = InterlockedDecrement(&This->refiks);
1332 if (!ref && !InterlockedDecrement(&This->numIfaces))
1333 secondarybuffer_destroy(This);
1335 TRACE("(%p) ref %ld\n", This, ref);
1337 return ref;
1340 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1341 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1342 ULONG cbPropData, ULONG *pcbReturned)
1344 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1346 TRACE("(iface=%p,guidPropSet=%s,dwPropID=%ld,pInstanceData=%p,cbInstanceData=%ld,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n",
1347 This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1349 return E_PROP_ID_UNSUPPORTED;
1352 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1353 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1354 ULONG cbPropData)
1356 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1358 TRACE("(%p,%s,%ld,%p,%ld,%p,%ld)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1360 return E_PROP_ID_UNSUPPORTED;
1363 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1364 ULONG dwPropID, ULONG *pTypeSupport)
1366 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1368 TRACE("(%p,%s,%ld,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1370 return E_PROP_ID_UNSUPPORTED;
1373 const IKsPropertySetVtbl iksbvt = {
1374 IKsPropertySetImpl_QueryInterface,
1375 IKsPropertySetImpl_AddRef,
1376 IKsPropertySetImpl_Release,
1377 IKsPropertySetImpl_Get,
1378 IKsPropertySetImpl_Set,
1379 IKsPropertySetImpl_QuerySupport