wine/dlls/dsound/buffer.c
Eduard Permyakov 975d0632a1 dsound: Commit next audio chunk between play cursor and write cursor to playing.
This region of the audio buffer is forbidden to be written to by the
DirectSound specification. The documentation states: "The write cursor
is the point after which it is safe to write data into the buffer. The
block between the play cursor and the write cursor is already committed
to be played, and cannot be changed safely." However, some applications
still do this, which has lead to audio glitches only when using the Wine
DirectSound implementation. Experiments showed that the native DirctSound
implementation will still play the old audio the first time around when the
buffer region gets overwritten. Use an approach of copying the next forbidden
region into a "committed buffer" to add the same behavior to the Wine
implementation.

Out of performance considerations, only copy data to the committed buffer
when we detect that an overwrite is possible (i.e. the current mixing
region of the buffer gets locked).

Signed-off-by: Eduard Permyakov <epermyakov@codeweavers.com>
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2021-09-20 22:48:41 +02:00

1370 lines
40 KiB
C

/* DirectSound
*
* Copyright 1998 Marcus Meissner
* Copyright 1998 Rob Riggs
* Copyright 2000-2002 TransGaming Technologies, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "mmsystem.h"
#include "vfwmsgs.h"
#include "wine/debug.h"
#include "dsound.h"
#include "dsound_private.h"
#include "dsconf.h"
WINE_DEFAULT_DEBUG_CHANNEL(dsound);
/*******************************************************************************
* IDirectSoundNotify
*/
static inline struct IDirectSoundBufferImpl *impl_from_IDirectSoundNotify(IDirectSoundNotify *iface)
{
return CONTAINING_RECORD(iface, struct IDirectSoundBufferImpl, IDirectSoundNotify_iface);
}
static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface(IDirectSoundNotify *iface, REFIID riid,
void **ppobj)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj);
return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
}
static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(IDirectSoundNotify *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
ULONG ref = InterlockedIncrement(&This->refn);
TRACE("(%p) ref %d\n", This, ref);
if(ref == 1)
InterlockedIncrement(&This->numIfaces);
return ref;
}
static ULONG WINAPI IDirectSoundNotifyImpl_Release(IDirectSoundNotify *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
ULONG ref = InterlockedDecrement(&This->refn);
TRACE("(%p) ref %d\n", This, ref);
if (!ref && !InterlockedDecrement(&This->numIfaces))
secondarybuffer_destroy(This);
return ref;
}
static int __cdecl notify_compar(const void *l, const void *r)
{
const DSBPOSITIONNOTIFY *left = l;
const DSBPOSITIONNOTIFY *right = r;
/* place DSBPN_OFFSETSTOP at the start of the sorted array */
if(left->dwOffset == DSBPN_OFFSETSTOP){
if(right->dwOffset != DSBPN_OFFSETSTOP)
return -1;
}else if(right->dwOffset == DSBPN_OFFSETSTOP)
return 1;
if(left->dwOffset == right->dwOffset)
return 0;
if(left->dwOffset < right->dwOffset)
return -1;
return 1;
}
static void commit_next_chunk(IDirectSoundBufferImpl *dsb)
{
void *dstbuff = dsb->committedbuff, *srcbuff = dsb->buffer->memory;
DWORD srcoff = dsb->sec_mixpos, srcsize = dsb->buflen, cpysize = dsb->writelead;
if(dsb->state != STATE_PLAYING)
return;
if(cpysize > srcsize - srcoff) {
DWORD overflow = cpysize - (srcsize - srcoff);
memcpy(dstbuff, (BYTE*)srcbuff + srcoff, srcsize - srcoff);
memcpy((BYTE*)dstbuff + (srcsize - srcoff), srcbuff, overflow);
}else{
memcpy(dstbuff, (BYTE*)srcbuff + srcoff, cpysize);
}
dsb->use_committed = TRUE;
dsb->committed_mixpos = 0;
TRACE("committing %u bytes from offset %u\n", dsb->writelead, dsb->sec_mixpos);
}
static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions(IDirectSoundNotify *iface,
DWORD howmuch, const DSBPOSITIONNOTIFY *notify)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundNotify(iface);
TRACE("(%p,0x%08x,%p)\n",This,howmuch,notify);
if (howmuch > 0 && notify == NULL) {
WARN("invalid parameter: notify == NULL\n");
return DSERR_INVALIDPARAM;
}
if (TRACE_ON(dsound)) {
unsigned int i;
for (i=0;i<howmuch;i++)
TRACE("notify at %d to %p\n",
notify[i].dwOffset,notify[i].hEventNotify);
}
if (howmuch > 0) {
/* Make an internal copy of the caller-supplied array.
* Replace the existing copy if one is already present. */
HeapFree(GetProcessHeap(), 0, This->notifies);
This->notifies = HeapAlloc(GetProcessHeap(), 0,
howmuch * sizeof(DSBPOSITIONNOTIFY));
if (This->notifies == NULL) {
WARN("out of memory\n");
return DSERR_OUTOFMEMORY;
}
CopyMemory(This->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY));
This->nrofnotifies = howmuch;
qsort(This->notifies, howmuch, sizeof(DSBPOSITIONNOTIFY), notify_compar);
} else {
HeapFree(GetProcessHeap(), 0, This->notifies);
This->notifies = NULL;
This->nrofnotifies = 0;
}
return S_OK;
}
static const IDirectSoundNotifyVtbl dsnvt =
{
IDirectSoundNotifyImpl_QueryInterface,
IDirectSoundNotifyImpl_AddRef,
IDirectSoundNotifyImpl_Release,
IDirectSoundNotifyImpl_SetNotificationPositions,
};
/*******************************************************************************
* IDirectSoundBuffer
*/
static inline IDirectSoundBufferImpl *impl_from_IDirectSoundBuffer8(IDirectSoundBuffer8 *iface)
{
return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IDirectSoundBuffer8_iface);
}
static inline BOOL is_primary_buffer(IDirectSoundBufferImpl *This)
{
return (This->dsbd.dwFlags & DSBCAPS_PRIMARYBUFFER) != 0;
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(IDirectSoundBuffer8 *iface,
LPCWAVEFORMATEX wfex)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%p)\n", iface, wfex);
if (is_primary_buffer(This))
return primarybuffer_SetFormat(This->device, wfex);
else {
WARN("not available for secondary buffers.\n");
return DSERR_INVALIDCALL;
}
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume(IDirectSoundBuffer8 *iface, LONG vol)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
LONG oldVol;
HRESULT hres = DS_OK;
TRACE("(%p,%d)\n",This,vol);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
WARN("control unavailable: This->dsbd.dwFlags = 0x%08x\n", This->dsbd.dwFlags);
return DSERR_CONTROLUNAVAIL;
}
if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) {
WARN("invalid parameter: vol = %d\n", vol);
return DSERR_INVALIDPARAM;
}
AcquireSRWLockExclusive(&This->lock);
if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) {
oldVol = This->ds3db_lVolume;
This->ds3db_lVolume = vol;
if (vol != oldVol)
/* recalc 3d volume, which in turn recalcs the pans */
DSOUND_Calc3DBuffer(This);
} else {
oldVol = This->volpan.lVolume;
This->volpan.lVolume = vol;
if (vol != oldVol)
DSOUND_RecalcVolPan(&(This->volpan));
}
ReleaseSRWLockExclusive(&This->lock);
return hres;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume(IDirectSoundBuffer8 *iface, LONG *vol)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%p)\n",This,vol);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
if (vol == NULL) {
WARN("invalid parameter: vol == NULL\n");
return DSERR_INVALIDPARAM;
}
*vol = This->volpan.lVolume;
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetFrequency(IDirectSoundBuffer8 *iface, DWORD freq)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD oldFreq;
void *newcommitted;
TRACE("(%p,%d)\n",This,freq);
if (is_primary_buffer(This)) {
WARN("not available for primary buffers.\n");
return DSERR_CONTROLUNAVAIL;
}
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
if (freq == DSBFREQUENCY_ORIGINAL)
freq = This->pwfx->nSamplesPerSec;
if ((freq < DSBFREQUENCY_MIN) || (freq > DSBFREQUENCY_MAX)) {
WARN("invalid parameter: freq = %d\n", freq);
return DSERR_INVALIDPARAM;
}
AcquireSRWLockExclusive(&This->lock);
oldFreq = This->freq;
This->freq = freq;
if (freq != oldFreq) {
This->freqAdjustNum = This->freq;
This->freqAdjustDen = This->device->pwfx->nSamplesPerSec;
This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign;
DSOUND_RecalcFormat(This);
newcommitted = HeapReAlloc(GetProcessHeap(), 0, This->committedbuff, This->writelead);
if(!newcommitted) {
ReleaseSRWLockExclusive(&This->lock);
return DSERR_OUTOFMEMORY;
}
This->committedbuff = newcommitted;
}
ReleaseSRWLockExclusive(&This->lock);
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Play(IDirectSoundBuffer8 *iface, DWORD reserved1,
DWORD reserved2, DWORD flags)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
HRESULT hres = DS_OK;
int i;
TRACE("(%p,%08x,%08x,%08x)\n",This,reserved1,reserved2,flags);
AcquireSRWLockExclusive(&This->lock);
This->playflags = flags;
if (This->state == STATE_STOPPED) {
This->leadin = TRUE;
This->state = STATE_STARTING;
}
for (i = 0; i < This->num_filters; i++) {
IMediaObject_Discontinuity(This->filters[i].obj, 0);
}
ReleaseSRWLockExclusive(&This->lock);
return hres;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Stop(IDirectSoundBuffer8 *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
HRESULT hres = DS_OK;
TRACE("(%p)\n",This);
AcquireSRWLockExclusive(&This->lock);
if (This->state == STATE_PLAYING || This->state == STATE_STARTING)
{
This->state = STATE_STOPPED;
This->use_committed = FALSE;
This->committed_mixpos = 0;
DSOUND_CheckEvent(This, 0, 0);
}
ReleaseSRWLockExclusive(&This->lock);
return hres;
}
static ULONG WINAPI IDirectSoundBufferImpl_AddRef(IDirectSoundBuffer8 *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref %d\n", This, ref);
if(ref == 1)
InterlockedIncrement(&This->numIfaces);
return ref;
}
static ULONG WINAPI IDirectSoundBufferImpl_Release(IDirectSoundBuffer8 *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
ULONG ref;
if (is_primary_buffer(This)){
ref = capped_refcount_dec(&This->ref);
if(!ref)
capped_refcount_dec(&This->numIfaces);
TRACE("(%p) ref %d\n", This, ref);
return ref;
}
ref = InterlockedDecrement(&This->ref);
if (!ref && !InterlockedDecrement(&This->numIfaces))
secondarybuffer_destroy(This);
TRACE("(%p) ref %d\n", This, ref);
return ref;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(IDirectSoundBuffer8 *iface,
DWORD *playpos, DWORD *writepos)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD pos;
TRACE("(%p,%p,%p)\n",This,playpos,writepos);
AcquireSRWLockShared(&This->lock);
pos = This->sec_mixpos;
/* sanity */
if (pos >= This->buflen){
FIXME("Bad play position. playpos: %d, buflen: %d\n", pos, This->buflen);
pos %= This->buflen;
}
if (playpos)
*playpos = pos;
if (writepos)
*writepos = pos;
if (writepos && This->state != STATE_STOPPED) {
/* apply the documented 10ms lead to writepos */
*writepos += This->writelead;
*writepos %= This->buflen;
}
ReleaseSRWLockShared(&This->lock);
TRACE("playpos = %d, writepos = %d, buflen=%d (%p, time=%d)\n",
playpos?*playpos:-1, writepos?*writepos:-1, This->buflen, This, GetTickCount());
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus(IDirectSoundBuffer8 *iface, DWORD *status)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%p)\n",This,status);
if (status == NULL) {
WARN("invalid parameter: status = NULL\n");
return DSERR_INVALIDPARAM;
}
*status = 0;
AcquireSRWLockShared(&This->lock);
if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) {
*status |= DSBSTATUS_PLAYING;
if (This->playflags & DSBPLAY_LOOPING)
*status |= DSBSTATUS_LOOPING;
}
if (This->dsbd.dwFlags & DSBCAPS_LOCDEFER)
*status |= DSBSTATUS_LOCSOFTWARE;
ReleaseSRWLockShared(&This->lock);
TRACE("status=%x\n", *status);
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat(IDirectSoundBuffer8 *iface,
LPWAVEFORMATEX lpwf, DWORD wfsize, DWORD *wfwritten)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD size;
TRACE("(%p,%p,%d,%p)\n",This,lpwf,wfsize,wfwritten);
size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
if (lpwf) { /* NULL is valid */
if (wfsize >= size) {
CopyMemory(lpwf,This->pwfx,size);
if (wfwritten)
*wfwritten = size;
} else {
WARN("invalid parameter: wfsize too small\n");
CopyMemory(lpwf,This->pwfx,wfsize);
if (wfwritten)
*wfwritten = wfsize;
return DSERR_INVALIDPARAM;
}
} else {
if (wfwritten)
*wfwritten = sizeof(WAVEFORMATEX) + This->pwfx->cbSize;
else {
WARN("invalid parameter: wfwritten == NULL\n");
return DSERR_INVALIDPARAM;
}
}
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Lock(IDirectSoundBuffer8 *iface, DWORD writecursor,
DWORD writebytes, void **lplpaudioptr1, DWORD *audiobytes1, void **lplpaudioptr2,
DWORD *audiobytes2, DWORD flags)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
HRESULT hres = DS_OK;
TRACE("(%p,%d,%d,%p,%p,%p,%p,0x%08x) at %d\n", This, writecursor, writebytes, lplpaudioptr1,
audiobytes1, lplpaudioptr2, audiobytes2, flags, GetTickCount());
if (!audiobytes1)
return DSERR_INVALIDPARAM;
/* when this flag is set, writecursor is meaningless and must be calculated */
if (flags & DSBLOCK_FROMWRITECURSOR) {
/* GetCurrentPosition does too much magic to duplicate here */
hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writecursor);
if (hres != DS_OK) {
WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n");
return hres;
}
}
/* when this flag is set, writebytes is meaningless and must be set */
if (flags & DSBLOCK_ENTIREBUFFER)
writebytes = This->buflen;
if (writecursor >= This->buflen) {
WARN("Invalid parameter, writecursor: %u >= buflen: %u\n",
writecursor, This->buflen);
return DSERR_INVALIDPARAM;
}
if (writebytes > This->buflen) {
WARN("Invalid parameter, writebytes: %u > buflen: %u\n",
writebytes, This->buflen);
return DSERR_INVALIDPARAM;
}
AcquireSRWLockShared(&This->lock);
if (writecursor+writebytes <= This->buflen) {
*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) {
WARN("Overwriting mixing position, case 1\n");
commit_next_chunk(This);
}
*audiobytes1 = writebytes;
if (lplpaudioptr2)
*(LPBYTE*)lplpaudioptr2 = NULL;
if (audiobytes2)
*audiobytes2 = 0;
TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n",
*(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
TRACE("->%d.0\n",writebytes);
This->buffer->lockedbytes += writebytes;
} else {
DWORD remainder = writebytes + writecursor - This->buflen;
*(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor;
*audiobytes1 = This->buflen-writecursor;
This->buffer->lockedbytes += *audiobytes1;
if (This->sec_mixpos >= writecursor && This->sec_mixpos < writecursor + writebytes && This->state == STATE_PLAYING) {
WARN("Overwriting mixing position, case 2\n");
commit_next_chunk(This);
}
if (lplpaudioptr2)
*(LPBYTE*)lplpaudioptr2 = This->buffer->memory;
if (audiobytes2) {
*audiobytes2 = writebytes-(This->buflen-writecursor);
This->buffer->lockedbytes += *audiobytes2;
}
if (audiobytes2 && This->sec_mixpos < remainder && This->state == STATE_PLAYING) {
WARN("Overwriting mixing position, case 3\n");
commit_next_chunk(This);
}
TRACE("Locked %p(%i bytes) and %p(%i bytes) writecursor=%d\n", *(LPBYTE*)lplpaudioptr1, *audiobytes1, lplpaudioptr2 ? *(LPBYTE*)lplpaudioptr2 : NULL, audiobytes2 ? *audiobytes2: 0, writecursor);
}
ReleaseSRWLockShared(&This->lock);
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition(IDirectSoundBuffer8 *iface,
DWORD newpos)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
HRESULT hres = DS_OK;
TRACE("(%p,%d)\n",This,newpos);
AcquireSRWLockExclusive(&This->lock);
/* start mixing from this new location instead */
newpos %= This->buflen;
newpos -= newpos%This->pwfx->nBlockAlign;
This->sec_mixpos = newpos;
This->use_committed = FALSE;
This->committed_mixpos = 0;
/* at this point, do not attempt to reset buffers, mess with primary mix position,
or anything like that to reduce latency. The data already prebuffered cannot be changed */
ReleaseSRWLockExclusive(&This->lock);
return hres;
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetPan(IDirectSoundBuffer8 *iface, LONG pan)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
HRESULT hres = DS_OK;
TRACE("(%p,%d)\n",This,pan);
if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) {
WARN("invalid parameter: pan = %d\n", pan);
return DSERR_INVALIDPARAM;
}
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
AcquireSRWLockExclusive(&This->lock);
if (This->volpan.lPan != pan) {
This->volpan.lPan = pan;
DSOUND_RecalcVolPan(&(This->volpan));
}
ReleaseSRWLockExclusive(&This->lock);
return hres;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetPan(IDirectSoundBuffer8 *iface, LONG *pan)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%p)\n",This,pan);
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN)) {
WARN("control unavailable\n");
return DSERR_CONTROLUNAVAIL;
}
if (pan == NULL) {
WARN("invalid parameter: pan = NULL\n");
return DSERR_INVALIDPARAM;
}
*pan = This->volpan.lPan;
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Unlock(IDirectSoundBuffer8 *iface, void *p1, DWORD x1,
void *p2, DWORD x2)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface), *iter;
HRESULT hres = DS_OK;
TRACE("(%p,%p,%d,%p,%d)\n", This,p1,x1,p2,x2);
if (!p2)
x2 = 0;
if((p1 && ((BYTE*)p1 < This->buffer->memory || (BYTE*)p1 >= This->buffer->memory + This->buflen)) ||
(p2 && ((BYTE*)p2 < This->buffer->memory || (BYTE*)p2 >= This->buffer->memory + This->buflen)))
return DSERR_INVALIDPARAM;
if (x1 || x2)
{
AcquireSRWLockShared(&This->device->buffer_list_lock);
LIST_FOR_EACH_ENTRY(iter, &This->buffer->buffers, IDirectSoundBufferImpl, entry )
{
AcquireSRWLockShared(&iter->lock);
if (x1)
{
if(x1 + (DWORD_PTR)p1 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
hres = DSERR_INVALIDPARAM;
else
iter->buffer->lockedbytes -= x1;
}
if (x2)
{
if(x2 + (DWORD_PTR)p2 - (DWORD_PTR)iter->buffer->memory > iter->buflen)
hres = DSERR_INVALIDPARAM;
else
iter->buffer->lockedbytes -= x2;
}
ReleaseSRWLockShared(&iter->lock);
}
ReleaseSRWLockShared(&This->device->buffer_list_lock);
}
return hres;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Restore(IDirectSoundBuffer8 *iface)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
FIXME("(%p):stub\n",This);
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency(IDirectSoundBuffer8 *iface, DWORD *freq)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%p)\n",This,freq);
if (freq == NULL) {
WARN("invalid parameter: freq = NULL\n");
return DSERR_INVALIDPARAM;
}
*freq = This->freq;
TRACE("-> %d\n", *freq);
return DS_OK;
}
static const char* dump_DSFX_guid(const DSEFFECTDESC *desc)
{
#define FE(guid) if (IsEqualGUID(&guid, &desc->guidDSFXClass)) return #guid
FE(GUID_DSFX_STANDARD_GARGLE);
FE(GUID_DSFX_STANDARD_CHORUS);
FE(GUID_DSFX_STANDARD_FLANGER);
FE(GUID_DSFX_STANDARD_ECHO);
FE(GUID_DSFX_STANDARD_DISTORTION);
FE(GUID_DSFX_STANDARD_COMPRESSOR);
FE(GUID_DSFX_STANDARD_PARAMEQ);
FE(GUID_DSFX_STANDARD_I3DL2REVERB);
FE(GUID_DSFX_WAVES_REVERB);
#undef FE
return debugstr_guid(&desc->guidDSFXClass);
}
static HRESULT WINAPI IDirectSoundBufferImpl_SetFX(IDirectSoundBuffer8 *iface, DWORD dwEffectsCount,
LPDSEFFECTDESC pDSFXDesc, DWORD *pdwResultCodes)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD u;
DSFilter *filters;
HRESULT hr, hr2;
DMO_MEDIA_TYPE dmt;
WAVEFORMATEX wfx;
TRACE("(%p,%u,%p,%p)\n", This, dwEffectsCount, pDSFXDesc, pdwResultCodes);
if (pdwResultCodes)
for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
if ((dwEffectsCount > 0 && !pDSFXDesc) ||
(dwEffectsCount == 0 && (pDSFXDesc || pdwResultCodes))
)
return E_INVALIDARG;
if (!(This->dsbd.dwFlags & DSBCAPS_CTRLFX)) {
WARN("attempted to call SetFX on buffer without DSBCAPS_CTRLFX\n");
return DSERR_CONTROLUNAVAIL;
}
if (This->state != STATE_STOPPED)
return DSERR_INVALIDCALL;
if (This->buffer->lockedbytes > 0)
return DSERR_INVALIDCALL;
if (dwEffectsCount == 0) {
if (This->num_filters > 0) {
for (u = 0; u < This->num_filters; u++) {
IMediaObject_Release(This->filters[u].obj);
}
HeapFree(GetProcessHeap(), 0, This->filters);
This->filters = NULL;
This->num_filters = 0;
}
return DS_OK;
}
filters = HeapAlloc(GetProcessHeap(), 0, dwEffectsCount * sizeof(DSFilter));
if (!filters) {
WARN("out of memory\n");
return DSERR_OUTOFMEMORY;
}
hr = DS_OK;
wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx.nChannels = This->pwfx->nChannels;
wfx.nSamplesPerSec = This->pwfx->nSamplesPerSec;
wfx.wBitsPerSample = sizeof(float) * 8;
wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample)/8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = sizeof(wfx);
dmt.majortype = KSDATAFORMAT_TYPE_AUDIO;
dmt.subtype = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
dmt.bFixedSizeSamples = TRUE;
dmt.bTemporalCompression = FALSE;
dmt.lSampleSize = sizeof(float) * This->pwfx->nChannels / 8;
dmt.formattype = FORMAT_WaveFormatEx;
dmt.pUnk = NULL;
dmt.cbFormat = sizeof(WAVEFORMATEX);
dmt.pbFormat = (BYTE*)&wfx;
for (u = 0; u < dwEffectsCount; u++) {
TRACE("%d: 0x%08x, %s\n", u, pDSFXDesc[u].dwFlags, dump_DSFX_guid(&pDSFXDesc[u]));
hr2 = CoCreateInstance(&pDSFXDesc[u].guidDSFXClass, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, (LPVOID*)&filters[u].obj);
if (SUCCEEDED(hr2)) {
hr2 = IMediaObject_SetInputType(filters[u].obj, 0, &dmt, 0);
if (FAILED(hr2))
WARN("Could not set DMO input type\n");
}
if (SUCCEEDED(hr2)) {
hr2 = IMediaObject_SetOutputType(filters[u].obj, 0, &dmt, 0);
if (FAILED(hr2))
WARN("Could not set DMO output type\n");
}
if (FAILED(hr2)) {
if (hr == DS_OK)
hr = hr2;
if (pdwResultCodes)
pdwResultCodes[u] = (hr2 == REGDB_E_CLASSNOTREG) ? DSFXR_UNKNOWN : DSFXR_FAILED;
} else {
if (pdwResultCodes)
pdwResultCodes[u] = DSFXR_LOCSOFTWARE;
}
}
if (FAILED(hr)) {
for (u = 0; u < dwEffectsCount; u++) {
if (pdwResultCodes)
pdwResultCodes[u] = (pdwResultCodes[u] != DSFXR_UNKNOWN) ? DSFXR_PRESENT : DSFXR_UNKNOWN;
if (filters[u].obj)
IMediaObject_Release(filters[u].obj);
}
HeapFree(GetProcessHeap(), 0, filters);
} else {
if (This->num_filters > 0) {
for (u = 0; u < This->num_filters; u++) {
IMediaObject_Release(This->filters[u].obj);
if (This->filters[u].inplace) IMediaObjectInPlace_Release(This->filters[u].inplace);
}
HeapFree(GetProcessHeap(), 0, This->filters);
}
for (u = 0; u < dwEffectsCount; u++) {
memcpy(&filters[u].guid, &pDSFXDesc[u].guidDSFXClass, sizeof(GUID));
if (FAILED(IMediaObject_QueryInterface(filters[u].obj, &IID_IMediaObjectInPlace, (void*)&filters[u].inplace)))
filters[u].inplace = NULL;
}
This->filters = filters;
This->num_filters = dwEffectsCount;
}
return hr;
}
static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(IDirectSoundBuffer8 *iface,
DWORD dwFlags, DWORD dwEffectsCount, DWORD *pdwResultCodes)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD u;
FIXME("(%p,%08u,%u,%p): stub, faking success\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
if (pdwResultCodes)
for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
WARN("control unavailable\n");
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(IDirectSoundBuffer8 *iface,
REFGUID clsid, DWORD index, REFGUID iid, void **out)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
DWORD i, count = 0;
TRACE("(%p,%s,%u,%s,%p)\n", This, debugstr_guid(clsid), index, debugstr_guid(iid), out);
if (!out)
return E_INVALIDARG;
for (i = 0; i < This->num_filters; i++)
{
if (IsEqualGUID(clsid, &This->filters[i].guid) || IsEqualGUID(clsid, &GUID_All_Objects))
{
if (count++ == index)
return IMediaObject_QueryInterface(This->filters[i].obj, iid, out);
}
}
return DSERR_OBJECTNOTFOUND;
}
static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(IDirectSoundBuffer8 *iface,
IDirectSound *dsound, LPCDSBUFFERDESC dbsd)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
WARN("(%p) already initialized\n", This);
return DSERR_ALREADYINITIALIZED;
}
static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(IDirectSoundBuffer8 *iface, LPDSBCAPS caps)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p)->(%p)\n",This,caps);
if (caps == NULL) {
WARN("invalid parameter: caps == NULL\n");
return DSERR_INVALIDPARAM;
}
if (caps->dwSize < sizeof(*caps)) {
WARN("invalid parameter: caps->dwSize = %d\n",caps->dwSize);
return DSERR_INVALIDPARAM;
}
caps->dwFlags = This->dsbd.dwFlags;
caps->dwFlags |= DSBCAPS_LOCSOFTWARE;
caps->dwBufferBytes = This->buflen;
/* According to windows, this is zero*/
caps->dwUnlockTransferRate = 0;
caps->dwPlayCpuOverhead = 0;
return DS_OK;
}
static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface(IDirectSoundBuffer8 *iface, REFIID riid,
void **ppobj)
{
IDirectSoundBufferImpl *This = impl_from_IDirectSoundBuffer8(iface);
TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
if (ppobj == NULL) {
WARN("invalid parameter\n");
return E_INVALIDARG;
}
*ppobj = NULL; /* assume failure */
if ( IsEqualGUID(riid, &IID_IUnknown) ||
IsEqualGUID(riid, &IID_IDirectSoundBuffer) ||
IsEqualGUID(riid, &IID_IDirectSoundBuffer8) ) {
IDirectSoundBuffer8_AddRef(iface);
*ppobj = iface;
return S_OK;
}
if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) {
if(This->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY) {
IDirectSoundNotify_AddRef(&This->IDirectSoundNotify_iface);
*ppobj = &This->IDirectSoundNotify_iface;
return S_OK;
}
TRACE( "App requested IDirectSoundNotify without DSBCAPS_CTRLPOSITIONNOTIFY flag.\n");
return E_NOINTERFACE;
}
if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) {
if(This->dsbd.dwFlags & DSBCAPS_CTRL3D){
IDirectSound3DBuffer_AddRef(&This->IDirectSound3DBuffer_iface);
*ppobj = &This->IDirectSound3DBuffer_iface;
return S_OK;
}
TRACE("app requested IDirectSound3DBuffer on non-3D secondary buffer\n");
return E_NOINTERFACE;
}
if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) {
ERR("app requested IDirectSound3DListener on secondary buffer\n");
return E_NOINTERFACE;
}
if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) {
IKsPropertySet_AddRef(&This->IKsPropertySet_iface);
*ppobj = &This->IKsPropertySet_iface;
return S_OK;
}
FIXME( "Unknown IID %s\n", debugstr_guid( riid ) );
return E_NOINTERFACE;
}
static const IDirectSoundBuffer8Vtbl dsbvt =
{
IDirectSoundBufferImpl_QueryInterface,
IDirectSoundBufferImpl_AddRef,
IDirectSoundBufferImpl_Release,
IDirectSoundBufferImpl_GetCaps,
IDirectSoundBufferImpl_GetCurrentPosition,
IDirectSoundBufferImpl_GetFormat,
IDirectSoundBufferImpl_GetVolume,
IDirectSoundBufferImpl_GetPan,
IDirectSoundBufferImpl_GetFrequency,
IDirectSoundBufferImpl_GetStatus,
IDirectSoundBufferImpl_Initialize,
IDirectSoundBufferImpl_Lock,
IDirectSoundBufferImpl_Play,
IDirectSoundBufferImpl_SetCurrentPosition,
IDirectSoundBufferImpl_SetFormat,
IDirectSoundBufferImpl_SetVolume,
IDirectSoundBufferImpl_SetPan,
IDirectSoundBufferImpl_SetFrequency,
IDirectSoundBufferImpl_Stop,
IDirectSoundBufferImpl_Unlock,
IDirectSoundBufferImpl_Restore,
IDirectSoundBufferImpl_SetFX,
IDirectSoundBufferImpl_AcquireResources,
IDirectSoundBufferImpl_GetObjectInPath
};
HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *dsbd,
IDirectSoundBuffer **buffer)
{
IDirectSoundBufferImpl *dsb;
LPWAVEFORMATEX wfex = dsbd->lpwfxFormat;
HRESULT err = DS_OK;
DWORD capf = 0;
size_t bufsize;
TRACE("(%p,%p,%p)\n", device, dsbd, buffer);
if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) {
WARN("invalid parameter: dsbd->dwBufferBytes = %d\n", dsbd->dwBufferBytes);
return DSERR_INVALIDPARAM; /* FIXME: which error? */
}
dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb));
if (!dsb)
return DSERR_OUTOFMEMORY;
TRACE("Created buffer at %p\n", dsb);
dsb->ref = 1;
dsb->refn = 0;
dsb->ref3D = 0;
dsb->refiks = 0;
dsb->numIfaces = 1;
dsb->device = device;
dsb->IDirectSoundBuffer8_iface.lpVtbl = &dsbvt;
dsb->IDirectSoundNotify_iface.lpVtbl = &dsnvt;
dsb->IDirectSound3DBuffer_iface.lpVtbl = &ds3dbvt;
dsb->IKsPropertySet_iface.lpVtbl = &iksbvt;
/* size depends on version */
CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize);
dsb->pwfx = DSOUND_CopyFormat(wfex);
if (!dsb->pwfx) {
IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
return DSERR_OUTOFMEMORY;
}
if (dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign)
dsb->buflen = dsbd->dwBufferBytes +
(dsbd->lpwfxFormat->nBlockAlign -
(dsbd->dwBufferBytes % dsbd->lpwfxFormat->nBlockAlign));
else
dsb->buflen = dsbd->dwBufferBytes;
dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec;
dsb->notifies = NULL;
dsb->nrofnotifies = 0;
/* Check necessary hardware mixing capabilities */
if (wfex->nChannels==2) capf |= DSCAPS_SECONDARYSTEREO;
else capf |= DSCAPS_SECONDARYMONO;
if (wfex->wBitsPerSample==16) capf |= DSCAPS_SECONDARY16BIT;
else capf |= DSCAPS_SECONDARY8BIT;
TRACE("capf = 0x%08x, device->drvcaps.dwFlags = 0x%08x\n", capf, device->drvcaps.dwFlags);
/* Allocate an empty buffer */
bufsize = (sizeof(*(dsb->buffer)) + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
dsb->buffer = HeapAlloc(GetProcessHeap(),0,bufsize + dsb->buflen);
if (!dsb->buffer) {
IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
return DSERR_OUTOFMEMORY;
}
/* Allocate system memory for buffer */
dsb->buffer->memory = (BYTE *)dsb->buffer + bufsize;
dsb->buffer->ref = 1;
dsb->buffer->lockedbytes = 0;
list_init(&dsb->buffer->buffers);
list_add_head(&dsb->buffer->buffers, &dsb->entry);
FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0);
/* It's not necessary to initialize values to zero since */
/* we allocated this structure with HEAP_ZERO_MEMORY... */
dsb->sec_mixpos = 0;
dsb->state = STATE_STOPPED;
dsb->freqAdjustNum = dsb->freq;
dsb->freqAdjustDen = device->pwfx->nSamplesPerSec;
dsb->nAvgBytesPerSec = dsb->freq *
dsbd->lpwfxFormat->nBlockAlign;
/* calculate fragment size and write lead */
DSOUND_RecalcFormat(dsb);
dsb->committedbuff = HeapAlloc(GetProcessHeap(), 0, dsb->writelead);
if(!dsb->committedbuff) {
IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
return DSERR_OUTOFMEMORY;
}
if (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D) {
dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER);
dsb->ds3db_ds3db.vPosition.x = 0.0;
dsb->ds3db_ds3db.vPosition.y = 0.0;
dsb->ds3db_ds3db.vPosition.z = 0.0;
dsb->ds3db_ds3db.vVelocity.x = 0.0;
dsb->ds3db_ds3db.vVelocity.y = 0.0;
dsb->ds3db_ds3db.vVelocity.z = 0.0;
dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE;
dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE;
dsb->ds3db_ds3db.vConeOrientation.x = 0.0;
dsb->ds3db_ds3db.vConeOrientation.y = 0.0;
dsb->ds3db_ds3db.vConeOrientation.z = 0.0;
dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME;
dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE;
dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL;
dsb->ds3db_need_recalc = FALSE;
DSOUND_Calc3DBuffer(dsb);
} else
DSOUND_RecalcVolPan(&(dsb->volpan));
InitializeSRWLock(&dsb->lock);
/* register buffer */
err = DirectSoundDevice_AddBuffer(device, dsb);
if (err == DS_OK)
*buffer = (IDirectSoundBuffer*)&dsb->IDirectSoundBuffer8_iface;
else
IDirectSoundBuffer8_Release(&dsb->IDirectSoundBuffer8_iface);
return err;
}
void secondarybuffer_destroy(IDirectSoundBufferImpl *This)
{
ULONG ref = InterlockedIncrement(&This->numIfaces);
if (ref > 1)
WARN("Destroying buffer with %u in use interfaces\n", ref - 1);
if (This->dsbd.dwFlags & DSBCAPS_LOCHARDWARE)
This->device->drvcaps.dwFreeHwMixingAllBuffers++;
DirectSoundDevice_RemoveBuffer(This->device, This);
This->buffer->ref--;
list_remove(&This->entry);
if (This->buffer->ref == 0)
HeapFree(GetProcessHeap(), 0, This->buffer);
HeapFree(GetProcessHeap(), 0, This->notifies);
HeapFree(GetProcessHeap(), 0, This->pwfx);
HeapFree(GetProcessHeap(), 0, This->committedbuff);
if (This->filters) {
int i;
for (i = 0; i < This->num_filters; i++) {
IMediaObject_Release(This->filters[i].obj);
if (This->filters[i].inplace) IMediaObjectInPlace_Release(This->filters[i].inplace);
}
HeapFree(GetProcessHeap(), 0, This->filters);
}
HeapFree(GetProcessHeap(), 0, This);
TRACE("(%p) released\n", This);
}
HRESULT IDirectSoundBufferImpl_Duplicate(
DirectSoundDevice *device,
IDirectSoundBufferImpl **ppdsb,
IDirectSoundBufferImpl *pdsb)
{
IDirectSoundBufferImpl *dsb;
HRESULT hres = DS_OK;
VOID *committedbuff;
TRACE("(%p,%p,%p)\n", device, ppdsb, pdsb);
dsb = HeapAlloc(GetProcessHeap(),0,sizeof(*dsb));
if (dsb == NULL) {
WARN("out of memory\n");
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
committedbuff = HeapAlloc(GetProcessHeap(),0,pdsb->writelead);
if (committedbuff == NULL) {
HeapFree(GetProcessHeap(),0,dsb);
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
AcquireSRWLockShared(&pdsb->lock);
CopyMemory(dsb, pdsb, sizeof(*dsb));
dsb->pwfx = DSOUND_CopyFormat(pdsb->pwfx);
ReleaseSRWLockShared(&pdsb->lock);
if (dsb->pwfx == NULL) {
HeapFree(GetProcessHeap(),0,committedbuff);
HeapFree(GetProcessHeap(),0,dsb);
*ppdsb = NULL;
return DSERR_OUTOFMEMORY;
}
dsb->buffer->ref++;
list_add_head(&dsb->buffer->buffers, &dsb->entry);
dsb->ref = 0;
dsb->refn = 0;
dsb->ref3D = 0;
dsb->refiks = 0;
dsb->numIfaces = 0;
dsb->state = STATE_STOPPED;
dsb->sec_mixpos = 0;
dsb->notifies = NULL;
dsb->nrofnotifies = 0;
dsb->device = device;
dsb->committedbuff = committedbuff;
dsb->use_committed = FALSE;
dsb->committed_mixpos = 0;
DSOUND_RecalcFormat(dsb);
InitializeSRWLock(&dsb->lock);
/* register buffer */
hres = DirectSoundDevice_AddBuffer(device, dsb);
if (hres != DS_OK) {
list_remove(&dsb->entry);
dsb->buffer->ref--;
HeapFree(GetProcessHeap(),0,dsb->pwfx);
HeapFree(GetProcessHeap(),0,dsb->committedbuff);
HeapFree(GetProcessHeap(),0,dsb);
dsb = NULL;
}else
IDirectSoundBuffer8_AddRef(&dsb->IDirectSoundBuffer8_iface);
*ppdsb = dsb;
return hres;
}
/*******************************************************************************
* IKsPropertySet
*/
static inline IDirectSoundBufferImpl *impl_from_IKsPropertySet(IKsPropertySet *iface)
{
return CONTAINING_RECORD(iface, IDirectSoundBufferImpl, IKsPropertySet_iface);
}
/* IUnknown methods */
static HRESULT WINAPI IKsPropertySetImpl_QueryInterface(IKsPropertySet *iface, REFIID riid,
void **ppobj)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
return IDirectSoundBuffer8_QueryInterface(&This->IDirectSoundBuffer8_iface, riid, ppobj);
}
static ULONG WINAPI IKsPropertySetImpl_AddRef(IKsPropertySet *iface)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
ULONG ref = InterlockedIncrement(&This->refiks);
TRACE("(%p) ref %d\n", This, ref);
if(ref == 1)
InterlockedIncrement(&This->numIfaces);
return ref;
}
static ULONG WINAPI IKsPropertySetImpl_Release(IKsPropertySet *iface)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
ULONG ref;
if (is_primary_buffer(This)){
ref = capped_refcount_dec(&This->refiks);
if(!ref)
capped_refcount_dec(&This->numIfaces);
TRACE("(%p) ref %d\n", This, ref);
return ref;
}
ref = InterlockedDecrement(&This->refiks);
if (!ref && !InterlockedDecrement(&This->numIfaces))
secondarybuffer_destroy(This);
TRACE("(%p) ref %d\n", This, ref);
return ref;
}
static HRESULT WINAPI IKsPropertySetImpl_Get(IKsPropertySet *iface, REFGUID guidPropSet,
ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
ULONG cbPropData, ULONG *pcbReturned)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
TRACE("(iface=%p,guidPropSet=%s,dwPropID=%d,pInstanceData=%p,cbInstanceData=%d,pPropData=%p,cbPropData=%d,pcbReturned=%p)\n",
This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned);
return E_PROP_ID_UNSUPPORTED;
}
static HRESULT WINAPI IKsPropertySetImpl_Set(IKsPropertySet *iface, REFGUID guidPropSet,
ULONG dwPropID, void *pInstanceData, ULONG cbInstanceData, void *pPropData,
ULONG cbPropData)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
TRACE("(%p,%s,%d,%p,%d,%p,%d)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData);
return E_PROP_ID_UNSUPPORTED;
}
static HRESULT WINAPI IKsPropertySetImpl_QuerySupport(IKsPropertySet *iface, REFGUID guidPropSet,
ULONG dwPropID, ULONG *pTypeSupport)
{
IDirectSoundBufferImpl *This = impl_from_IKsPropertySet(iface);
TRACE("(%p,%s,%d,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport);
return E_PROP_ID_UNSUPPORTED;
}
const IKsPropertySetVtbl iksbvt = {
IKsPropertySetImpl_QueryInterface,
IKsPropertySetImpl_AddRef,
IKsPropertySetImpl_Release,
IKsPropertySetImpl_Get,
IKsPropertySetImpl_Set,
IKsPropertySetImpl_QuerySupport
};