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 ) ) {
815 IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
816 *ppobj = &This->IDirectSound3DBuffer_iface;
820 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
821 ERR("app requested IDirectSound3DListener on secondary buffer\n");
822 return E_NOINTERFACE;
825 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
826 IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
827 *ppobj = &This->IKsPropertySet_iface;
831 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
833 return E_NOINTERFACE;
836 static const IDirectSoundBuffer8Vtbl dsbvt =
838 IDirectSoundBufferImpl_QueryInterface,
839 IDirectSoundBufferImpl_AddRef,
840 IDirectSoundBufferImpl_Release,
841 IDirectSoundBufferImpl_GetCaps,
842 IDirectSoundBufferImpl_GetCurrentPosition,
843 IDirectSoundBufferImpl_GetFormat,
844 IDirectSoundBufferImpl_GetVolume,
845 IDirectSoundBufferImpl_GetPan,
846 IDirectSoundBufferImpl_GetFrequency,
847 IDirectSoundBufferImpl_GetStatus,
848 IDirectSoundBufferImpl_Initialize,
849 IDirectSoundBufferImpl_Lock,
850 IDirectSoundBufferImpl_Play,
851 IDirectSoundBufferImpl_SetCurrentPosition,
852 IDirectSoundBufferImpl_SetFormat,
853 IDirectSoundBufferImpl_SetVolume,
854 IDirectSoundBufferImpl_SetPan,
855 IDirectSoundBufferImpl_SetFrequency,
856 IDirectSoundBufferImpl_Stop,
857 IDirectSoundBufferImpl_Unlock,
858 IDirectSoundBufferImpl_Restore,
859 IDirectSoundBufferImpl_SetFX,
860 IDirectSoundBufferImpl_AcquireResources,
861 IDirectSoundBufferImpl_GetObjectInPath
864 HRESULT IDirectSoundBufferImpl_Create(
865 DirectSoundDevice * device,
866 IDirectSoundBufferImpl **pdsb,
867 LPCDSBUFFERDESC dsbd)
869 IDirectSoundBufferImpl *dsb;
870 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
873 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
875 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
876 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
878 return DSERR_INVALIDPARAM; /* FIXME: which error? */
881 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
884 WARN("out of memory\n");
886 return DSERR_OUTOFMEMORY;
889 TRACE("Created buffer at %p\n", dsb);
895 dsb->device = device;
896 dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
897 dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
898 dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
900 /* size depends on version */
901 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
903 dsb->pwfx = DSOUND_CopyFormat(wfex);
904 if (dsb->pwfx == NULL) {
905 HeapFree(GetProcessHeap(),0,dsb);
907 return DSERR_OUTOFMEMORY;
910 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
911 dsb->buflen = dsbd->dwBufferBytes +
912 (dsbd->lpwfxFormat->nBlockAlign -
913 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
915 dsb->buflen = dsbd->dwBufferBytes;
917 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
919 dsb->notifies = NULL;
920 dsb->nrofnotifies = 0;
922 /* Check necessary hardware mixing capabilities */
923 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
924 else capf |= DSCAPS_SECONDARYMONO;
925 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
926 else capf |= DSCAPS_SECONDARY8BIT;
928 TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
930 /* Allocate an empty buffer */
931 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
932 if (dsb->buffer == NULL) {
933 WARN("out of memory\n");
934 HeapFree(GetProcessHeap(),0,dsb->pwfx);
935 HeapFree(GetProcessHeap(),0,dsb);
937 return DSERR_OUTOFMEMORY;
940 /* Allocate system memory for buffer */
941 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
942 if (dsb->buffer->memory == NULL) {
943 WARN("out of memory\n");
944 HeapFree(GetProcessHeap(),0,dsb->pwfx);
945 HeapFree(GetProcessHeap(),0,dsb->buffer);
946 HeapFree(GetProcessHeap(),0,dsb);
948 return DSERR_OUTOFMEMORY;
951 dsb->buffer->ref = 1;
952 list_init(&dsb->buffer->buffers);
953 list_add_head(&dsb->buffer->buffers, &dsb->entry);
954 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
956 /* It's not necessary to initialize values to zero since */
957 /* we allocated this structure with HEAP_ZERO_MEMORY... */
958 dsb->buf_mixpos = dsb->sec_mixpos = 0;
959 dsb->state = STATE_STOPPED;
961 dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
962 dsb->nAvgBytesPerSec = dsb->freq *
963 dsbd->lpwfxFormat->nBlockAlign;
965 /* calculate fragment size and write lead */
966 DSOUND_RecalcFormat(dsb);
968 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
969 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
970 dsb->ds3db_ds3db.vPosition.x = 0.0;
971 dsb->ds3db_ds3db.vPosition.y = 0.0;
972 dsb->ds3db_ds3db.vPosition.z = 0.0;
973 dsb->ds3db_ds3db.vVelocity.x = 0.0;
974 dsb->ds3db_ds3db.vVelocity.y = 0.0;
975 dsb->ds3db_ds3db.vVelocity.z = 0.0;
976 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
977 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
978 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
979 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
980 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
981 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
982 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
983 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
984 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
986 dsb->ds3db_need_recalc = FALSE;
987 DSOUND_Calc3DBuffer(dsb);
989 DSOUND_RecalcVolPan(&(dsb->volpan));
991 RtlInitializeResource(&dsb->lock);
993 /* register buffer if not primary */
994 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
995 err = DirectSoundDevice_AddBuffer(device, dsb);
997 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
998 HeapFree(GetProcessHeap(),0,dsb->buffer);
999 RtlDeleteResource(&dsb->lock);
1000 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1001 HeapFree(GetProcessHeap(),0,dsb);
1006 IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1011 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1013 DirectSoundDevice_RemoveBuffer(This->device, This);
1014 RtlDeleteResource(&This->lock);
1016 This->buffer->ref--;
1017 list_remove(&This->entry);
1018 if (This->buffer->ref == 0) {
1019 HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1020 HeapFree(GetProcessHeap(), 0, This->buffer);
1023 HeapFree(GetProcessHeap(), 0, This->notifies);
1024 HeapFree(GetProcessHeap(), 0, This->pwfx);
1025 HeapFree(GetProcessHeap(), 0, This);
1027 TRACE("(%p) released\n", This);
1030 HRESULT IDirectSoundBufferImpl_Destroy(
1031 IDirectSoundBufferImpl *pdsb)
1033 TRACE("(%p)\n",pdsb);
1035 /* This keeps the *_Destroy functions from possibly deleting
1036 * this object until it is ready to be deleted */
1037 InterlockedIncrement(&pdsb->numIfaces);
1040 WARN("notify not NULL\n");
1041 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1042 pdsb->notify = NULL;
1045 secondarybuffer_destroy(pdsb);
1050 HRESULT IDirectSoundBufferImpl_Duplicate(
1051 DirectSoundDevice *device,
1052 IDirectSoundBufferImpl **ppdsb,
1053 IDirectSoundBufferImpl *pdsb)
1055 IDirectSoundBufferImpl *dsb;
1056 HRESULT hres = DS_OK;
1057 TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1059 dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1061 WARN("out of memory\n");
1063 return DSERR_OUTOFMEMORY;
1066 RtlAcquireResourceShared(&pdsb->lock, TRUE);
1068 CopyMemory(dsb, pdsb, sizeof(*dsb));
1070 dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1072 RtlReleaseResource(&pdsb->lock);
1074 if (dsb->pwfx == NULL) {
1075 HeapFree(GetProcessHeap(),0,dsb);
1077 return DSERR_OUTOFMEMORY;
1081 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1086 dsb->state = STATE_STOPPED;
1087 dsb->buf_mixpos = dsb->sec_mixpos = 0;
1089 dsb->notifies = NULL;
1090 dsb->nrofnotifies = 0;
1091 dsb->device = device;
1092 DSOUND_RecalcFormat(dsb);
1094 RtlInitializeResource(&dsb->lock);
1096 /* register buffer */
1097 hres = DirectSoundDevice_AddBuffer(device, dsb);
1098 if (hres != DS_OK) {
1099 RtlDeleteResource(&dsb->lock);
1100 list_remove(&dsb->entry);
1102 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1103 HeapFree(GetProcessHeap(),0,dsb);
1107 IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
1112 /*******************************************************************************
1116 static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
1118 return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
1121 /* IUnknown methods */
1122 static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
1125 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1127 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1129 return IDirectSoundBuffer_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
1132 static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
1134 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1135 ULONG ref = InterlockedIncrement(&This->refiks);
1137 TRACE("(%p) ref was %d\n", This, ref - 1);
1140 InterlockedIncrement(&This->numIfaces);
1145 static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
1147 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1148 ULONG ref = InterlockedDecrement(&This->refiks);
1150 TRACE("(%p) ref was %d\n", This, ref + 1);
1152 if (!ref && !InterlockedDecrement(&This->numIfaces)) {
1153 if (is_primary_buffer(This))
1154 primarybuffer_destroy(This);
1156 secondarybuffer_destroy(This);
1161 static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
1162 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1163 ULONG cbPropData, ULONG *pcbReturned)
1165 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1167 TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1168 This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1170 return E_PROP_ID_UNSUPPORTED;
1173 static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
1174 ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
1177 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1179 TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1181 return E_PROP_ID_UNSUPPORTED;
1184 static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
1185 ULONG dwPropID, ULONG *pTypeSupport)
1187 IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
1189 TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1191 return E_PROP_ID_UNSUPPORTED;
1194 const IKsPropertySetVtbl iksbvt = {
1195 IKsPropertySetImpl_QueryInterface,
1196 IKsPropertySetImpl_AddRef,
1197 IKsPropertySetImpl_Release,
1198 IKsPropertySetImpl_Get,
1199 IKsPropertySetImpl_Set,
1200 IKsPropertySetImpl_QuerySupport