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 ) ) {
833 IKsBufferPropertySetImpl_Create(This, &(This->iks));
835 IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
839 WARN("IID_IKsPropertySet\n");
840 return E_NOINTERFACE;
843 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
845 return E_NOINTERFACE;
848 static const IDirectSoundBuffer8Vtbl dsbvt =
850 IDirectSoundBufferImpl_QueryInterface,
851 IDirectSoundBufferImpl_AddRef,
852 IDirectSoundBufferImpl_Release,
853 IDirectSoundBufferImpl_GetCaps,
854 IDirectSoundBufferImpl_GetCurrentPosition,
855 IDirectSoundBufferImpl_GetFormat,
856 IDirectSoundBufferImpl_GetVolume,
857 IDirectSoundBufferImpl_GetPan,
858 IDirectSoundBufferImpl_GetFrequency,
859 IDirectSoundBufferImpl_GetStatus,
860 IDirectSoundBufferImpl_Initialize,
861 IDirectSoundBufferImpl_Lock,
862 IDirectSoundBufferImpl_Play,
863 IDirectSoundBufferImpl_SetCurrentPosition,
864 IDirectSoundBufferImpl_SetFormat,
865 IDirectSoundBufferImpl_SetVolume,
866 IDirectSoundBufferImpl_SetPan,
867 IDirectSoundBufferImpl_SetFrequency,
868 IDirectSoundBufferImpl_Stop,
869 IDirectSoundBufferImpl_Unlock,
870 IDirectSoundBufferImpl_Restore,
871 IDirectSoundBufferImpl_SetFX,
872 IDirectSoundBufferImpl_AcquireResources,
873 IDirectSoundBufferImpl_GetObjectInPath
876 HRESULT IDirectSoundBufferImpl_Create(
877 DirectSoundDevice * device,
878 IDirectSoundBufferImpl **pdsb,
879 LPCDSBUFFERDESC dsbd)
881 IDirectSoundBufferImpl *dsb;
882 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
885 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
887 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
888 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
890 return DSERR_INVALIDPARAM; /* FIXME: which error? */
893 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
896 WARN("out of memory\n");
898 return DSERR_OUTOFMEMORY;
901 TRACE("Created buffer at %p\n", dsb);
905 dsb->device = device;
906 dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
909 /* size depends on version */
910 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
912 dsb->pwfx = DSOUND_CopyFormat(wfex);
913 if (dsb->pwfx == NULL) {
914 HeapFree(GetProcessHeap(),0,dsb);
916 return DSERR_OUTOFMEMORY;
919 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
920 dsb->buflen = dsbd->dwBufferBytes +
921 (dsbd->lpwfxFormat->nBlockAlign -
922 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
924 dsb->buflen = dsbd->dwBufferBytes;
926 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
928 dsb->notifies = NULL;
929 dsb->nrofnotifies = 0;
931 /* Check necessary hardware mixing capabilities */
932 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
933 else capf |= DSCAPS_SECONDARYMONO;
934 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
935 else capf |= DSCAPS_SECONDARY8BIT;
937 TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
939 /* Allocate an empty buffer */
940 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
941 if (dsb->buffer == NULL) {
942 WARN("out of memory\n");
943 HeapFree(GetProcessHeap(),0,dsb->pwfx);
944 HeapFree(GetProcessHeap(),0,dsb);
946 return DSERR_OUTOFMEMORY;
949 /* Allocate system memory for buffer */
950 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
951 if (dsb->buffer->memory == NULL) {
952 WARN("out of memory\n");
953 HeapFree(GetProcessHeap(),0,dsb->pwfx);
954 HeapFree(GetProcessHeap(),0,dsb->buffer);
955 HeapFree(GetProcessHeap(),0,dsb);
957 return DSERR_OUTOFMEMORY;
960 dsb->buffer->ref = 1;
961 list_init(&dsb->buffer->buffers);
962 list_add_head(&dsb->buffer->buffers, &dsb->entry);
963 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
965 /* It's not necessary to initialize values to zero since */
966 /* we allocated this structure with HEAP_ZERO_MEMORY... */
967 dsb->buf_mixpos = dsb->sec_mixpos = 0;
968 dsb->state = STATE_STOPPED;
970 dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
971 dsb->nAvgBytesPerSec = dsb->freq *
972 dsbd->lpwfxFormat->nBlockAlign;
974 /* calculate fragment size and write lead */
975 DSOUND_RecalcFormat(dsb);
977 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
978 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
979 dsb->ds3db_ds3db.vPosition.x = 0.0;
980 dsb->ds3db_ds3db.vPosition.y = 0.0;
981 dsb->ds3db_ds3db.vPosition.z = 0.0;
982 dsb->ds3db_ds3db.vVelocity.x = 0.0;
983 dsb->ds3db_ds3db.vVelocity.y = 0.0;
984 dsb->ds3db_ds3db.vVelocity.z = 0.0;
985 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
986 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
987 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
988 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
989 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
990 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
991 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
992 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
993 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
995 dsb->ds3db_need_recalc = FALSE;
996 DSOUND_Calc3DBuffer(dsb);
998 DSOUND_RecalcVolPan(&(dsb->volpan));
1000 RtlInitializeResource(&dsb->lock);
1002 /* register buffer if not primary */
1003 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1004 err = DirectSoundDevice_AddBuffer(device, dsb);
1006 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1007 HeapFree(GetProcessHeap(),0,dsb->buffer);
1008 RtlDeleteResource(&dsb->lock);
1009 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1010 HeapFree(GetProcessHeap(),0,dsb);
1019 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1021 DirectSoundDevice_RemoveBuffer(This->device, This);
1022 RtlDeleteResource(&This->lock);
1024 This->buffer->ref--;
1025 list_remove(&This->entry);
1026 if (This->buffer->ref == 0) {
1027 HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1028 HeapFree(GetProcessHeap(), 0, This->buffer);
1031 HeapFree(GetProcessHeap(), 0, This->notifies);
1032 HeapFree(GetProcessHeap(), 0, This->pwfx);
1033 HeapFree(GetProcessHeap(), 0, This);
1035 TRACE("(%p) released\n", This);
1038 HRESULT IDirectSoundBufferImpl_Destroy(
1039 IDirectSoundBufferImpl *pdsb)
1041 TRACE("(%p)\n",pdsb);
1043 /* This keeps the *_Destroy functions from possibly deleting
1044 * this object until it is ready to be deleted */
1045 InterlockedIncrement(&pdsb->numIfaces);
1048 WARN("iks not NULL\n");
1049 IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1054 WARN("ds3db not NULL\n");
1055 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1060 WARN("notify not NULL\n");
1061 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1062 pdsb->notify = NULL;
1065 secondarybuffer_destroy(pdsb);
1070 HRESULT IDirectSoundBufferImpl_Duplicate(
1071 DirectSoundDevice *device,
1072 IDirectSoundBufferImpl **ppdsb,
1073 IDirectSoundBufferImpl *pdsb)
1075 IDirectSoundBufferImpl *dsb;
1076 HRESULT hres = DS_OK;
1077 TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1079 dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1081 WARN("out of memory\n");
1083 return DSERR_OUTOFMEMORY;
1085 CopyMemory(dsb, pdsb, sizeof(*dsb));
1087 dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1088 if (dsb->pwfx == NULL) {
1089 HeapFree(GetProcessHeap(),0,dsb);
1091 return DSERR_OUTOFMEMORY;
1095 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1098 dsb->state = STATE_STOPPED;
1099 dsb->buf_mixpos = dsb->sec_mixpos = 0;
1101 dsb->notifies = NULL;
1102 dsb->nrofnotifies = 0;
1103 dsb->device = device;
1105 dsb->iks = NULL; /* FIXME? */
1106 DSOUND_RecalcFormat(dsb);
1108 RtlInitializeResource(&dsb->lock);
1110 /* register buffer */
1111 hres = DirectSoundDevice_AddBuffer(device, dsb);
1112 if (hres != DS_OK) {
1113 RtlDeleteResource(&dsb->lock);
1114 list_remove(&dsb->entry);
1116 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1117 HeapFree(GetProcessHeap(),0,dsb);
1125 /*******************************************************************************
1126 * IKsBufferPropertySet
1129 /* IUnknown methods */
1130 static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
1131 LPKSPROPERTYSET iface,
1135 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1136 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1138 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
1141 static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
1143 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1144 ULONG ref = InterlockedIncrement(&(This->ref));
1145 TRACE("(%p) ref was %d\n", This, ref - 1);
1149 static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
1151 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1152 ULONG ref = InterlockedDecrement(&(This->ref));
1153 TRACE("(%p) ref was %d\n", This, ref + 1);
1157 IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
1158 HeapFree(GetProcessHeap(), 0, This);
1159 TRACE("(%p) released\n", This);
1164 static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
1165 LPKSPROPERTYSET iface,
1166 REFGUID guidPropSet,
1168 LPVOID pInstanceData,
1169 ULONG cbInstanceData,
1172 PULONG pcbReturned )
1174 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1176 TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1177 This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1179 return E_PROP_ID_UNSUPPORTED;
1182 static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
1183 LPKSPROPERTYSET iface,
1184 REFGUID guidPropSet,
1186 LPVOID pInstanceData,
1187 ULONG cbInstanceData,
1191 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1193 TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1195 return E_PROP_ID_UNSUPPORTED;
1198 static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
1199 LPKSPROPERTYSET iface,
1200 REFGUID guidPropSet,
1202 PULONG pTypeSupport )
1204 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1206 TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1208 return E_PROP_ID_UNSUPPORTED;
1211 static const IKsPropertySetVtbl iksbvt = {
1212 IKsBufferPropertySetImpl_QueryInterface,
1213 IKsBufferPropertySetImpl_AddRef,
1214 IKsBufferPropertySetImpl_Release,
1215 IKsBufferPropertySetImpl_Get,
1216 IKsBufferPropertySetImpl_Set,
1217 IKsBufferPropertySetImpl_QuerySupport
1220 HRESULT IKsBufferPropertySetImpl_Create(
1221 IDirectSoundBufferImpl *dsb,
1222 IKsBufferPropertySetImpl **piks)
1224 IKsBufferPropertySetImpl *iks;
1225 TRACE("(%p,%p)\n",dsb,piks);
1228 iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
1230 WARN("out of memory\n");
1232 return DSERR_OUTOFMEMORY;
1238 iks->lpVtbl = &iksbvt;
1240 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
1246 HRESULT IKsBufferPropertySetImpl_Destroy(
1247 IKsBufferPropertySetImpl *piks)
1249 TRACE("(%p)\n",piks);
1251 while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);