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
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
32 #include "wine/debug.h"
34 #include "dsound_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
39 /*******************************************************************************
43 struct IDirectSoundNotifyImpl
46 const IDirectSoundNotifyVtbl *lpVtbl;
48 IDirectSoundBufferImpl* dsb;
51 static HRESULT IDirectSoundNotifyImpl_Create(IDirectSoundBufferImpl *dsb,
52 IDirectSoundNotifyImpl **pdsn);
53 static HRESULT IDirectSoundNotifyImpl_Destroy(IDirectSoundNotifyImpl *pdsn);
55 static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(
56 LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj
58 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
59 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
61 if (This->dsb == NULL) {
62 WARN("invalid parameter\n");
66 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj);
69 static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface)
71 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
72 ULONG ref = InterlockedIncrement(&(This->ref));
73 TRACE("(%p) ref was %d\n", This, ref - 1);
77 static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface)
79 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
80 ULONG ref = InterlockedDecrement(&(This->ref));
81 TRACE("(%p) ref was %d\n", This, ref + 1);
84 This->dsb->notify = NULL;
85 IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb);
86 HeapFree(GetProcessHeap(), 0, This);
87 TRACE("(%p) released\n", This);
92 static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(
93 LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify
95 IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface;
96 TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
98 if (howmuch > 0 && notify == NULL) {
99 WARN("invalid parameter: notify == NULL\n");
100 return DSERR_INVALIDPARAM;
103 if (TRACE_ON(dsound)) {
105 for (i=0;i<howmuch;i++)
106 TRACE("notify at %d to %p\n",
107 notify[i].dwOffset,notify[i].hEventNotify);
111 /* Make an internal copy of the caller-supplied array.
112 * Replace the existing copy if one is already present. */
113 HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
114 This->dsb->notifies = HeapAlloc(GetProcessHeap(), 0,
115 howmuch * sizeof(DSBPOSITIONNOTIFY));
117 if (This->dsb->notifies == NULL) {
118 WARN("out of memory\n");
119 return DSERR_OUTOFMEMORY;
121 CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
122 This->dsb->nrofnotifies = howmuch;
124 HeapFree(GetProcessHeap(), 0, This->dsb->notifies);
125 This->dsb->notifies = NULL;
126 This->dsb->nrofnotifies = 0;
132 static const IDirectSoundNotifyVtbl dsnvt =
134 IDirectSoundNotifyImpl_QueryInterface,
135 IDirectSoundNotifyImpl_AddRef,
136 IDirectSoundNotifyImpl_Release,
137 IDirectSoundNotifyImpl_SetNotificationPositions,
140 static HRESULT IDirectSoundNotifyImpl_Create(
141 IDirectSoundBufferImpl * dsb,
142 IDirectSoundNotifyImpl **pdsn)
144 IDirectSoundNotifyImpl * dsn;
145 TRACE("(%p,%p)\n",dsb,pdsn);
147 dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dsn));
150 WARN("out of memory\n");
151 return DSERR_OUTOFMEMORY;
155 dsn->lpVtbl = &dsnvt;
158 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
164 static HRESULT IDirectSoundNotifyImpl_Destroy(
165 IDirectSoundNotifyImpl *pdsn)
167 TRACE("(%p)\n",pdsn);
169 while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0);
174 /*******************************************************************************
178 static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
180 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
183 static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
185 return This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER ? TRUE : FALSE;
188 static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
189 LPCWAVEFORMATEX wfex)
191 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
193 TRACE("(%p,%p)\n", iface, wfex);
195 if (is_primary_buffer(This))
196 return primarybuffer_SetFormat(This->device, wfex);
198 WARN("not available for secondary buffers.\n");
199 return DSERR_INVALIDCALL;
203 static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
205 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
208 HRESULT hres = DS_OK;
210 TRACE("(%p,%d)\n",This,vol);
212 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
213 WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
214 return DSERR_CONTROLUNAVAIL;
217 if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
218 WARN("invalid parameter: vol = %d\n", vol);
219 return DSERR_INVALIDPARAM;
223 RtlAcquireResourceExclusive(&This->lock, TRUE);
225 if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
226 oldVol = This->ds3db_lVolume;
227 This->ds3db_lVolume = vol;
229 /* recalc 3d volume, which in turn recalcs the pans */
230 DSOUND_Calc3DBuffer(This);
232 oldVol = This->volpan.lVolume;
233 This->volpan.lVolume = vol;
235 DSOUND_RecalcVolPan(&(This->volpan));
238 RtlReleaseResource(&This->lock);
244 static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
246 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
248 TRACE("(%p,%p)\n",This,vol);
250 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
251 WARN("control unavailable\n");
252 return DSERR_CONTROLUNAVAIL;
256 WARN("invalid parameter: vol == NULL\n");
257 return DSERR_INVALIDPARAM;
260 *vol = This->volpan.lVolume;
265 static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
267 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
270 TRACE("(%p,%d)\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 = %d\n", freq);
287 return DSERR_INVALIDPARAM;
291 RtlAcquireResourceExclusive(&This->lock, TRUE);
293 oldFreq = This->freq;
295 if (freq != oldFreq) {
296 This->freqAdjust = ((DWORD64)This->freq << DSOUND_FREQSHIFT) / This->device->pwfx->nSamplesPerSec;
297 This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
298 DSOUND_RecalcFormat(This);
301 RtlReleaseResource(&This->lock);
307 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
308 DWORD reserved2, DWORD flags)
310 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
311 HRESULT hres = DS_OK;
313 TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
316 RtlAcquireResourceExclusive(&This->lock, TRUE);
318 This->playflags = flags;
319 if (This->state == STATE_STOPPED) {
321 This->state = STATE_STARTING;
322 } else if (This->state == STATE_STOPPING)
323 This->state = STATE_PLAYING;
325 RtlReleaseResource(&This->lock);
331 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
333 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
334 HRESULT hres = DS_OK;
336 TRACE("(%p)\n",This);
339 RtlAcquireResourceExclusive(&This->lock, TRUE);
341 if (This->state == STATE_PLAYING)
342 This->state = STATE_STOPPING;
343 else if (This->state == STATE_STARTING)
345 This->state = STATE_STOPPED;
346 DSOUND_CheckEvent(This, 0, 0);
349 RtlReleaseResource(&This->lock);
355 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
357 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
358 ULONG ref = InterlockedIncrement(&This->ref);
360 TRACE("(%p) ref was %d\n", This, ref - 1);
363 InterlockedIncrement(&This->numIfaces);
368 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
370 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
371 ULONG ref = InterlockedDecrement(&This->ref);
373 TRACE("(%p) ref was %d\n", This, ref + 1);
375 if (!ref && !InterlockedDecrement(&This->numIfaces)) {
376 if (is_primary_buffer(This))
377 primarybuffer_destroy(This);
379 secondarybuffer_destroy(This);
384 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
385 DWORD *playpos, DWORD *writepos)
387 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
390 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
392 RtlAcquireResourceShared(&This->lock, TRUE);
394 pos = This->sec_mixpos;
397 if (pos >= This->buflen){
398 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
407 if (writepos && This->state != STATE_STOPPED) {
408 /* apply the documented 10ms lead to writepos */
409 *writepos += This->writelead;
410 *writepos %= This->buflen;
413 RtlReleaseResource(&This->lock);
415 TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
416 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
421 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
423 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
425 TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
427 if (status == NULL) {
428 WARN("invalid parameter: status = NULL\n");
429 return DSERR_INVALIDPARAM;
433 RtlAcquireResourceShared(&This->lock, TRUE);
434 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
435 *status |= DSBSTATUS_PLAYING;
436 if (This->playflags & DSBPLAY_LOOPING)
437 *status |= DSBSTATUS_LOOPING;
439 RtlReleaseResource(&This->lock);
441 TRACE("status=%x\n", *status);
446 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
447 LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
449 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
452 TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
454 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
456 if (lpwf) { /* NULL is valid */
457 if (wfsize >= size) {
458 CopyMemory(lpwf,This->pwfx,size);
462 WARN("invalid parameter: wfsize too small\n");
463 CopyMemory(lpwf,This->pwfx,wfsize);
466 return DSERR_INVALIDPARAM;
470 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
472 WARN("invalid parameter: wfwritten == NULL\n");
473 return DSERR_INVALIDPARAM;
480 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
481 DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
482 DWORD *audiobytes2, DWORD flags)
484 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
485 HRESULT hres = DS_OK;
487 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
488 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
491 return DSERR_INVALIDPARAM;
493 /* when this flag is set, writecursor is meaningless and must be calculated */
494 if (flags & DSBLOCK_FROMWRITECURSOR) {
495 /* GetCurrentPosition does too much magic to duplicate here */
496 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
498 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
503 /* when this flag is set, writebytes is meaningless and must be set */
504 if (flags & DSBLOCK_ENTIREBUFFER)
505 writebytes = This->buflen;
507 if (writecursor >= This->buflen) {
508 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
509 writecursor, This->buflen);
510 return DSERR_INVALIDPARAM;
513 if (writebytes > This->buflen) {
514 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
515 writebytes, This->buflen);
516 return DSERR_INVALIDPARAM;
520 RtlAcquireResourceShared(&This->lock, TRUE);
522 if (writecursor+writebytes <= This->buflen) {
523 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
524 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
525 WARN("Overwriting mixing position, case 1\n");
526 *audiobytes1 = writebytes;
528 *(LPBYTE*)lplpaudioptr2 = NULL;
531 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
532 *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
533 TRACE("->%d.0\n",writebytes);
535 DWORD remainder = writebytes + writecursor - This->buflen;
536 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
537 *audiobytes1 = This->buflen-writecursor;
538 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
539 WARN("Overwriting mixing position, case 2\n");
541 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
543 *audiobytes2 = writebytes-(This->buflen-writecursor);
544 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
545 WARN("Overwriting mixing position, case 3\n");
546 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
549 RtlReleaseResource(&This->lock);
555 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
558 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
559 HRESULT hres = DS_OK;
562 TRACE("(%p,%d)\n",This,newpos);
565 RtlAcquireResourceExclusive(&This->lock, TRUE);
567 oldpos = This->sec_mixpos;
569 /* start mixing from this new location instead */
570 newpos %= This->buflen;
571 newpos -= newpos%This->pwfx->nBlockAlign;
572 This->sec_mixpos = newpos;
574 /* at this point, do not attempt to reset buffers, mess with primary mix position,
575 or anything like that to reduce latency. The data already prebuffered cannot be changed */
577 /* position HW buffer if applicable, else just start mixing from new location instead */
578 if (oldpos != newpos)
579 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
581 RtlReleaseResource(&This->lock);
587 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
589 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
590 HRESULT hres = DS_OK;
592 TRACE("(%p,%d)\n",This,pan);
594 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
595 WARN("invalid parameter: pan = %d\n", pan);
596 return DSERR_INVALIDPARAM;
599 /* You cannot use both pan and 3D controls */
600 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
601 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
602 WARN("control unavailable\n");
603 return DSERR_CONTROLUNAVAIL;
607 RtlAcquireResourceExclusive(&This->lock, TRUE);
609 if (This->volpan.lPan != pan) {
610 This->volpan.lPan = pan;
611 DSOUND_RecalcVolPan(&(This->volpan));
614 RtlReleaseResource(&This->lock);
620 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
622 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
624 TRACE("(%p,%p)\n",This,pan);
626 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
627 WARN("control unavailable\n");
628 return DSERR_CONTROLUNAVAIL;
632 WARN("invalid parameter: pan = NULL\n");
633 return DSERR_INVALIDPARAM;
636 *pan = This->volpan.lPan;
641 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
644 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
645 HRESULT hres = DS_OK;
647 TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
652 if((p1 && ((BYTE*)p1 < This->buffer->memory ||
653 (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
654 (p2 && ((BYTE*)p2 < This->buffer->memory ||
655 (BYTE*)p2 >= This->buffer->memory + This->buflen)))
656 return DSERR_INVALIDPARAM;
660 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
661 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
663 RtlAcquireResourceShared(&iter->lock, TRUE);
666 if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
667 hres = DSERR_INVALIDPARAM;
669 RtlReleaseResource(&iter->lock);
671 RtlReleaseResource(&This->device->buffer_list_lock);
677 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
679 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
681 FIXME("(%p):stub\n",This);
685 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
687 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
689 TRACE("(%p,%p)\n",This,freq);
692 WARN("invalid parameter: freq = NULL\n");
693 return DSERR_INVALIDPARAM;
697 TRACE("-> %d\n", *freq);
702 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
703 LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
705 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
708 FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
711 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
713 WARN("control unavailable\n");
714 return DSERR_CONTROLUNAVAIL;
717 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
718 DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
720 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
723 FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
726 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
728 WARN("control unavailable\n");
732 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
733 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
735 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
737 FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
739 WARN("control unavailable\n");
740 return DSERR_CONTROLUNAVAIL;
743 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
744 IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
746 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
748 WARN("(%p) already initialized\n", This);
749 return DSERR_ALREADYINITIALIZED;
752 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
754 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
756 TRACE("(%p)->(%p)\n",This,caps);
759 WARN("invalid parameter: caps == NULL\n");
760 return DSERR_INVALIDPARAM;
763 if (caps->dwSize < sizeof(*caps)) {
764 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
765 return DSERR_INVALIDPARAM;
768 caps->dwFlags = This->dsbd.dwFlags;
769 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
771 caps->dwBufferBytes = This->buflen;
773 /* According to windows, this is zero*/
774 caps->dwUnlockTransferRate = 0;
775 caps->dwPlayCpuOverhead = 0;
780 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
783 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
785 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
788 WARN("invalid parameter\n");
792 *ppobj = NULL; /* assume failure */
794 if ( IsEqualGUID(riid, &IID_IUnknown) ||
795 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
796 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
797 IDirectSoundBuffer8_AddRef(iface);
802 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
804 IDirectSoundNotifyImpl_Create(This, &(This->notify));
806 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
807 *ppobj = This->notify;
810 WARN("IID_IDirectSoundNotify\n");
811 return E_NOINTERFACE;
814 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
816 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
818 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
819 *ppobj = This->ds3db;
822 WARN("IID_IDirectSound3DBuffer\n");
823 return E_NOINTERFACE;
826 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
827 ERR("app requested IDirectSound3DListener on secondary buffer\n");
828 return E_NOINTERFACE;
831 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
832 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
833 *ppobj = &This->IKsPropertySet_iface;
837 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
839 return E_NOINTERFACE;
842 static const IDirectSoundBuffer8Vtbl dsbvt =
844 IDirectSoundBufferImpl_QueryInterface,
845 IDirectSoundBufferImpl_AddRef,
846 IDirectSoundBufferImpl_Release,
847 IDirectSoundBufferImpl_GetCaps,
848 IDirectSoundBufferImpl_GetCurrentPosition,
849 IDirectSoundBufferImpl_GetFormat,
850 IDirectSoundBufferImpl_GetVolume,
851 IDirectSoundBufferImpl_GetPan,
852 IDirectSoundBufferImpl_GetFrequency,
853 IDirectSoundBufferImpl_GetStatus,
854 IDirectSoundBufferImpl_Initialize,
855 IDirectSoundBufferImpl_Lock,
856 IDirectSoundBufferImpl_Play,
857 IDirectSoundBufferImpl_SetCurrentPosition,
858 IDirectSoundBufferImpl_SetFormat,
859 IDirectSoundBufferImpl_SetVolume,
860 IDirectSoundBufferImpl_SetPan,
861 IDirectSoundBufferImpl_SetFrequency,
862 IDirectSoundBufferImpl_Stop,
863 IDirectSoundBufferImpl_Unlock,
864 IDirectSoundBufferImpl_Restore,
865 IDirectSoundBufferImpl_SetFX,
866 IDirectSoundBufferImpl_AcquireResources,
867 IDirectSoundBufferImpl_GetObjectInPath
870 HRESULT IDirectSoundBufferImpl_Create(
871 DirectSoundDevice * device,
872 IDirectSoundBufferImpl **pdsb,
873 LPCDSBUFFERDESC dsbd)
875 IDirectSoundBufferImpl *dsb;
876 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
879 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
881 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
882 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
884 return DSERR_INVALIDPARAM; /* FIXME: which error? */
887 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
890 WARN("out of memory\n");
892 return DSERR_OUTOFMEMORY;
895 TRACE("Created buffer at %p\n", dsb);
900 dsb->device = device;
901 dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
902 dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
904 /* size depends on version */
905 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
907 dsb->pwfx = DSOUND_CopyFormat(wfex);
908 if (dsb->pwfx == NULL) {
909 HeapFree(GetProcessHeap(),0,dsb);
911 return DSERR_OUTOFMEMORY;
914 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
915 dsb->buflen = dsbd->dwBufferBytes +
916 (dsbd->lpwfxFormat->nBlockAlign -
917 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
919 dsb->buflen = dsbd->dwBufferBytes;
921 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
923 dsb->notifies = NULL;
924 dsb->nrofnotifies = 0;
926 /* Check necessary hardware mixing capabilities */
927 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
928 else capf |= DSCAPS_SECONDARYMONO;
929 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
930 else capf |= DSCAPS_SECONDARY8BIT;
932 TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
934 /* Allocate an empty buffer */
935 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
936 if (dsb->buffer == NULL) {
937 WARN("out of memory\n");
938 HeapFree(GetProcessHeap(),0,dsb->pwfx);
939 HeapFree(GetProcessHeap(),0,dsb);
941 return DSERR_OUTOFMEMORY;
944 /* Allocate system memory for buffer */
945 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
946 if (dsb->buffer->memory == NULL) {
947 WARN("out of memory\n");
948 HeapFree(GetProcessHeap(),0,dsb->pwfx);
949 HeapFree(GetProcessHeap(),0,dsb->buffer);
950 HeapFree(GetProcessHeap(),0,dsb);
952 return DSERR_OUTOFMEMORY;
955 dsb->buffer->ref = 1;
956 list_init(&dsb->buffer->buffers);
957 list_add_head(&dsb->buffer->buffers, &dsb->entry);
958 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
960 /* It's not necessary to initialize values to zero since */
961 /* we allocated this structure with HEAP_ZERO_MEMORY... */
962 dsb->buf_mixpos = dsb->sec_mixpos = 0;
963 dsb->state = STATE_STOPPED;
965 dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
966 dsb->nAvgBytesPerSec = dsb->freq *
967 dsbd->lpwfxFormat->nBlockAlign;
969 /* calculate fragment size and write lead */
970 DSOUND_RecalcFormat(dsb);
972 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
973 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
974 dsb->ds3db_ds3db.vPosition.x = 0.0;
975 dsb->ds3db_ds3db.vPosition.y = 0.0;
976 dsb->ds3db_ds3db.vPosition.z = 0.0;
977 dsb->ds3db_ds3db.vVelocity.x = 0.0;
978 dsb->ds3db_ds3db.vVelocity.y = 0.0;
979 dsb->ds3db_ds3db.vVelocity.z = 0.0;
980 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
981 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
982 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
983 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
984 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
985 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
986 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
987 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
988 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
990 dsb->ds3db_need_recalc = FALSE;
991 DSOUND_Calc3DBuffer(dsb);
993 DSOUND_RecalcVolPan(&(dsb->volpan));
995 RtlInitializeResource(&dsb->lock);
997 /* register buffer if not primary */
998 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
999 err = DirectSoundDevice_AddBuffer(device, dsb);
1001 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1002 HeapFree(GetProcessHeap(),0,dsb->buffer);
1003 RtlDeleteResource(&dsb->lock);
1004 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1005 HeapFree(GetProcessHeap(),0,dsb);
1010 IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1015 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1017 DirectSoundDevice_RemoveBuffer(This->device, This);
1018 RtlDeleteResource(&This->lock);
1020 This->buffer->ref--;
1021 list_remove(&This->entry);
1022 if (This->buffer->ref == 0) {
1023 HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1024 HeapFree(GetProcessHeap(), 0, This->buffer);
1027 HeapFree(GetProcessHeap(), 0, This->notifies);
1028 HeapFree(GetProcessHeap(), 0, This->pwfx);
1029 HeapFree(GetProcessHeap(), 0, This);
1031 TRACE("(%p) released\n", This);
1034 HRESULT IDirectSoundBufferImpl_Destroy(
1035 IDirectSoundBufferImpl *pdsb)
1037 TRACE("(%p)\n",pdsb);
1039 /* This keeps the *_Destroy functions from possibly deleting
1040 * this object until it is ready to be deleted */
1041 InterlockedIncrement(&pdsb->numIfaces);
1044 WARN("ds3db not NULL\n");
1045 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1050 WARN("notify not NULL\n");
1051 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1052 pdsb->notify = NULL;
1055 secondarybuffer_destroy(pdsb);
1060 HRESULT IDirectSoundBufferImpl_Duplicate(
1061 DirectSoundDevice *device,
1062 IDirectSoundBufferImpl **ppdsb,
1063 IDirectSoundBufferImpl *pdsb)
1065 IDirectSoundBufferImpl *dsb;
1066 HRESULT hres = DS_OK;
1067 TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1069 dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1071 WARN("out of memory\n");
1073 return DSERR_OUTOFMEMORY;
1076 RtlAcquireResourceShared(&pdsb->lock, TRUE);
1078 CopyMemory(dsb, pdsb, sizeof(*dsb));
1080 dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1082 RtlReleaseResource(&pdsb->lock);
1084 if (dsb->pwfx == NULL) {
1085 HeapFree(GetProcessHeap(),0,dsb);
1087 return DSERR_OUTOFMEMORY;
1091 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1095 dsb->state = STATE_STOPPED;
1096 dsb->buf_mixpos = dsb->sec_mixpos = 0;
1098 dsb->notifies = NULL;
1099 dsb->nrofnotifies = 0;
1100 dsb->device = device;
1102 DSOUND_RecalcFormat(dsb);
1104 RtlInitializeResource(&dsb->lock);
1106 /* register buffer */
1107 hres = DirectSoundDevice_AddBuffer(device, dsb);
1108 if (hres != DS_OK) {
1109 RtlDeleteResource(&dsb->lock);
1110 list_remove(&dsb->entry);
1112 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1113 HeapFree(GetProcessHeap(),0,dsb);
1117 IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1122 /*******************************************************************************
1126 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1128 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1131 /* IUnknown methods */
1132 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1135 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1137 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1139 return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1142 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1144 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1145 ULONG ref = InterlockedIncrement(&This->refiks);
1147 TRACE("(%p) ref was %d\n", This, ref - 1);
1150 InterlockedIncrement(&This->numIfaces);
1155 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1157 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1158 ULONG ref = InterlockedDecrement(&This->refiks);
1160 TRACE("(%p) ref was %d\n", This, ref + 1);
1162 if (!ref && !InterlockedDecrement(&This->numIfaces)) {
1163 if (is_primary_buffer(This))
1164 primarybuffer_destroy(This);
1166 secondarybuffer_destroy(This);
1171 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1172 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1173 ULONG cbPropData, ULONG *pcbReturned)
1175 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1177 TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1178 This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1180 return E_PROP_ID_UNSUPPORTED;
1183 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1184 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1187 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1189 TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1191 return E_PROP_ID_UNSUPPORTED;
1194 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1195 ULONG dwPropID, ULONG *pTypeSupport)
1197 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1199 TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1201 return E_PROP_ID_UNSUPPORTED;
1204 const IKsPropertySetVtbl iksbvt = {
1205 IKsPropertySetImpl_QueryInterface,
1206 IKsPropertySetImpl_AddRef,
1207 IKsPropertySetImpl_Release,
1208 IKsPropertySetImpl_Get,
1209 IKsPropertySetImpl_Set,
1210 IKsPropertySetImpl_QuerySupport