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);
299 DSOUND_MixToTemporary(This, 0, This->buflen, FALSE);
302 RtlReleaseResource(&This->lock);
308 static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
309 DWORD reserved2, DWORD flags)
311 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
312 HRESULT hres = DS_OK;
314 TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
317 RtlAcquireResourceExclusive(&This->lock, TRUE);
319 This->playflags = flags;
320 if (This->state == STATE_STOPPED) {
322 This->state = STATE_STARTING;
323 } else if (This->state == STATE_STOPPING)
324 This->state = STATE_PLAYING;
326 RtlReleaseResource(&This->lock);
332 static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
334 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
335 HRESULT hres = DS_OK;
337 TRACE("(%p)\n",This);
340 RtlAcquireResourceExclusive(&This->lock, TRUE);
342 if (This->state == STATE_PLAYING)
343 This->state = STATE_STOPPING;
344 else if (This->state == STATE_STARTING)
346 This->state = STATE_STOPPED;
347 DSOUND_CheckEvent(This, 0, 0);
350 RtlReleaseResource(&This->lock);
356 static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
358 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
359 ULONG ref = InterlockedIncrement(&This->ref);
361 TRACE("(%p) ref was %d\n", This, ref - 1);
364 InterlockedIncrement(&This->numIfaces);
369 static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
371 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
372 ULONG ref = InterlockedDecrement(&This->ref);
374 TRACE("(%p) ref was %d\n", This, ref + 1);
376 if (!ref && !InterlockedDecrement(&This->numIfaces)) {
377 if (is_primary_buffer(This))
378 primarybuffer_destroy(This);
380 secondarybuffer_destroy(This);
385 static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
386 DWORD *playpos, DWORD *writepos)
388 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
391 TRACE("(%p,%p,%p)\n",This,playpos,writepos);
393 RtlAcquireResourceShared(&This->lock, TRUE);
395 pos = This->sec_mixpos;
398 if (pos >= This->buflen){
399 FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
408 if (writepos && This->state != STATE_STOPPED) {
409 /* apply the documented 10ms lead to writepos */
410 *writepos += This->writelead;
411 *writepos %= This->buflen;
414 RtlReleaseResource(&This->lock);
416 TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
417 playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
422 static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
424 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
426 TRACE("(%p,%p), thread is %04x\n",This,status,GetCurrentThreadId());
428 if (status == NULL) {
429 WARN("invalid parameter: status = NULL\n");
430 return DSERR_INVALIDPARAM;
434 RtlAcquireResourceShared(&This->lock, TRUE);
435 if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
436 *status |= DSBSTATUS_PLAYING;
437 if (This->playflags & DSBPLAY_LOOPING)
438 *status |= DSBSTATUS_LOOPING;
440 RtlReleaseResource(&This->lock);
442 TRACE("status=%x\n", *status);
447 static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
448 LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
450 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
453 TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
455 size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
457 if (lpwf) { /* NULL is valid */
458 if (wfsize >= size) {
459 CopyMemory(lpwf,This->pwfx,size);
463 WARN("invalid parameter: wfsize too small\n");
464 CopyMemory(lpwf,This->pwfx,wfsize);
467 return DSERR_INVALIDPARAM;
471 *wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
473 WARN("invalid parameter: wfwritten == NULL\n");
474 return DSERR_INVALIDPARAM;
481 static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
482 DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
483 DWORD *audiobytes2, DWORD flags)
485 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
486 HRESULT hres = DS_OK;
488 TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
489 audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
492 return DSERR_INVALIDPARAM;
494 /* when this flag is set, writecursor is meaningless and must be calculated */
495 if (flags & DSBLOCK_FROMWRITECURSOR) {
496 /* GetCurrentPosition does too much magic to duplicate here */
497 hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
499 WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
504 /* when this flag is set, writebytes is meaningless and must be set */
505 if (flags & DSBLOCK_ENTIREBUFFER)
506 writebytes = This->buflen;
508 if (writecursor >= This->buflen) {
509 WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
510 writecursor, This->buflen);
511 return DSERR_INVALIDPARAM;
514 if (writebytes > This->buflen) {
515 WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
516 writebytes, This->buflen);
517 return DSERR_INVALIDPARAM;
521 RtlAcquireResourceShared(&This->lock, TRUE);
523 if (writecursor+writebytes <= This->buflen) {
524 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
525 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
526 WARN("Overwriting mixing position, case 1\n");
527 *audiobytes1 = writebytes;
529 *(LPBYTE*)lplpaudioptr2 = NULL;
532 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
533 *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
534 TRACE("->%d.0\n",writebytes);
536 DWORD remainder = writebytes + writecursor - This->buflen;
537 *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
538 *audiobytes1 = This->buflen-writecursor;
539 if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING)
540 WARN("Overwriting mixing position, case 2\n");
542 *(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
544 *audiobytes2 = writebytes-(This->buflen-writecursor);
545 if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING)
546 WARN("Overwriting mixing position, case 3\n");
547 TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
550 RtlReleaseResource(&This->lock);
556 static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
559 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
560 HRESULT hres = DS_OK;
563 TRACE("(%p,%d)\n",This,newpos);
566 RtlAcquireResourceExclusive(&This->lock, TRUE);
568 oldpos = This->sec_mixpos;
570 /* start mixing from this new location instead */
571 newpos %= This->buflen;
572 newpos -= newpos%This->pwfx->nBlockAlign;
573 This->sec_mixpos = newpos;
575 /* at this point, do not attempt to reset buffers, mess with primary mix position,
576 or anything like that to reduce latency. The data already prebuffered cannot be changed */
578 /* position HW buffer if applicable, else just start mixing from new location instead */
579 if (oldpos != newpos)
580 /* FIXME: Perhaps add a call to DSOUND_MixToTemporary here? Not sure it's needed */
581 This->buf_mixpos = DSOUND_secpos_to_bufpos(This, newpos, 0, NULL);
583 RtlReleaseResource(&This->lock);
589 static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
591 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
592 HRESULT hres = DS_OK;
594 TRACE("(%p,%d)\n",This,pan);
596 if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
597 WARN("invalid parameter: pan = %d\n", pan);
598 return DSERR_INVALIDPARAM;
601 /* You cannot use both pan and 3D controls */
602 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) ||
603 (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) {
604 WARN("control unavailable\n");
605 return DSERR_CONTROLUNAVAIL;
609 RtlAcquireResourceExclusive(&This->lock, TRUE);
611 if (This->volpan.lPan != pan) {
612 This->volpan.lPan = pan;
613 DSOUND_RecalcVolPan(&(This->volpan));
616 RtlReleaseResource(&This->lock);
622 static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
624 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
626 TRACE("(%p,%p)\n",This,pan);
628 if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
629 WARN("control unavailable\n");
630 return DSERR_CONTROLUNAVAIL;
634 WARN("invalid parameter: pan = NULL\n");
635 return DSERR_INVALIDPARAM;
638 *pan = This->volpan.lPan;
643 static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
646 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
647 HRESULT hres = DS_OK;
649 TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
654 if((p1 && ((BYTE*)p1 < This->buffer->memory ||
655 (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
656 (p2 && ((BYTE*)p2 < This->buffer->memory ||
657 (BYTE*)p2 >= This->buffer->memory + This->buflen)))
658 return DSERR_INVALIDPARAM;
662 RtlAcquireResourceShared(&This->device->buffer_list_lock, TRUE);
663 LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
665 RtlAcquireResourceShared(&iter->lock, TRUE);
668 if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
669 hres = DSERR_INVALIDPARAM;
671 DSOUND_MixToTemporary(iter, (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory, x1, FALSE);
674 DSOUND_MixToTemporary(iter, 0, x2, FALSE);
675 RtlReleaseResource(&iter->lock);
677 RtlReleaseResource(&This->device->buffer_list_lock);
683 static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
685 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
687 FIXME("(%p):stub\n",This);
691 static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
693 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
695 TRACE("(%p,%p)\n",This,freq);
698 WARN("invalid parameter: freq = NULL\n");
699 return DSERR_INVALIDPARAM;
703 TRACE("-> %d\n", *freq);
708 static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
709 LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
711 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
714 FIXME("(%p,%u,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes);
717 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
719 WARN("control unavailable\n");
720 return DSERR_CONTROLUNAVAIL;
723 static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
724 DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
726 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
729 FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
732 for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
734 WARN("control unavailable\n");
738 static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
739 REFGUID rguidObject, DWORD dwIndex, REFGUID rguidInterface, void **ppObject)
741 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
743 FIXME("(%p,%s,%u,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
745 WARN("control unavailable\n");
746 return DSERR_CONTROLUNAVAIL;
749 static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
750 IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
752 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
754 WARN("(%p) already initialized\n", This);
755 return DSERR_ALREADYINITIALIZED;
758 static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
760 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
762 TRACE("(%p)->(%p)\n",This,caps);
765 WARN("invalid parameter: caps == NULL\n");
766 return DSERR_INVALIDPARAM;
769 if (caps->dwSize < sizeof(*caps)) {
770 WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
771 return DSERR_INVALIDPARAM;
774 caps->dwFlags = This->dsbd.dwFlags;
775 caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
777 caps->dwBufferBytes = This->buflen;
779 /* According to windows, this is zero*/
780 caps->dwUnlockTransferRate = 0;
781 caps->dwPlayCpuOverhead = 0;
786 static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
789 IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
791 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
794 WARN("invalid parameter\n");
798 *ppobj = NULL; /* assume failure */
800 if ( IsEqualGUID(riid, &IID_IUnknown) ||
801 IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
802 IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
803 IDirectSoundBuffer8_AddRef(iface);
808 if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
810 IDirectSoundNotifyImpl_Create(This, &(This->notify));
812 IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify);
813 *ppobj = This->notify;
816 WARN("IID_IDirectSoundNotify\n");
817 return E_NOINTERFACE;
820 if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
822 IDirectSound3DBufferImpl_Create(This, &(This->ds3db));
824 IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db);
825 *ppobj = This->ds3db;
828 WARN("IID_IDirectSound3DBuffer\n");
829 return E_NOINTERFACE;
832 if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
833 ERR("app requested IDirectSound3DListener on secondary buffer\n");
834 return E_NOINTERFACE;
837 if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
839 IKsBufferPropertySetImpl_Create(This, &(This->iks));
841 IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks);
845 WARN("IID_IKsPropertySet\n");
846 return E_NOINTERFACE;
849 FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
851 return E_NOINTERFACE;
854 static const IDirectSoundBuffer8Vtbl dsbvt =
856 IDirectSoundBufferImpl_QueryInterface,
857 IDirectSoundBufferImpl_AddRef,
858 IDirectSoundBufferImpl_Release,
859 IDirectSoundBufferImpl_GetCaps,
860 IDirectSoundBufferImpl_GetCurrentPosition,
861 IDirectSoundBufferImpl_GetFormat,
862 IDirectSoundBufferImpl_GetVolume,
863 IDirectSoundBufferImpl_GetPan,
864 IDirectSoundBufferImpl_GetFrequency,
865 IDirectSoundBufferImpl_GetStatus,
866 IDirectSoundBufferImpl_Initialize,
867 IDirectSoundBufferImpl_Lock,
868 IDirectSoundBufferImpl_Play,
869 IDirectSoundBufferImpl_SetCurrentPosition,
870 IDirectSoundBufferImpl_SetFormat,
871 IDirectSoundBufferImpl_SetVolume,
872 IDirectSoundBufferImpl_SetPan,
873 IDirectSoundBufferImpl_SetFrequency,
874 IDirectSoundBufferImpl_Stop,
875 IDirectSoundBufferImpl_Unlock,
876 IDirectSoundBufferImpl_Restore,
877 IDirectSoundBufferImpl_SetFX,
878 IDirectSoundBufferImpl_AcquireResources,
879 IDirectSoundBufferImpl_GetObjectInPath
882 HRESULT IDirectSoundBufferImpl_Create(
883 DirectSoundDevice * device,
884 IDirectSoundBufferImpl **pdsb,
885 LPCDSBUFFERDESC dsbd)
887 IDirectSoundBufferImpl *dsb;
888 LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
891 TRACE("(%p,%p,%p)\n",device,pdsb,dsbd);
893 if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
894 WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
896 return DSERR_INVALIDPARAM; /* FIXME: which error? */
899 dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
902 WARN("out of memory\n");
904 return DSERR_OUTOFMEMORY;
907 TRACE("Created buffer at %p\n", dsb);
911 dsb->device = device;
912 dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
915 /* size depends on version */
916 CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
918 dsb->pwfx = DSOUND_CopyFormat(wfex);
919 if (dsb->pwfx == NULL) {
920 HeapFree(GetProcessHeap(),0,dsb);
922 return DSERR_OUTOFMEMORY;
925 if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
926 dsb->buflen = dsbd->dwBufferBytes +
927 (dsbd->lpwfxFormat->nBlockAlign -
928 (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
930 dsb->buflen = dsbd->dwBufferBytes;
932 dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
934 dsb->notifies = NULL;
935 dsb->nrofnotifies = 0;
937 /* Check necessary hardware mixing capabilities */
938 if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
939 else capf |= DSCAPS_SECONDARYMONO;
940 if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
941 else capf |= DSCAPS_SECONDARY8BIT;
943 TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
945 /* Allocate an empty buffer */
946 dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer)));
947 if (dsb->buffer == NULL) {
948 WARN("out of memory\n");
949 HeapFree(GetProcessHeap(),0,dsb->pwfx);
950 HeapFree(GetProcessHeap(),0,dsb);
952 return DSERR_OUTOFMEMORY;
955 /* Allocate system memory for buffer */
956 dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen);
957 if (dsb->buffer->memory == NULL) {
958 WARN("out of memory\n");
959 HeapFree(GetProcessHeap(),0,dsb->pwfx);
960 HeapFree(GetProcessHeap(),0,dsb->buffer);
961 HeapFree(GetProcessHeap(),0,dsb);
963 return DSERR_OUTOFMEMORY;
966 dsb->buffer->ref = 1;
967 list_init(&dsb->buffer->buffers);
968 list_add_head(&dsb->buffer->buffers, &dsb->entry);
969 FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
971 /* It's not necessary to initialize values to zero since */
972 /* we allocated this structure with HEAP_ZERO_MEMORY... */
973 dsb->buf_mixpos = dsb->sec_mixpos = 0;
974 dsb->state = STATE_STOPPED;
976 dsb->freqAdjust = ((DWORD64)dsb->freq << DSOUND_FREQSHIFT) / device->pwfx->nSamplesPerSec;
977 dsb->nAvgBytesPerSec = dsb->freq *
978 dsbd->lpwfxFormat->nBlockAlign;
980 /* calculate fragment size and write lead */
981 DSOUND_RecalcFormat(dsb);
983 if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
984 dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
985 dsb->ds3db_ds3db.vPosition.x = 0.0;
986 dsb->ds3db_ds3db.vPosition.y = 0.0;
987 dsb->ds3db_ds3db.vPosition.z = 0.0;
988 dsb->ds3db_ds3db.vVelocity.x = 0.0;
989 dsb->ds3db_ds3db.vVelocity.y = 0.0;
990 dsb->ds3db_ds3db.vVelocity.z = 0.0;
991 dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
992 dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
993 dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
994 dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
995 dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
996 dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
997 dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
998 dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
999 dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
1001 dsb->ds3db_need_recalc = FALSE;
1002 DSOUND_Calc3DBuffer(dsb);
1004 DSOUND_RecalcVolPan(&(dsb->volpan));
1006 RtlInitializeResource(&dsb->lock);
1008 /* register buffer if not primary */
1009 if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) {
1010 err = DirectSoundDevice_AddBuffer(device, dsb);
1012 HeapFree(GetProcessHeap(),0,dsb->buffer->memory);
1013 HeapFree(GetProcessHeap(),0,dsb->buffer);
1014 RtlDeleteResource(&dsb->lock);
1015 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1016 HeapFree(GetProcessHeap(),0,dsb);
1025 void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
1027 DirectSoundDevice_RemoveBuffer(This->device, This);
1028 RtlDeleteResource(&This->lock);
1030 This->buffer->ref--;
1031 list_remove(&This->entry);
1032 if (This->buffer->ref == 0) {
1033 HeapFree(GetProcessHeap(), 0, This->buffer->memory);
1034 HeapFree(GetProcessHeap(), 0, This->buffer);
1037 HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
1038 HeapFree(GetProcessHeap(), 0, This->notifies);
1039 HeapFree(GetProcessHeap(), 0, This->pwfx);
1040 HeapFree(GetProcessHeap(), 0, This);
1042 TRACE("(%p) released\n", This);
1045 HRESULT IDirectSoundBufferImpl_Destroy(
1046 IDirectSoundBufferImpl *pdsb)
1048 TRACE("(%p)\n",pdsb);
1050 /* This keeps the *_Destroy functions from possibly deleting
1051 * this object until it is ready to be deleted */
1052 InterlockedIncrement(&pdsb->numIfaces);
1055 WARN("iks not NULL\n");
1056 IKsBufferPropertySetImpl_Destroy(pdsb->iks);
1061 WARN("ds3db not NULL\n");
1062 IDirectSound3DBufferImpl_Destroy(pdsb->ds3db);
1067 WARN("notify not NULL\n");
1068 IDirectSoundNotifyImpl_Destroy(pdsb->notify);
1069 pdsb->notify = NULL;
1072 secondarybuffer_destroy(pdsb);
1077 HRESULT IDirectSoundBufferImpl_Duplicate(
1078 DirectSoundDevice *device,
1079 IDirectSoundBufferImpl **ppdsb,
1080 IDirectSoundBufferImpl *pdsb)
1082 IDirectSoundBufferImpl *dsb;
1083 HRESULT hres = DS_OK;
1084 TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
1086 dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
1088 WARN("out of memory\n");
1090 return DSERR_OUTOFMEMORY;
1092 CopyMemory(dsb, pdsb, sizeof(*dsb));
1094 dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
1095 if (dsb->pwfx == NULL) {
1096 HeapFree(GetProcessHeap(),0,dsb);
1098 return DSERR_OUTOFMEMORY;
1102 list_add_head(&dsb->buffer->buffers, &dsb->entry);
1105 dsb->state = STATE_STOPPED;
1106 dsb->buf_mixpos = dsb->sec_mixpos = 0;
1108 dsb->notifies = NULL;
1109 dsb->nrofnotifies = 0;
1110 dsb->device = device;
1112 dsb->iks = NULL; /* FIXME? */
1113 dsb->tmp_buffer = NULL;
1114 DSOUND_RecalcFormat(dsb);
1115 DSOUND_MixToTemporary(dsb, 0, dsb->buflen, FALSE);
1117 RtlInitializeResource(&dsb->lock);
1119 /* register buffer */
1120 hres = DirectSoundDevice_AddBuffer(device, dsb);
1121 if (hres != DS_OK) {
1122 RtlDeleteResource(&dsb->lock);
1123 HeapFree(GetProcessHeap(),0,dsb->tmp_buffer);
1124 list_remove(&dsb->entry);
1126 HeapFree(GetProcessHeap(),0,dsb->pwfx);
1127 HeapFree(GetProcessHeap(),0,dsb);
1135 /*******************************************************************************
1136 * IKsBufferPropertySet
1139 /* IUnknown methods */
1140 static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface(
1141 LPKSPROPERTYSET iface,
1145 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1146 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
1148 return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj);
1151 static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface)
1153 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1154 ULONG ref = InterlockedIncrement(&(This->ref));
1155 TRACE("(%p) ref was %d\n", This, ref - 1);
1159 static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface)
1161 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1162 ULONG ref = InterlockedDecrement(&(This->ref));
1163 TRACE("(%p) ref was %d\n", This, ref + 1);
1167 IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb);
1168 HeapFree(GetProcessHeap(), 0, This);
1169 TRACE("(%p) released\n", This);
1174 static HRESULT WINAPI IKsBufferPropertySetImpl_Get(
1175 LPKSPROPERTYSET iface,
1176 REFGUID guidPropSet,
1178 LPVOID pInstanceData,
1179 ULONG cbInstanceData,
1182 PULONG pcbReturned )
1184 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1186 TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
1187 This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
1189 return E_PROP_ID_UNSUPPORTED;
1192 static HRESULT WINAPI IKsBufferPropertySetImpl_Set(
1193 LPKSPROPERTYSET iface,
1194 REFGUID guidPropSet,
1196 LPVOID pInstanceData,
1197 ULONG cbInstanceData,
1201 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1203 TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
1205 return E_PROP_ID_UNSUPPORTED;
1208 static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport(
1209 LPKSPROPERTYSET iface,
1210 REFGUID guidPropSet,
1212 PULONG pTypeSupport )
1214 IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface;
1216 TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
1218 return E_PROP_ID_UNSUPPORTED;
1221 static const IKsPropertySetVtbl iksbvt = {
1222 IKsBufferPropertySetImpl_QueryInterface,
1223 IKsBufferPropertySetImpl_AddRef,
1224 IKsBufferPropertySetImpl_Release,
1225 IKsBufferPropertySetImpl_Get,
1226 IKsBufferPropertySetImpl_Set,
1227 IKsBufferPropertySetImpl_QuerySupport
1230 HRESULT IKsBufferPropertySetImpl_Create(
1231 IDirectSoundBufferImpl *dsb,
1232 IKsBufferPropertySetImpl **piks)
1234 IKsBufferPropertySetImpl *iks;
1235 TRACE("(%p,%p)\n",dsb,piks);
1238 iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks));
1240 WARN("out of memory\n");
1242 return DSERR_OUTOFMEMORY;
1248 iks->lpVtbl = &iksbvt;
1250 IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb);
1256 HRESULT IKsBufferPropertySetImpl_Destroy(
1257 IKsBufferPropertySetImpl *piks)
1259 TRACE("(%p)\n",piks);
1261 while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0);