diff --git a/reactos/lib/dsound/buffer.c b/reactos/lib/dsound/buffer.c index b20421e81cc..60ca6797fdf 100644 --- a/reactos/lib/dsound/buffer.c +++ b/reactos/lib/dsound/buffer.c @@ -1,1562 +1,1511 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include - -#define NONAMELESSSTRUCT -#define NONAMELESSUNION -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winreg.h" -#include "winternl.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - -/******************************************************************************* - * IDirectSoundNotify - */ -static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface( - LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj -) { - IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - - if (This->dsb == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj); -} - -static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) -{ - IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) { - IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; - ULONG ref; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) { - IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb); - This->dsb->notify = NULL; - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - return ref; -} - -static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions( - LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify -) { - IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; - TRACE("(%p,0x%08lx,%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;idsb->hwnotify) { - HRESULT hres; - hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify); - if (hres != DS_OK) - WARN("IDsDriverNotify_SetNotificationPositions failed\n"); - return hres; - } else if (howmuch > 0) { - /* Make an internal copy of the caller-supplied array. - * Replace the existing copy if one is already present. */ - if (This->dsb->notifies) - This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY)); - else - This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - howmuch * sizeof(DSBPOSITIONNOTIFY)); - - if (This->dsb->notifies == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } - memcpy(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY)); - This->dsb->nrofnotifies = howmuch; - } else { - if (This->dsb->notifies) { - HeapFree(GetProcessHeap(), 0, This->dsb->notifies); - This->dsb->notifies = NULL; - } - This->dsb->nrofnotifies = 0; - } - - return S_OK; -} - -IDirectSoundNotifyVtbl dsnvt = -{ - IDirectSoundNotifyImpl_QueryInterface, - IDirectSoundNotifyImpl_AddRef, - IDirectSoundNotifyImpl_Release, - IDirectSoundNotifyImpl_SetNotificationPositions, -}; - -HRESULT WINAPI IDirectSoundNotifyImpl_Create( - IDirectSoundBufferImpl * dsb, - IDirectSoundNotifyImpl **pdsn) -{ - IDirectSoundNotifyImpl * dsn; - TRACE("(%p,%p)\n",dsb,pdsn); - - dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn)); - - if (dsn == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } - - dsn->ref = 0; - dsn->lpVtbl = &dsnvt; - dsn->dsb = dsb; - dsb->notify = dsn; - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); - - *pdsn = dsn; - return DS_OK; -} - -HRESULT WINAPI IDirectSoundNotifyImpl_Destroy( - IDirectSoundNotifyImpl *pdsn) -{ - TRACE("(%p)\n",pdsn); - - while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0); - - return DS_OK; -} - -/******************************************************************************* - * IDirectSoundBuffer - */ - -static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat( - LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - - TRACE("(%p,%p)\n",This,wfex); - /* This method is not available on secondary buffers */ - WARN("invalid call\n"); - return DSERR_INVALIDCALL; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume( - LPDIRECTSOUNDBUFFER8 iface,LONG vol -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - LONG oldVol; - HRESULT hres = DS_OK; - - TRACE("(%p,%ld)\n",This,vol); - - if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { - WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags); - return DSERR_CONTROLUNAVAIL; - } - - if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { - WARN("invalid parameter: vol = %ld\n", vol); - return DSERR_INVALIDPARAM; - } - - /* **** */ - EnterCriticalSection(&(This->lock)); - - if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) { - oldVol = This->ds3db_lVolume; - This->ds3db_lVolume = vol; - } else { - oldVol = This->volpan.lVolume; - This->volpan.lVolume = vol; - if (vol != oldVol) - DSOUND_RecalcVolPan(&(This->volpan)); - } - - if (vol != oldVol) { - if (This->hwbuf) { - hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); - if (hres != DS_OK) - WARN("IDsDriverBuffer_SetVolumePan failed\n"); - } else - DSOUND_ForceRemix(This); - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume( - LPDIRECTSOUNDBUFFER8 iface,LPLONG vol -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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( - LPDIRECTSOUNDBUFFER8 iface,DWORD freq -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - DWORD oldFreq; - - TRACE("(%p,%ld)\n",This,freq); - - 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 = %ld\n", freq); - return DSERR_INVALIDPARAM; - } - - /* **** */ - EnterCriticalSection(&(This->lock)); - - oldFreq = This->freq; - This->freq = freq; - if (freq != oldFreq) { - This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->pwfx->nSamplesPerSec; - This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign; - DSOUND_RecalcFormat(This); - if (!This->hwbuf) - DSOUND_ForceRemix(This); - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_Play( - LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags -) { - HRESULT hres = DS_OK; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags); - - /* **** */ - EnterCriticalSection(&(This->lock)); - - This->playflags = flags; - if (This->state == STATE_STOPPED) { - This->leadin = TRUE; - This->startpos = This->buf_mixpos; - This->state = STATE_STARTING; - } else if (This->state == STATE_STOPPING) - This->state = STATE_PLAYING; - if (This->hwbuf) { - hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags); - if (hres != DS_OK) - WARN("IDsDriverBuffer_Play failed\n"); - else - This->state = STATE_PLAYING; - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) -{ - HRESULT hres = DS_OK; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p)\n",This); - - /* **** */ - EnterCriticalSection(&(This->lock)); - - if (This->state == STATE_PLAYING) - This->state = STATE_STOPPING; - else if (This->state == STATE_STARTING) - This->state = STATE_STOPPED; - if (This->hwbuf) { - hres = IDsDriverBuffer_Stop(This->hwbuf); - if (hres != DS_OK) - WARN("IDsDriverBuffer_Stop failed\n"); - else - This->state = STATE_STOPPED; - } - DSOUND_CheckEvent(This, 0); - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return hres; -} - -static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) -{ - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) -{ - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - ULONG ref; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - - DSOUND_RemoveBuffer(This->dsound, This); - - This->lock.DebugInfo->Spare[1] = 0; - DeleteCriticalSection(&(This->lock)); - - if (This->hwbuf) { - IDsDriverBuffer_Release(This->hwbuf); - if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { - This->buffer->ref--; - if (This->buffer->ref==0) { - HeapFree(GetProcessHeap(),0,This->buffer->memory); - HeapFree(GetProcessHeap(),0,This->buffer); - } - } - } else { - This->buffer->ref--; - if (This->buffer->ref==0) { - HeapFree(GetProcessHeap(),0,This->buffer->memory); - HeapFree(GetProcessHeap(),0,This->buffer); - } - } - - if (This->notifies != NULL) - HeapFree(GetProcessHeap(), 0, This->notifies); - - if (This->pwfx) - HeapFree(GetProcessHeap(), 0, This->pwfx); - - HeapFree(GetProcessHeap(),0,This); - - TRACE("(%p) released\n",This); - return 0; -} - -DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, - DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix) -{ - DWORD bplay; - - TRACE("primary playpos=%ld, mixpos=%ld\n", pplay, pmix); - TRACE("this mixpos=%ld, time=%ld\n", bmix, GetTickCount()); - - /* the actual primary play position (pplay) is always behind last mixed (pmix), - * unless the computer is too slow or something */ - /* we need to know how far away we are from there */ -#if 0 /* we'll never fill the primary entirely */ - if (pmix == pplay) { - if ((state == STATE_PLAYING) || (state == STATE_STOPPING)) { - /* wow, the software mixer is really doing well, - * seems the entire primary buffer is filled! */ - pmix += This->dsound->buflen; - } - /* else: the primary buffer is not playing, so probably empty */ - } -#endif - if (pmix < pplay) pmix += This->dsound->buflen; /* wraparound */ - pmix -= pplay; - /* detect buffer underrun */ - if (pwrite < pplay) pwrite += This->dsound->buflen; /* wraparound */ - pwrite -= pplay; - if (pmix > (ds_snd_queue_max * This->dsound->fraglen + pwrite + This->dsound->writelead)) { - WARN("detected an underrun: primary queue was %ld\n",pmix); - pmix = 0; - } - /* divide the offset by its sample size */ - pmix /= This->dsound->pwfx->nBlockAlign; - TRACE("primary back-samples=%ld\n",pmix); - /* adjust for our frequency */ - pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT; - /* multiply by our own sample size */ - pmix *= This->pwfx->nBlockAlign; - TRACE("this back-offset=%ld\n", pmix); - /* subtract from our last mixed position */ - bplay = bmix; - while (bplay < pmix) bplay += This->buflen; /* wraparound */ - bplay -= pmix; - if (This->leadin && ((bplay < This->startpos) || (bplay > bmix))) { - /* seems we haven't started playing yet */ - TRACE("this still in lead-in phase\n"); - bplay = This->startpos; - } - /* return the result */ - return bplay; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos -) { - HRESULT hres; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%p,%p)\n",This,playpos,writepos); - if (This->hwbuf) { - hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos); - if (hres != DS_OK) { - WARN("IDsDriverBuffer_GetPosition failed\n"); - return hres; - } - } else { - if (playpos && (This->state != STATE_PLAYING)) { - /* we haven't been merged into the primary buffer (yet) */ - *playpos = This->buf_mixpos; - } else if (playpos) { - DWORD pplay, pwrite, lplay, splay, pstate; - /* let's get this exact; first, recursively call GetPosition on the primary */ - EnterCriticalSection(&(This->dsound->mixlock)); - if (DSOUND_PrimaryGetPosition(This->dsound, &pplay, &pwrite) != DS_OK) - WARN("DSOUND_PrimaryGetPosition failed\n"); - /* detect HEL mode underrun */ - pstate = This->dsound->state; - if (!(This->dsound->hwbuf || This->dsound->pwqueue)) { - TRACE("detected an underrun\n"); - /* pplay = ? */ - if (pstate == STATE_PLAYING) - pstate = STATE_STARTING; - else if (pstate == STATE_STOPPING) - pstate = STATE_STOPPED; - } - /* get data for ourselves while we still have the lock */ - pstate &= This->state; - lplay = This->primary_mixpos; - splay = This->buf_mixpos; - if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->hwbuf) { - /* calculate play position using this */ - *playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay); - } else { - /* (unless the app isn't using GETCURRENTPOSITION2) */ - /* don't know exactly how this should be handled... - * the docs says that play cursor is reported as directly - * behind write cursor, hmm... */ - /* let's just do what might work for Half-Life */ - DWORD wp; - wp = (This->dsound->pwplay + ds_hel_margin) * This->dsound->fraglen; - wp %= This->dsound->buflen; - *playpos = DSOUND_CalcPlayPosition(This, pstate, wp, pwrite, lplay, splay); - } - LeaveCriticalSection(&(This->dsound->mixlock)); - } - if (writepos) - *writepos = This->buf_mixpos; - } - if (writepos) { - if (This->state != STATE_STOPPED) { - /* apply the documented 10ms lead to writepos */ - *writepos += This->writelead; - } - *writepos %= This->buflen; - } - if (playpos) - This->last_playpos = *playpos; - TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD status -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId()); - - if (status == NULL) { - WARN("invalid parameter: status = NULL\n"); - return DSERR_INVALIDPARAM; - } - - *status = 0; - if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) { - *status |= DSBSTATUS_PLAYING; - if (This->playflags & DSBPLAY_LOOPING) - *status |= DSBSTATUS_LOOPING; - } - - TRACE("status=%lx\n", *status); - return DS_OK; -} - - -static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat( - LPDIRECTSOUNDBUFFER8 iface, - LPWAVEFORMATEX lpwf, - DWORD wfsize, - LPDWORD wfwritten) -{ - DWORD size; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); - - size = sizeof(WAVEFORMATEX) + This->pwfx->cbSize; - - if (lpwf) { /* NULL is valid */ - if (wfsize >= size) { - memcpy(lpwf,This->pwfx,size); - if (wfwritten) - *wfwritten = size; - } else { - WARN("invalid parameter: wfsize to small\n"); - if (wfwritten) - *wfwritten = 0; - 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( - LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags -) { - HRESULT hres = DS_OK; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - - TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", - This, - writecursor, - writebytes, - lplpaudioptr1, - audiobytes1, - lplpaudioptr2, - audiobytes2, - flags, - GetTickCount() - ); - - if (flags & DSBLOCK_FROMWRITECURSOR) { - DWORD writepos; - /* GetCurrentPosition does too much magic to duplicate here */ - hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos); - if (hres != DS_OK) { - WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n"); - return hres; - } - writecursor += writepos; - } - writecursor %= This->buflen; - if (flags & DSBLOCK_ENTIREBUFFER) - writebytes = This->buflen; - if (writebytes > This->buflen) - writebytes = This->buflen; - - EnterCriticalSection(&(This->lock)); - - if ((writebytes == This->buflen) && - ((This->state == STATE_STARTING) || - (This->state == STATE_PLAYING))) - /* some games, like Half-Life, try to be clever (not) and - * keep one secondary buffer, and mix sounds into it itself, - * locking the entire buffer every time... so we can just forget - * about tracking the last-written-to-position... */ - This->probably_valid_to = (DWORD)-1; - else - This->probably_valid_to = writecursor; - - if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { - hres = IDsDriverBuffer_Lock(This->hwbuf, - lplpaudioptr1, audiobytes1, - lplpaudioptr2, audiobytes2, - writecursor, writebytes, - 0); - if (hres != DS_OK) { - WARN("IDsDriverBuffer_Lock failed\n"); - LeaveCriticalSection(&(This->lock)); - return hres; - } - } else { - BOOL remix = FALSE; - if (writecursor+writebytes <= This->buflen) { - *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; - *audiobytes1 = writebytes; - if (lplpaudioptr2) - *(LPBYTE*)lplpaudioptr2 = NULL; - if (audiobytes2) - *audiobytes2 = 0; - TRACE("->%ld.0\n",writebytes); - } else { - *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; - *audiobytes1 = This->buflen-writecursor; - if (lplpaudioptr2) - *(LPBYTE*)lplpaudioptr2 = This->buffer->memory; - if (audiobytes2) - *audiobytes2 = writebytes-(This->buflen-writecursor); - TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); - } - if (This->state == STATE_PLAYING) { - /* if the segment between playpos and buf_mixpos is touched, - * we need to cancel some mixing */ - /* we'll assume that the app always calls GetCurrentPosition before - * locking a playing buffer, so that last_playpos is up-to-date */ - if (This->buf_mixpos >= This->last_playpos) { - if (This->buf_mixpos > writecursor && - This->last_playpos < writecursor+writebytes) - remix = TRUE; - } else { - if (This->buf_mixpos > writecursor || - This->last_playpos < writecursor+writebytes) - remix = TRUE; - } - if (remix) { - TRACE("locking prebuffered region, ouch\n"); - DSOUND_MixCancelAt(This, writecursor); - } - } - } - - LeaveCriticalSection(&(This->lock)); - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,DWORD newpos -) { - HRESULT hres = DS_OK; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,newpos); - - /* **** */ - EnterCriticalSection(&(This->lock)); - - newpos %= This->buflen; - This->buf_mixpos = newpos; - if (This->hwbuf) { - hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos); - if (hres != DS_OK) - WARN("IDsDriverBuffer_SetPosition failed\n"); - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_SetPan( - LPDIRECTSOUNDBUFFER8 iface,LONG pan -) { - HRESULT hres = DS_OK; - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - - TRACE("(%p,%ld)\n",This,pan); - - if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { - WARN("invalid parameter: pan = %ld\n", pan); - return DSERR_INVALIDPARAM; - } - - /* You cannot use both pan and 3D controls */ - if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) || - (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - /* **** */ - EnterCriticalSection(&(This->lock)); - - if (This->volpan.lPan != pan) { - This->volpan.lPan = pan; - DSOUND_RecalcVolPan(&(This->volpan)); - - if (This->hwbuf) { - hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); - if (hres != DS_OK) - WARN("IDsDriverBuffer_SetVolumePan failed\n"); - } else - DSOUND_ForceRemix(This); - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_GetPan( - LPDIRECTSOUNDBUFFER8 iface,LPLONG pan -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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( - LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - DWORD probably_valid_to; - HRESULT hres = DS_OK; - - TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2); - - /* **** */ - EnterCriticalSection(&(This->lock)); - - if (!(This->dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { - hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2); - if (hres != DS_OK) - WARN("IDsDriverBuffer_Unlock failed\n"); - } - - if (hres == DS_OK) { - if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2; - else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1; - probably_valid_to %= This->buflen; - if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) && - ((This->state == STATE_STARTING) || - (This->state == STATE_PLAYING))) - /* see IDirectSoundBufferImpl_Lock */ - probably_valid_to = (DWORD)-1; - This->probably_valid_to = probably_valid_to; - } - - LeaveCriticalSection(&(This->lock)); - /* **** */ - - TRACE("probably_valid_to=%ld\n", This->probably_valid_to); - return hres; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_Restore( - LPDIRECTSOUNDBUFFER8 iface -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - FIXME("(%p):stub\n",This); - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p,%p)\n",This,freq); - - if (freq == NULL) { - WARN("invalid parameter: freq = NULL\n"); - return DSERR_INVALIDPARAM; - } - - *freq = This->freq; - TRACE("-> %ld\n", *freq); - - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_SetFX( - LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - DWORD u; - - FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); - - if (pdwResultCodes) - for (u=0; u(%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 = %ld < %d\n",caps->dwSize, sizeof(*caps)); - return DSERR_INVALIDPARAM; - } - - caps->dwFlags = This->dsbd.dwFlags; - if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; - else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; - - caps->dwBufferBytes = This->buflen; - - /* This value represents the speed of the "unlock" command. - As unlock is quite fast (it does not do anything), I put - 4096 ko/s = 4 Mo / s */ - /* FIXME: hwbuf speed */ - caps->dwUnlockTransferRate = 4096; - caps->dwPlayCpuOverhead = 0; - - return DS_OK; -} - -static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface( - LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj -) { - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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) ) { - if (!This->dsb) - SecondaryBufferImpl_Create(This, &(This->dsb)); - if (This->dsb) { - IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb); - *ppobj = This->dsb; - return S_OK; - } - WARN("IID_IDirectSoundBuffer\n"); - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { - if (!This->notify) - IDirectSoundNotifyImpl_Create(This, &(This->notify)); - if (This->notify) { - IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify); - *ppobj = This->notify; - return S_OK; - } - WARN("IID_IDirectSoundNotify\n"); - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { - if (!This->ds3db) - IDirectSound3DBufferImpl_Create(This, &(This->ds3db)); - if (This->ds3db) { - IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db); - *ppobj = This->ds3db; - return S_OK; - } - WARN("IID_IDirectSound3DBuffer\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 ) ) { - if (!This->iks) - IKsBufferPropertySetImpl_Create(This, &(This->iks)); - if (This->iks) { - IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks); - *ppobj = This->iks; - return S_OK; - } - WARN("IID_IKsPropertySet\n"); - return E_NOINTERFACE; - } - - FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); - - return E_NOINTERFACE; -} - -static 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 WINAPI IDirectSoundBufferImpl_Create( - IDirectSoundImpl *ds, - IDirectSoundBufferImpl **pdsb, - LPCDSBUFFERDESC dsbd) -{ - IDirectSoundBufferImpl *dsb; - LPWAVEFORMATEX wfex = dsbd->lpwfxFormat; - HRESULT err = DS_OK; - DWORD capf = 0; - int use_hw, alloc_size, cp_size; - TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd); - - if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) { - WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes); - *pdsb = NULL; - return DSERR_INVALIDPARAM; /* FIXME: which error? */ - } - - dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); - - if (dsb == 0) { - WARN("out of memory\n"); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - - TRACE("Created buffer at %p\n", dsb); - - dsb->ref = 0; - dsb->dsb = 0; - dsb->dsound = ds; - dsb->lpVtbl = &dsbvt; - dsb->iks = NULL; - - /* size depends on version */ - memcpy(&dsb->dsbd, dsbd, dsbd->dwSize); - - /* variable sized struct so calculate size based on format */ - if (wfex->wFormatTag == WAVE_FORMAT_PCM) { - alloc_size = sizeof(WAVEFORMATEX); - cp_size = sizeof(PCMWAVEFORMAT); - } else - alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize; - - dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size); - if (dsb->pwfx == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,dsb); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - - memcpy(dsb->pwfx, wfex, cp_size); - - dsb->buflen = dsbd->dwBufferBytes; - dsb->freq = dsbd->lpwfxFormat->nSamplesPerSec; - - dsb->notify = NULL; - dsb->notifies = NULL; - dsb->nrofnotifies = 0; - dsb->hwnotify = 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; - - use_hw = (ds->drvcaps.dwFlags & capf) == capf; - TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->drvcaps.dwFlags); - - /* FIXME: check hardware sample rate mixing capabilities */ - /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */ - /* FIXME: check whether any hardware buffers are left */ - /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */ - - /* Allocate system memory if applicable */ - if ((ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) { - dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer))); - if (dsb->buffer == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,dsb->pwfx); - HeapFree(GetProcessHeap(),0,dsb); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - - dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen); - if (dsb->buffer->memory == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,dsb->pwfx); - HeapFree(GetProcessHeap(),0,dsb->buffer); - HeapFree(GetProcessHeap(),0,dsb); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - dsb->buffer->ref = 1; - } - - /* Allocate the hardware buffer */ - if (use_hw) { - err = IDsDriver_CreateSoundBuffer(ds->driver,wfex,dsbd->dwFlags,0, - &(dsb->buflen),&(dsb->buffer->memory), - (LPVOID*)&(dsb->hwbuf)); - /* fall back to software buffer on failure */ - if (err != DS_OK) { - TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n"); - use_hw = 0; - if (ds->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { - dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer))); - if (dsb->buffer == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,dsb->pwfx); - HeapFree(GetProcessHeap(),0,dsb); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - - dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen); - if (dsb->buffer->memory == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,dsb->buffer); - HeapFree(GetProcessHeap(),0,dsb->pwfx); - HeapFree(GetProcessHeap(),0,dsb); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - dsb->buffer->ref = 1; - } - err = DS_OK; - } - } - - /* calculate fragment size and write lead */ - DSOUND_RecalcFormat(dsb); - - /* It's not necessary to initialize values to zero since */ - /* we allocated this structure with HEAP_ZERO_MEMORY... */ - dsb->playpos = 0; - dsb->buf_mixpos = 0; - dsb->state = STATE_STOPPED; - - dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) / - ds->pwfx->nSamplesPerSec; - dsb->nAvgBytesPerSec = dsb->freq * - dsbd->lpwfxFormat->nBlockAlign; - - 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)); - - InitializeCriticalSection(&(dsb->lock)); - dsb->lock.DebugInfo->Spare[1] = (DWORD)"DSOUNDBUFFER_lock"; - - /* register buffer if not primary */ - if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) { - err = DSOUND_AddBuffer(ds, dsb); - if (err != DS_OK) { - if (dsb->buffer->memory) - HeapFree(GetProcessHeap(),0,dsb->buffer->memory); - if (dsb->buffer) - HeapFree(GetProcessHeap(),0,dsb->buffer); - dsb->lock.DebugInfo->Spare[1] = 0; - DeleteCriticalSection(&(dsb->lock)); - HeapFree(GetProcessHeap(),0,dsb->pwfx); - HeapFree(GetProcessHeap(),0,dsb); - dsb = NULL; - } - } - - *pdsb = dsb; - return err; -} - -HRESULT WINAPI IDirectSoundBufferImpl_Destroy( - IDirectSoundBufferImpl *pdsb) -{ - TRACE("(%p)\n",pdsb); - - /* This keeps the *_Destroy functions from possibly deleting - * this object until it is ready to be deleted */ - IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb); - - if (pdsb->iks) { - WARN("iks not NULL\n"); - IKsBufferPropertySetImpl_Destroy(pdsb->iks); - pdsb->iks = NULL; - } - - if (pdsb->ds3db) { - WARN("ds3db not NULL\n"); - IDirectSound3DBufferImpl_Destroy(pdsb->ds3db); - pdsb->ds3db = NULL; - } - - if (pdsb->notify) { - WARN("notify not NULL\n"); - IDirectSoundNotifyImpl_Destroy(pdsb->notify); - pdsb->notify = NULL; - } - - if (pdsb->dsb) { - WARN("dsb not NULL\n"); - SecondaryBufferImpl_Destroy(pdsb->dsb); - pdsb->dsb = NULL; - } - - while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); - - return S_OK; -} - -/******************************************************************************* - * SecondaryBuffer - */ - -static HRESULT WINAPI SecondaryBufferImpl_QueryInterface( - LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - - return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj); -} - -static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) -{ - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) -{ - IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; - ULONG ref; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - ref = InterlockedDecrement(&(This->ref)); - if (!ref) { - This->dsb->dsb = NULL; - IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - return ref; -} - -static HRESULT WINAPI SecondaryBufferImpl_GetCaps( - LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p)->(%p)\n",This,caps); - - return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p,%p)\n",This,playpos,writepos); - - return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetFormat( - LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); - - return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetVolume( - LPDIRECTSOUNDBUFFER8 iface,LPLONG vol) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,vol); - - return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetPan( - LPDIRECTSOUNDBUFFER8 iface,LPLONG pan) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,pan); - - return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetFrequency( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,freq); - - return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetStatus( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD status) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,status); - - return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status); -} - -static HRESULT WINAPI SecondaryBufferImpl_Initialize( - LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p,%p)\n",This,dsound,dbsd); - - return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd); -} - -static HRESULT WINAPI SecondaryBufferImpl_Lock( - LPDIRECTSOUNDBUFFER8 iface, - DWORD writecursor, - DWORD writebytes, - LPVOID lplpaudioptr1, - LPDWORD audiobytes1, - LPVOID lplpaudioptr2, - LPDWORD audiobytes2, - DWORD dwFlags) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n", - This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); - - return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb, - writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); -} - -static HRESULT WINAPI SecondaryBufferImpl_Play( - LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags); - - return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,DWORD newpos) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,newpos); - - return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetFormat( - LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,wfex); - - return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetVolume( - LPDIRECTSOUNDBUFFER8 iface,LONG vol) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,vol); - - return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetPan( - LPDIRECTSOUNDBUFFER8 iface,LONG pan) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,pan); - - return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetFrequency( - LPDIRECTSOUNDBUFFER8 iface,DWORD freq) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,freq); - - return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); -} - -static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p)\n",This); - - return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb); -} - -static HRESULT WINAPI SecondaryBufferImpl_Unlock( - LPDIRECTSOUNDBUFFER8 iface, - LPVOID lpvAudioPtr1, - DWORD dwAudioBytes1, - LPVOID lpvAudioPtr2, - DWORD dwAudioBytes2) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%p,%ld,%p,%ld)\n", - This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); - - return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb, - lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2); -} - -static HRESULT WINAPI SecondaryBufferImpl_Restore( - LPDIRECTSOUNDBUFFER8 iface) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p)\n",This); - - return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb); -} - -static HRESULT WINAPI SecondaryBufferImpl_SetFX( - LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); - - return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes); -} - -static HRESULT WINAPI SecondaryBufferImpl_AcquireResources( - LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes); - - return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes); -} - -static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath( - LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject) -{ - SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; - TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject); - - return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject); -} - -static IDirectSoundBuffer8Vtbl sbvt = -{ - SecondaryBufferImpl_QueryInterface, - SecondaryBufferImpl_AddRef, - SecondaryBufferImpl_Release, - SecondaryBufferImpl_GetCaps, - SecondaryBufferImpl_GetCurrentPosition, - SecondaryBufferImpl_GetFormat, - SecondaryBufferImpl_GetVolume, - SecondaryBufferImpl_GetPan, - SecondaryBufferImpl_GetFrequency, - SecondaryBufferImpl_GetStatus, - SecondaryBufferImpl_Initialize, - SecondaryBufferImpl_Lock, - SecondaryBufferImpl_Play, - SecondaryBufferImpl_SetCurrentPosition, - SecondaryBufferImpl_SetFormat, - SecondaryBufferImpl_SetVolume, - SecondaryBufferImpl_SetPan, - SecondaryBufferImpl_SetFrequency, - SecondaryBufferImpl_Stop, - SecondaryBufferImpl_Unlock, - SecondaryBufferImpl_Restore, - SecondaryBufferImpl_SetFX, - SecondaryBufferImpl_AcquireResources, - SecondaryBufferImpl_GetObjectInPath -}; - -HRESULT WINAPI SecondaryBufferImpl_Create( - IDirectSoundBufferImpl *dsb, - SecondaryBufferImpl **psb) -{ - SecondaryBufferImpl *sb; - TRACE("(%p,%p)\n",dsb,psb); - - sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb)); - - if (sb == 0) { - WARN("out of memory\n"); - *psb = NULL; - return DSERR_OUTOFMEMORY; - } - sb->ref = 0; - sb->dsb = dsb; - sb->lpVtbl = &sbvt; - - IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb); - *psb = sb; - return S_OK; -} - -HRESULT WINAPI SecondaryBufferImpl_Destroy( - SecondaryBufferImpl *pdsb) -{ - TRACE("(%p)\n",pdsb); - - while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); - - return S_OK; -} +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +/******************************************************************************* + * IDirectSoundNotify + */ +static HRESULT WINAPI IDirectSoundNotifyImpl_QueryInterface( + LPDIRECTSOUNDNOTIFY iface,REFIID riid,LPVOID *ppobj +) { + IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + + if (This->dsb == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER)This->dsb, riid, ppobj); +} + +static ULONG WINAPI IDirectSoundNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) +{ + IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectSoundNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) +{ + IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)This->dsb); + This->dsb->notify = NULL; + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI IDirectSoundNotifyImpl_SetNotificationPositions( + LPDIRECTSOUNDNOTIFY iface,DWORD howmuch,LPCDSBPOSITIONNOTIFY notify +) { + IDirectSoundNotifyImpl *This = (IDirectSoundNotifyImpl *)iface; + TRACE("(%p,0x%08lx,%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;idsb->hwnotify) { + HRESULT hres; + hres = IDsDriverNotify_SetNotificationPositions(This->dsb->hwnotify, howmuch, notify); + if (hres != DS_OK) + WARN("IDsDriverNotify_SetNotificationPositions failed\n"); + return hres; + } else if (howmuch > 0) { + /* Make an internal copy of the caller-supplied array. + * Replace the existing copy if one is already present. */ + if (This->dsb->notifies) + This->dsb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->dsb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY)); + else + This->dsb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + howmuch * sizeof(DSBPOSITIONNOTIFY)); + + if (This->dsb->notifies == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + CopyMemory(This->dsb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY)); + This->dsb->nrofnotifies = howmuch; + } else { + HeapFree(GetProcessHeap(), 0, This->dsb->notifies); + This->dsb->notifies = NULL; + This->dsb->nrofnotifies = 0; + } + + return S_OK; +} + +static const IDirectSoundNotifyVtbl dsnvt = +{ + IDirectSoundNotifyImpl_QueryInterface, + IDirectSoundNotifyImpl_AddRef, + IDirectSoundNotifyImpl_Release, + IDirectSoundNotifyImpl_SetNotificationPositions, +}; + +HRESULT WINAPI IDirectSoundNotifyImpl_Create( + IDirectSoundBufferImpl * dsb, + IDirectSoundNotifyImpl **pdsn) +{ + IDirectSoundNotifyImpl * dsn; + TRACE("(%p,%p)\n",dsb,pdsn); + + dsn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dsn)); + + if (dsn == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + + dsn->ref = 0; + dsn->lpVtbl = &dsnvt; + dsn->dsb = dsb; + dsb->notify = dsn; + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); + + *pdsn = dsn; + return DS_OK; +} + +HRESULT WINAPI IDirectSoundNotifyImpl_Destroy( + IDirectSoundNotifyImpl *pdsn) +{ + TRACE("(%p)\n",pdsn); + + while (IDirectSoundNotifyImpl_Release((LPDIRECTSOUNDNOTIFY)pdsn) > 0); + + return DS_OK; +} + +/******************************************************************************* + * IDirectSoundBuffer + */ + +static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat( + LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + + TRACE("(%p,%p)\n",This,wfex); + /* This method is not available on secondary buffers */ + WARN("invalid call\n"); + return DSERR_INVALIDCALL; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_SetVolume( + LPDIRECTSOUNDBUFFER8 iface,LONG vol +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + LONG oldVol; + HRESULT hres = DS_OK; + + TRACE("(%p,%ld)\n",This,vol); + + if (!(This->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { + WARN("control unavailable: This->dsbd.dwFlags = 0x%08lx\n", This->dsbd.dwFlags); + return DSERR_CONTROLUNAVAIL; + } + + if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { + WARN("invalid parameter: vol = %ld\n", vol); + return DSERR_INVALIDPARAM; + } + + /* **** */ + EnterCriticalSection(&(This->lock)); + + if (This->dsbd.dwFlags & DSBCAPS_CTRL3D) { + oldVol = This->ds3db_lVolume; + This->ds3db_lVolume = vol; + } else { + oldVol = This->volpan.lVolume; + This->volpan.lVolume = vol; + if (vol != oldVol) + DSOUND_RecalcVolPan(&(This->volpan)); + } + + if (vol != oldVol) { + if (This->hwbuf) { + hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); + if (hres != DS_OK) + WARN("IDsDriverBuffer_SetVolumePan failed\n"); + } else + DSOUND_ForceRemix(This); + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_GetVolume( + LPDIRECTSOUNDBUFFER8 iface,LPLONG vol +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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( + LPDIRECTSOUNDBUFFER8 iface,DWORD freq +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + DWORD oldFreq; + + TRACE("(%p,%ld)\n",This,freq); + + 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 = %ld\n", freq); + return DSERR_INVALIDPARAM; + } + + /* **** */ + EnterCriticalSection(&(This->lock)); + + oldFreq = This->freq; + This->freq = freq; + if (freq != oldFreq) { + This->freqAdjust = (freq << DSOUND_FREQSHIFT) / This->dsound->device->pwfx->nSamplesPerSec; + This->nAvgBytesPerSec = freq * This->pwfx->nBlockAlign; + DSOUND_RecalcFormat(This); + if (!This->hwbuf) + DSOUND_ForceRemix(This); + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_Play( + LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags +) { + HRESULT hres = DS_OK; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags); + + /* **** */ + EnterCriticalSection(&(This->lock)); + + This->playflags = flags; + if (This->state == STATE_STOPPED) { + This->leadin = TRUE; + This->startpos = This->buf_mixpos; + This->state = STATE_STARTING; + } else if (This->state == STATE_STOPPING) + This->state = STATE_PLAYING; + if (This->hwbuf) { + hres = IDsDriverBuffer_Play(This->hwbuf, 0, 0, This->playflags); + if (hres != DS_OK) + WARN("IDsDriverBuffer_Play failed\n"); + else + This->state = STATE_PLAYING; + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) +{ + HRESULT hres = DS_OK; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p)\n",This); + + /* **** */ + EnterCriticalSection(&(This->lock)); + + if (This->state == STATE_PLAYING) + This->state = STATE_STOPPING; + else if (This->state == STATE_STARTING) + This->state = STATE_STOPPED; + if (This->hwbuf) { + hres = IDsDriverBuffer_Stop(This->hwbuf); + if (hres != DS_OK) + WARN("IDsDriverBuffer_Stop failed\n"); + else + This->state = STATE_STOPPED; + } + DSOUND_CheckEvent(This, 0); + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return hres; +} + +static ULONG WINAPI IDirectSoundBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) +{ + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) +{ + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + DSOUND_RemoveBuffer(This->dsound, This); + + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&(This->lock)); + + if (This->hwbuf) { + IDsDriverBuffer_Release(This->hwbuf); + if (This->dsound->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { + This->buffer->ref--; + if (This->buffer->ref==0) { + HeapFree(GetProcessHeap(),0,This->buffer->memory); + HeapFree(GetProcessHeap(),0,This->buffer); + } + } + } else { + This->buffer->ref--; + if (This->buffer->ref==0) { + HeapFree(GetProcessHeap(),0,This->buffer->memory); + HeapFree(GetProcessHeap(),0,This->buffer); + } + } + + HeapFree(GetProcessHeap(), 0, This->notifies); + HeapFree(GetProcessHeap(), 0, This->pwfx); + HeapFree(GetProcessHeap(), 0, This); + + TRACE("(%p) released\n", This); + } + return ref; +} + +DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite) +{ + DWORD bplay = This->buf_mixpos; + DWORD pmix = This->primary_mixpos; + TRACE("(%p, pplay=%lu, pwrite=%lu)\n", This, pplay, pwrite); + + /* the actual primary play position (pplay) is always behind last mixed (pmix), + * unless the computer is too slow or something */ + /* we need to know how far away we are from there */ + if (pmix < pplay) pmix += This->dsound->device->buflen; /* wraparound */ + pmix -= pplay; + /* detect buffer underrun */ + if (pwrite < pplay) pwrite += This->dsound->device->buflen; /* wraparound */ + pwrite -= pplay; + if (pmix > (ds_snd_queue_max * This->dsound->device->fraglen + pwrite + This->dsound->device->writelead)) { + WARN("detected an underrun: primary queue was %ld\n",pmix); + pmix = 0; + } + /* divide the offset by its sample size */ + pmix /= This->dsound->device->pwfx->nBlockAlign; + TRACE("primary back-samples=%ld\n",pmix); + /* adjust for our frequency */ + pmix = (pmix * This->freqAdjust) >> DSOUND_FREQSHIFT; + /* multiply by our own sample size */ + pmix *= This->pwfx->nBlockAlign; + TRACE("this back-offset=%ld\n", pmix); + /* subtract from our last mixed position */ + while (bplay < pmix) bplay += This->buflen; /* wraparound */ + bplay -= pmix; + if (This->leadin && ((bplay < This->startpos) || (bplay > This->buf_mixpos))) { + /* seems we haven't started playing yet */ + TRACE("this still in lead-in phase\n"); + bplay = This->startpos; + } + /* return the result */ + return bplay; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos +) { + HRESULT hres; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%p,%p)\n",This,playpos,writepos); + if (This->hwbuf) { + hres=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos); + if (hres != DS_OK) { + WARN("IDsDriverBuffer_GetPosition failed\n"); + return hres; + } + } else { + if (playpos && (This->state != STATE_PLAYING)) { + /* we haven't been merged into the primary buffer (yet) */ + *playpos = This->buf_mixpos; + } else if (playpos) { + DWORD pplay, pwrite; + /* let's get this exact; first, recursively call GetPosition on the primary */ + EnterCriticalSection(&(This->dsound->device->mixlock)); + if (DSOUND_PrimaryGetPosition(This->dsound->device, &pplay, &pwrite) != DS_OK) + WARN("DSOUND_PrimaryGetPosition failed\n"); + /* detect HEL mode underrun */ + if (!(This->dsound->device->hwbuf || This->dsound->device->pwqueue)) + TRACE("detected an underrun\n"); + if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || This->dsound->device->hwbuf) { + /* calculate play position using this */ + *playpos = DSOUND_CalcPlayPosition(This, pplay, pwrite); + } else { + /* (unless the app isn't using GETCURRENTPOSITION2) */ + /* don't know exactly how this should be handled... + * the docs says that play cursor is reported as directly + * behind write cursor, hmm... */ + /* let's just do what might work for Half-Life */ + DWORD wp; + wp = (This->dsound->device->pwplay + ds_hel_margin) * This->dsound->device->fraglen; + wp %= This->dsound->device->buflen; + *playpos = DSOUND_CalcPlayPosition(This, wp, pwrite); + } + LeaveCriticalSection(&(This->dsound->device->mixlock)); + } + if (writepos) + *writepos = This->buf_mixpos; + } + if (writepos) { + if (This->state != STATE_STOPPED) { + /* apply the documented 10ms lead to writepos */ + *writepos += This->writelead; + } + *writepos %= This->buflen; + } + if (playpos) + This->last_playpos = *playpos; + TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_GetStatus( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD status +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId()); + + if (status == NULL) { + WARN("invalid parameter: status = NULL\n"); + return DSERR_INVALIDPARAM; + } + + *status = 0; + if ((This->state == STATE_STARTING) || (This->state == STATE_PLAYING)) { + *status |= DSBSTATUS_PLAYING; + if (This->playflags & DSBPLAY_LOOPING) + *status |= DSBSTATUS_LOOPING; + } + + TRACE("status=%lx\n", *status); + return DS_OK; +} + + +static HRESULT WINAPI IDirectSoundBufferImpl_GetFormat( + LPDIRECTSOUNDBUFFER8 iface, + LPWAVEFORMATEX lpwf, + DWORD wfsize, + LPDWORD wfwritten) +{ + DWORD size; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%p,%ld,%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"); + if (wfwritten) + *wfwritten = 0; + 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( + LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags +) { + HRESULT hres = DS_OK; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + + TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", + This, + writecursor, + writebytes, + lplpaudioptr1, + audiobytes1, + lplpaudioptr2, + audiobytes2, + flags, + GetTickCount() + ); + + if (flags & DSBLOCK_FROMWRITECURSOR) { + DWORD writepos; + /* GetCurrentPosition does too much magic to duplicate here */ + hres = IDirectSoundBufferImpl_GetCurrentPosition(iface, NULL, &writepos); + if (hres != DS_OK) { + WARN("IDirectSoundBufferImpl_GetCurrentPosition failed\n"); + return hres; + } + writecursor += writepos; + } + writecursor %= This->buflen; + if (flags & DSBLOCK_ENTIREBUFFER) + writebytes = This->buflen; + if (writebytes > This->buflen) + writebytes = This->buflen; + + EnterCriticalSection(&(This->lock)); + + if ((writebytes == This->buflen) && + ((This->state == STATE_STARTING) || + (This->state == STATE_PLAYING))) + /* some games, like Half-Life, try to be clever (not) and + * keep one secondary buffer, and mix sounds into it itself, + * locking the entire buffer every time... so we can just forget + * about tracking the last-written-to-position... */ + This->probably_valid_to = (DWORD)-1; + else + This->probably_valid_to = writecursor; + + if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { + hres = IDsDriverBuffer_Lock(This->hwbuf, + lplpaudioptr1, audiobytes1, + lplpaudioptr2, audiobytes2, + writecursor, writebytes, + 0); + if (hres != DS_OK) { + WARN("IDsDriverBuffer_Lock failed\n"); + LeaveCriticalSection(&(This->lock)); + return hres; + } + } else { + BOOL remix = FALSE; + if (writecursor+writebytes <= This->buflen) { + *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; + *audiobytes1 = writebytes; + if (lplpaudioptr2) + *(LPBYTE*)lplpaudioptr2 = NULL; + if (audiobytes2) + *audiobytes2 = 0; + TRACE("->%ld.0\n",writebytes); + } else { + *(LPBYTE*)lplpaudioptr1 = This->buffer->memory+writecursor; + *audiobytes1 = This->buflen-writecursor; + if (lplpaudioptr2) + *(LPBYTE*)lplpaudioptr2 = This->buffer->memory; + if (audiobytes2) + *audiobytes2 = writebytes-(This->buflen-writecursor); + TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); + } + if (This->state == STATE_PLAYING) { + /* if the segment between playpos and buf_mixpos is touched, + * we need to cancel some mixing */ + /* we'll assume that the app always calls GetCurrentPosition before + * locking a playing buffer, so that last_playpos is up-to-date */ + if (This->buf_mixpos >= This->last_playpos) { + if (This->buf_mixpos > writecursor && + This->last_playpos < writecursor+writebytes) + remix = TRUE; + } else { + if (This->buf_mixpos > writecursor || + This->last_playpos < writecursor+writebytes) + remix = TRUE; + } + if (remix) { + TRACE("locking prebuffered region, ouch\n"); + DSOUND_MixCancelAt(This, writecursor); + } + } + } + + LeaveCriticalSection(&(This->lock)); + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_SetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,DWORD newpos +) { + HRESULT hres = DS_OK; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,newpos); + + /* **** */ + EnterCriticalSection(&(This->lock)); + + newpos %= This->buflen; + This->buf_mixpos = newpos; + if (This->hwbuf) { + hres = IDsDriverBuffer_SetPosition(This->hwbuf, This->buf_mixpos); + if (hres != DS_OK) + WARN("IDsDriverBuffer_SetPosition failed\n"); + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_SetPan( + LPDIRECTSOUNDBUFFER8 iface,LONG pan +) { + HRESULT hres = DS_OK; + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + + TRACE("(%p,%ld)\n",This,pan); + + if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { + WARN("invalid parameter: pan = %ld\n", pan); + return DSERR_INVALIDPARAM; + } + + /* You cannot use both pan and 3D controls */ + if (!(This->dsbd.dwFlags & DSBCAPS_CTRLPAN) || + (This->dsbd.dwFlags & DSBCAPS_CTRL3D)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + /* **** */ + EnterCriticalSection(&(This->lock)); + + if (This->volpan.lPan != pan) { + This->volpan.lPan = pan; + DSOUND_RecalcVolPan(&(This->volpan)); + + if (This->hwbuf) { + hres = IDsDriverBuffer_SetVolumePan(This->hwbuf, &(This->volpan)); + if (hres != DS_OK) + WARN("IDsDriverBuffer_SetVolumePan failed\n"); + } else + DSOUND_ForceRemix(This); + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_GetPan( + LPDIRECTSOUNDBUFFER8 iface,LPLONG pan +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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( + LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + DWORD probably_valid_to; + HRESULT hres = DS_OK; + + TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2); + + /* **** */ + EnterCriticalSection(&(This->lock)); + + if (!(This->dsound->device->drvdesc.dwFlags & DSDDESC_DONTNEEDSECONDARYLOCK) && This->hwbuf) { + hres = IDsDriverBuffer_Unlock(This->hwbuf, p1, x1, p2, x2); + if (hres != DS_OK) + WARN("IDsDriverBuffer_Unlock failed\n"); + } + + if (hres == DS_OK) { + if (p2) probably_valid_to = (((LPBYTE)p2)-This->buffer->memory) + x2; + else probably_valid_to = (((LPBYTE)p1)-This->buffer->memory) + x1; + probably_valid_to %= This->buflen; + if ((probably_valid_to == 0) && ((x1+x2) == This->buflen) && + ((This->state == STATE_STARTING) || + (This->state == STATE_PLAYING))) + /* see IDirectSoundBufferImpl_Lock */ + probably_valid_to = (DWORD)-1; + This->probably_valid_to = probably_valid_to; + } + + LeaveCriticalSection(&(This->lock)); + /* **** */ + + TRACE("probably_valid_to=%ld\n", This->probably_valid_to); + return hres; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_Restore( + LPDIRECTSOUNDBUFFER8 iface +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + FIXME("(%p):stub\n",This); + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_GetFrequency( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + TRACE("(%p,%p)\n",This,freq); + + if (freq == NULL) { + WARN("invalid parameter: freq = NULL\n"); + return DSERR_INVALIDPARAM; + } + + *freq = This->freq; + TRACE("-> %ld\n", *freq); + + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_SetFX( + LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + DWORD u; + + FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); + + if (pdwResultCodes) + for (u=0; u(%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 = %ld < %d\n",caps->dwSize, sizeof(*caps)); + return DSERR_INVALIDPARAM; + } + + caps->dwFlags = This->dsbd.dwFlags; + if (This->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; + else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; + + caps->dwBufferBytes = This->buflen; + + /* This value represents the speed of the "unlock" command. + As unlock is quite fast (it does not do anything), I put + 4096 ko/s = 4 Mo / s */ + /* FIXME: hwbuf speed */ + caps->dwUnlockTransferRate = 4096; + caps->dwPlayCpuOverhead = 0; + + return DS_OK; +} + +static HRESULT WINAPI IDirectSoundBufferImpl_QueryInterface( + LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj +) { + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)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) ) { + if (!This->dsb) + SecondaryBufferImpl_Create(This, &(This->dsb)); + if (This->dsb) { + IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)This->dsb); + *ppobj = This->dsb; + return S_OK; + } + WARN("IID_IDirectSoundBuffer\n"); + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { + if (!This->notify) + IDirectSoundNotifyImpl_Create(This, &(This->notify)); + if (This->notify) { + IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify); + *ppobj = This->notify; + return S_OK; + } + WARN("IID_IDirectSoundNotify\n"); + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { + if (!This->ds3db) + IDirectSound3DBufferImpl_Create(This, &(This->ds3db)); + if (This->ds3db) { + IDirectSound3DBuffer_AddRef((LPDIRECTSOUND3DBUFFER)This->ds3db); + *ppobj = This->ds3db; + return S_OK; + } + WARN("IID_IDirectSound3DBuffer\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 ) ) { + if (!This->iks) + IKsBufferPropertySetImpl_Create(This, &(This->iks)); + if (This->iks) { + IKsPropertySet_AddRef((LPKSPROPERTYSET)This->iks); + *ppobj = This->iks; + return S_OK; + } + WARN("IID_IKsPropertySet\n"); + return E_NOINTERFACE; + } + + 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 WINAPI IDirectSoundBufferImpl_Create( + IDirectSoundImpl *ds, + IDirectSoundBufferImpl **pdsb, + LPCDSBUFFERDESC dsbd) +{ + IDirectSoundBufferImpl *dsb; + LPWAVEFORMATEX wfex = dsbd->lpwfxFormat; + HRESULT err = DS_OK; + DWORD capf = 0; + int use_hw, alloc_size, cp_size; + TRACE("(%p,%p,%p)\n",ds,pdsb,dsbd); + + if (dsbd->dwBufferBytes < DSBSIZE_MIN || dsbd->dwBufferBytes > DSBSIZE_MAX) { + WARN("invalid parameter: dsbd->dwBufferBytes = %ld\n", dsbd->dwBufferBytes); + *pdsb = NULL; + return DSERR_INVALIDPARAM; /* FIXME: which error? */ + } + + dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); + + if (dsb == 0) { + WARN("out of memory\n"); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + + TRACE("Created buffer at %p\n", dsb); + + dsb->ref = 0; + dsb->dsb = 0; + dsb->dsound = ds; + dsb->lpVtbl = &dsbvt; + dsb->iks = NULL; + + /* size depends on version */ + CopyMemory(&dsb->dsbd, dsbd, dsbd->dwSize); + + /* variable sized struct so calculate size based on format */ + if (wfex->wFormatTag == WAVE_FORMAT_PCM) { + alloc_size = sizeof(WAVEFORMATEX); + cp_size = sizeof(PCMWAVEFORMAT); + } else + alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize; + + dsb->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alloc_size); + if (dsb->pwfx == NULL) { + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,dsb); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + + CopyMemory(dsb->pwfx, wfex, cp_size); + + 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->notify = NULL; + dsb->notifies = NULL; + dsb->nrofnotifies = 0; + dsb->hwnotify = 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; + + use_hw = (ds->device->drvcaps.dwFlags & capf) == capf; + TRACE("use_hw = 0x%08x, capf = 0x%08lx, ds->drvcaps.dwFlags = 0x%08lx\n", use_hw, capf, ds->device->drvcaps.dwFlags); + + /* FIXME: check hardware sample rate mixing capabilities */ + /* FIXME: check app hints for software/hardware buffer (STATIC, LOCHARDWARE, etc) */ + /* FIXME: check whether any hardware buffers are left */ + /* FIXME: handle DSDHEAP_CREATEHEAP for hardware buffers */ + + /* Allocate an empty buffer */ + dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer))); + if (dsb->buffer == NULL) { + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,dsb->pwfx); + HeapFree(GetProcessHeap(),0,dsb); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + + /* Allocate system memory for buffer if applicable */ + if ((ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) || !use_hw) { + dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen); + if (dsb->buffer->memory == NULL) { + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,dsb->pwfx); + HeapFree(GetProcessHeap(),0,dsb->buffer); + HeapFree(GetProcessHeap(),0,dsb); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + dsb->buffer->ref = 1; + FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0); + } + + /* Allocate the hardware buffer */ + if (use_hw) { + err = IDsDriver_CreateSoundBuffer(ds->device->driver,wfex,dsbd->dwFlags,0, + &(dsb->buflen),&(dsb->buffer->memory), + (LPVOID*)&(dsb->hwbuf)); + /* fall back to software buffer on failure */ + if (err != DS_OK) { + TRACE("IDsDriver_CreateSoundBuffer failed, falling back to software buffer\n"); + use_hw = 0; + if (ds->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { + dsb->buffer->memory = HeapAlloc(GetProcessHeap(),0,dsb->buflen); + if (dsb->buffer->memory == NULL) { + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,dsb->buffer); + HeapFree(GetProcessHeap(),0,dsb->pwfx); + HeapFree(GetProcessHeap(),0,dsb); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + dsb->buffer->ref = 1; + FillMemory(dsb->buffer->memory, dsb->buflen, dsbd->lpwfxFormat->wBitsPerSample == 8 ? 128 : 0); + } + err = DS_OK; + } + } + + /* calculate fragment size and write lead */ + DSOUND_RecalcFormat(dsb); + + /* It's not necessary to initialize values to zero since */ + /* we allocated this structure with HEAP_ZERO_MEMORY... */ + dsb->playpos = 0; + dsb->buf_mixpos = 0; + dsb->state = STATE_STOPPED; + + dsb->freqAdjust = (dsb->freq << DSOUND_FREQSHIFT) / + ds->device->pwfx->nSamplesPerSec; + dsb->nAvgBytesPerSec = dsb->freq * + dsbd->lpwfxFormat->nBlockAlign; + + 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)); + + InitializeCriticalSection(&(dsb->lock)); + dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock"; + + /* register buffer if not primary */ + if (!(dsbd->dwFlags & DSBCAPS_PRIMARYBUFFER)) { + err = DSOUND_AddBuffer(ds, dsb); + if (err != DS_OK) { + HeapFree(GetProcessHeap(),0,dsb->buffer->memory); + HeapFree(GetProcessHeap(),0,dsb->buffer); + dsb->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&(dsb->lock)); + HeapFree(GetProcessHeap(),0,dsb->pwfx); + HeapFree(GetProcessHeap(),0,dsb); + dsb = NULL; + } + } + + *pdsb = dsb; + return err; +} + +HRESULT WINAPI IDirectSoundBufferImpl_Destroy( + IDirectSoundBufferImpl *pdsb) +{ + TRACE("(%p)\n",pdsb); + + /* This keeps the *_Destroy functions from possibly deleting + * this object until it is ready to be deleted */ + IDirectSoundBufferImpl_AddRef((LPDIRECTSOUNDBUFFER8)pdsb); + + if (pdsb->iks) { + WARN("iks not NULL\n"); + IKsBufferPropertySetImpl_Destroy(pdsb->iks); + pdsb->iks = NULL; + } + + if (pdsb->ds3db) { + WARN("ds3db not NULL\n"); + IDirectSound3DBufferImpl_Destroy(pdsb->ds3db); + pdsb->ds3db = NULL; + } + + if (pdsb->notify) { + WARN("notify not NULL\n"); + IDirectSoundNotifyImpl_Destroy(pdsb->notify); + pdsb->notify = NULL; + } + + if (pdsb->dsb) { + WARN("dsb not NULL\n"); + SecondaryBufferImpl_Destroy(pdsb->dsb); + pdsb->dsb = NULL; + } + + while (IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); + + return S_OK; +} + +/******************************************************************************* + * SecondaryBuffer + */ + +static HRESULT WINAPI SecondaryBufferImpl_QueryInterface( + LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + + return IDirectSoundBufferImpl_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb,riid,ppobj); +} + +static ULONG WINAPI SecondaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) +{ + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI SecondaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) +{ + IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + This->dsb->dsb = NULL; + IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI SecondaryBufferImpl_GetCaps( + LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p)->(%p)\n",This,caps); + + return IDirectSoundBufferImpl_GetCaps((LPDIRECTSOUNDBUFFER8)This->dsb,caps); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p,%p)\n",This,playpos,writepos); + + return IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,playpos,writepos); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetFormat( + LPDIRECTSOUNDBUFFER8 iface,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); + + return IDirectSoundBufferImpl_GetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,lpwf,wfsize,wfwritten); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetVolume( + LPDIRECTSOUNDBUFFER8 iface,LPLONG vol) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p)\n",This,vol); + + return IDirectSoundBufferImpl_GetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetPan( + LPDIRECTSOUNDBUFFER8 iface,LPLONG pan) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p)\n",This,pan); + + return IDirectSoundBufferImpl_GetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetFrequency( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p)\n",This,freq); + + return IDirectSoundBufferImpl_GetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetStatus( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD status) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p)\n",This,status); + + return IDirectSoundBufferImpl_GetStatus((LPDIRECTSOUNDBUFFER8)This->dsb,status); +} + +static HRESULT WINAPI SecondaryBufferImpl_Initialize( + LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p,%p)\n",This,dsound,dbsd); + + return IDirectSoundBufferImpl_Initialize((LPDIRECTSOUNDBUFFER8)This->dsb,dsound,dbsd); +} + +static HRESULT WINAPI SecondaryBufferImpl_Lock( + LPDIRECTSOUNDBUFFER8 iface, + DWORD writecursor, + DWORD writebytes, + LPVOID lplpaudioptr1, + LPDWORD audiobytes1, + LPVOID lplpaudioptr2, + LPDWORD audiobytes2, + DWORD dwFlags) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx)\n", + This,writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); + + return IDirectSoundBufferImpl_Lock((LPDIRECTSOUNDBUFFER8)This->dsb, + writecursor,writebytes,lplpaudioptr1,audiobytes1,lplpaudioptr2,audiobytes2,dwFlags); +} + +static HRESULT WINAPI SecondaryBufferImpl_Play( + LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%08lx,%08lx,%08lx)\n",This,reserved1,reserved2,flags); + + return IDirectSoundBufferImpl_Play((LPDIRECTSOUNDBUFFER8)This->dsb,reserved1,reserved2,flags); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,DWORD newpos) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,newpos); + + return IDirectSoundBufferImpl_SetCurrentPosition((LPDIRECTSOUNDBUFFER8)This->dsb,newpos); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetFormat( + LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p)\n",This,wfex); + + return IDirectSoundBufferImpl_SetFormat((LPDIRECTSOUNDBUFFER8)This->dsb,wfex); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetVolume( + LPDIRECTSOUNDBUFFER8 iface,LONG vol) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,vol); + + return IDirectSoundBufferImpl_SetVolume((LPDIRECTSOUNDBUFFER8)This->dsb,vol); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetPan( + LPDIRECTSOUNDBUFFER8 iface,LONG pan) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,pan); + + return IDirectSoundBufferImpl_SetPan((LPDIRECTSOUNDBUFFER8)This->dsb,pan); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetFrequency( + LPDIRECTSOUNDBUFFER8 iface,DWORD freq) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,freq); + + return IDirectSoundBufferImpl_SetFrequency((LPDIRECTSOUNDBUFFER8)This->dsb,freq); +} + +static HRESULT WINAPI SecondaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p)\n",This); + + return IDirectSoundBufferImpl_Stop((LPDIRECTSOUNDBUFFER8)This->dsb); +} + +static HRESULT WINAPI SecondaryBufferImpl_Unlock( + LPDIRECTSOUNDBUFFER8 iface, + LPVOID lpvAudioPtr1, + DWORD dwAudioBytes1, + LPVOID lpvAudioPtr2, + DWORD dwAudioBytes2) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%p,%ld,%p,%ld)\n", + This, lpvAudioPtr1, dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); + + return IDirectSoundBufferImpl_Unlock((LPDIRECTSOUNDBUFFER8)This->dsb, + lpvAudioPtr1,dwAudioBytes1,lpvAudioPtr2,dwAudioBytes2); +} + +static HRESULT WINAPI SecondaryBufferImpl_Restore( + LPDIRECTSOUNDBUFFER8 iface) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p)\n",This); + + return IDirectSoundBufferImpl_Restore((LPDIRECTSOUNDBUFFER8)This->dsb); +} + +static HRESULT WINAPI SecondaryBufferImpl_SetFX( + LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%lu,%p,%p)\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); + + return IDirectSoundBufferImpl_SetFX((LPDIRECTSOUNDBUFFER8)This->dsb,dwEffectsCount,pDSFXDesc,pdwResultCodes); +} + +static HRESULT WINAPI SecondaryBufferImpl_AcquireResources( + LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%08lu,%lu,%p)\n",This,dwFlags,dwEffectsCount,pdwResultCodes); + + return IDirectSoundBufferImpl_AcquireResources((LPDIRECTSOUNDBUFFER8)This->dsb,dwFlags,dwEffectsCount,pdwResultCodes); +} + +static HRESULT WINAPI SecondaryBufferImpl_GetObjectInPath( + LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject) +{ + SecondaryBufferImpl *This = (SecondaryBufferImpl *)iface; + TRACE("(%p,%s,%lu,%s,%p)\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject); + + return IDirectSoundBufferImpl_GetObjectInPath((LPDIRECTSOUNDBUFFER8)This->dsb,rguidObject,dwIndex,rguidInterface,ppObject); +} + +static const IDirectSoundBuffer8Vtbl sbvt = +{ + SecondaryBufferImpl_QueryInterface, + SecondaryBufferImpl_AddRef, + SecondaryBufferImpl_Release, + SecondaryBufferImpl_GetCaps, + SecondaryBufferImpl_GetCurrentPosition, + SecondaryBufferImpl_GetFormat, + SecondaryBufferImpl_GetVolume, + SecondaryBufferImpl_GetPan, + SecondaryBufferImpl_GetFrequency, + SecondaryBufferImpl_GetStatus, + SecondaryBufferImpl_Initialize, + SecondaryBufferImpl_Lock, + SecondaryBufferImpl_Play, + SecondaryBufferImpl_SetCurrentPosition, + SecondaryBufferImpl_SetFormat, + SecondaryBufferImpl_SetVolume, + SecondaryBufferImpl_SetPan, + SecondaryBufferImpl_SetFrequency, + SecondaryBufferImpl_Stop, + SecondaryBufferImpl_Unlock, + SecondaryBufferImpl_Restore, + SecondaryBufferImpl_SetFX, + SecondaryBufferImpl_AcquireResources, + SecondaryBufferImpl_GetObjectInPath +}; + +HRESULT WINAPI SecondaryBufferImpl_Create( + IDirectSoundBufferImpl *dsb, + SecondaryBufferImpl **psb) +{ + SecondaryBufferImpl *sb; + TRACE("(%p,%p)\n",dsb,psb); + + sb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*sb)); + + if (sb == 0) { + WARN("out of memory\n"); + *psb = NULL; + return DSERR_OUTOFMEMORY; + } + sb->ref = 0; + sb->dsb = dsb; + sb->lpVtbl = &sbvt; + + IDirectSoundBuffer8_AddRef((LPDIRECTSOUNDBUFFER8)dsb); + *psb = sb; + return S_OK; +} + +HRESULT WINAPI SecondaryBufferImpl_Destroy( + SecondaryBufferImpl *pdsb) +{ + TRACE("(%p)\n",pdsb); + + while (SecondaryBufferImpl_Release((LPDIRECTSOUNDBUFFER8)pdsb) > 0); + + return S_OK; +} diff --git a/reactos/lib/dsound/capture.c b/reactos/lib/dsound/capture.c index 32ba93aaa8f..ea7957f4544 100644 --- a/reactos/lib/dsound/capture.c +++ b/reactos/lib/dsound/capture.c @@ -1,1888 +1,1797 @@ -/* DirectSoundCapture - * - * Copyright 1998 Marcus Meissner - * Copyright 1998 Rob Riggs - * Copyright 2000-2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * TODO: - * Implement DirectSoundFullDuplex support. - * Implement FX support. - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "mmddk.h" -#include "winreg.h" -#include "winternl.h" -#include "winnls.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - -static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize( - LPDIRECTSOUNDCAPTURE iface, - LPCGUID lpcGUID ); -static ULONG WINAPI IDirectSoundCaptureImpl_Release( - LPDIRECTSOUNDCAPTURE iface ); -static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release( - LPDIRECTSOUNDCAPTUREBUFFER8 iface ); -static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( - IDirectSoundCaptureImpl *ipDSC, - LPCDSCBUFFERDESC lpcDSCBufferDesc, - LPVOID* ppobj ); -static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize( - LPDIRECTSOUNDFULLDUPLEX iface, - LPCGUID pCaptureGuid, - LPCGUID pRendererGuid, - LPCDSCBUFFERDESC lpDscBufferDesc, - LPCDSBUFFERDESC lpDsBufferDesc, - HWND hWnd, - DWORD dwLevel, - LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, - LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 ); - -static IDirectSoundCaptureVtbl dscvt; -static IDirectSoundCaptureBuffer8Vtbl dscbvt; -static IDirectSoundFullDuplexVtbl dsfdvt; - -static IDirectSoundCaptureImpl* dsound_capture = NULL; - -static const char * captureStateString[] = { - "STATE_STOPPED", - "STATE_STARTING", - "STATE_CAPTURING", - "STATE_STOPPING" -}; - -/*************************************************************************** - * DirectSoundCaptureCreate [DSOUND.6] - * - * Create and initialize a DirectSoundCapture interface. - * - * PARAMS - * lpcGUID [I] Address of the GUID that identifies the sound capture device. - * lplpDSC [O] Address of a variable to receive the interface pointer. - * pUnkOuter [I] Must be NULL. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, - * DSERR_OUTOFMEMORY - * - * NOTES - * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate - * or NULL for the default device or DSDEVID_DefaultCapture or - * DSDEVID_DefaultVoiceCapture. - * - * DSERR_ALLOCATED is returned for sound devices that do not support full duplex. - */ -HRESULT WINAPI -DirectSoundCaptureCreate8( - LPCGUID lpcGUID, - LPDIRECTSOUNDCAPTURE* lplpDSC, - LPUNKNOWN pUnkOuter ) -{ - IDirectSoundCaptureImpl** ippDSC=(IDirectSoundCaptureImpl**)lplpDSC; - TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), lplpDSC, pUnkOuter); - - if ( pUnkOuter ) { - WARN("invalid parameter: pUnkOuter != NULL\n"); - return DSERR_NOAGGREGATION; - } - - if ( !lplpDSC ) { - WARN("invalid parameter: lplpDSC == NULL\n"); - return DSERR_INVALIDPARAM; - } - - /* Default device? */ - if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) ) - lpcGUID = &DSDEVID_DefaultCapture; - - *ippDSC = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(IDirectSoundCaptureImpl)); - - if (*ippDSC == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } else { - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)*ippDSC; - - This->ref = 1; - This->state = STATE_STOPPED; - - InitializeCriticalSection( &(This->lock) ); - This->lock.DebugInfo->Spare[1] = (DWORD)"DSCAPTURE_lock"; - - This->lpVtbl = &dscvt; - dsound_capture = This; - - if (GetDeviceID(lpcGUID, &This->guid) == DS_OK) { - HRESULT hres; - hres = IDirectSoundCaptureImpl_Initialize( (LPDIRECTSOUNDCAPTURE)This, &This->guid); - if (hres != DS_OK) - WARN("IDirectSoundCaptureImpl_Initialize failed\n"); - return hres; - } - } - WARN("invalid GUID: %s\n", debugstr_guid(lpcGUID)); - return DSERR_INVALIDPARAM; -} - -/*************************************************************************** - * DirectSoundCaptureEnumerateA [DSOUND.7] - * - * Enumerate all DirectSound drivers installed in the system. - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI -DirectSoundCaptureEnumerateA( - LPDSENUMCALLBACKA lpDSEnumCallback, - LPVOID lpContext) -{ - unsigned devs, wid; - DSDRIVERDESC desc; - GUID guid; - int err; - - TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveInGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { - for (wid = 0; wid < devs; ++wid) { - if (IsEqualGUID( &guid, &capture_guids[wid] ) ) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Capture Driver",desc.szDrvname,lpContext); - if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wid = 0; wid < devs; ++wid) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); - if (lpDSEnumCallback(&capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - - return DS_OK; -} - -/*************************************************************************** - * DirectSoundCaptureEnumerateW [DSOUND.8] - * - * Enumerate all DirectSound drivers installed in the system. - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI -DirectSoundCaptureEnumerateW( - LPDSENUMCALLBACKW lpDSEnumCallback, - LPVOID lpContext) -{ - unsigned devs, wid; - DSDRIVERDESC desc; - GUID guid; - int err; - WCHAR wDesc[MAXPNAMELEN]; - WCHAR wName[MAXPNAMELEN]; - - TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveInGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { - for (wid = 0; wid < devs; ++wid) { - if (IsEqualGUID( &guid, &capture_guids[wid] ) ) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Capture Driver",desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wid = 0; wid < devs; ++wid) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback((LPGUID)&capture_guids[wid], wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - - return DS_OK; -} - -static void CALLBACK -DSOUND_capture_callback( - HWAVEIN hwi, - UINT msg, - DWORD dwUser, - DWORD dw1, - DWORD dw2 ) -{ - IDirectSoundCaptureImpl* This = (IDirectSoundCaptureImpl*)dwUser; - TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg, - msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" : - msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount()); - - if (msg == MM_WIM_DATA) { - LPWAVEHDR pHdr = (LPWAVEHDR)dw1; - EnterCriticalSection( &(This->lock) ); - TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n", - captureStateString[This->state],This->index); - if (This->state != STATE_STOPPED) { - int index = This->index; - if (This->state == STATE_STARTING) { - This->read_position = pHdr->dwBytesRecorded; - This->state = STATE_CAPTURING; - } - waveInUnprepareHeader(hwi,&(This->pwave[This->index]),sizeof(WAVEHDR)); - if (This->capture_buffer->nrofnotifies) - SetEvent(This->capture_buffer->notifies[This->index].hEventNotify); - This->index = (This->index + 1) % This->nrofpwaves; - if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) { - TRACE("end of buffer\n"); - This->state = STATE_STOPPED; - } else { - if (This->state == STATE_CAPTURING) { - waveInPrepareHeader(hwi,&(This->pwave[index]),sizeof(WAVEHDR)); - waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR)); - } else if (This->state == STATE_STOPPING) { - TRACE("stopping\n"); - This->state = STATE_STOPPED; - } - } - } - TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n", - captureStateString[This->state],This->index); - LeaveCriticalSection( &(This->lock) ); - } - - TRACE("completed\n"); -} - -static HRESULT WINAPI -IDirectSoundCaptureImpl_QueryInterface( - LPDIRECTSOUNDCAPTURE iface, - REFIID riid, - LPVOID* ppobj ) -{ - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppobj = NULL; - - if (This->driver) { - HRESULT hres; - hres = IDsCaptureDriver_QueryInterface(This->driver, riid, ppobj); - if (hres != DS_OK) - WARN("IDsCaptureDriver_QueryInterface failed\n"); - return hres; - } - - WARN("unsupported riid: %s\n", debugstr_guid(riid)); - return E_FAIL; -} - -static ULONG WINAPI -IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface ) -{ - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface ) -{ - ULONG uRef; - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - uRef = InterlockedDecrement(&(This->ref)); - if ( uRef == 0 ) { - TRACE("deleting object\n"); - if (This->capture_buffer) - IDirectSoundCaptureBufferImpl_Release( - (LPDIRECTSOUNDCAPTUREBUFFER8) This->capture_buffer); - - if (This->driver) { - IDsCaptureDriver_Close(This->driver); - IDsCaptureDriver_Release(This->driver); - } - - if (This->pwfx) - HeapFree(GetProcessHeap(), 0, This->pwfx); - - This->lock.DebugInfo->Spare[1] = 0; - DeleteCriticalSection( &(This->lock) ); - HeapFree( GetProcessHeap(), 0, This ); - dsound_capture = NULL; - TRACE("(%p) released\n",This); - } - - return uRef; -} - -static HRESULT WINAPI -IDirectSoundCaptureImpl_CreateCaptureBuffer( - LPDIRECTSOUNDCAPTURE iface, - LPCDSCBUFFERDESC lpcDSCBufferDesc, - LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer, - LPUNKNOWN pUnk ) -{ - HRESULT hr; - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - - TRACE( "(%p,%p,%p,%p)\n",This,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpcDSCBufferDesc == NULL) { - WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n"); - return DSERR_INVALIDPARAM; - } - - if (lplpDSCaptureBuffer == NULL) { - WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (pUnk != NULL) { - WARN("invalid parameter: pUnk != NULL\n"); - return DSERR_INVALIDPARAM; - } - - /* FIXME: We can only have one buffer so what do we do here? */ - if (This->capture_buffer) { - WARN("lnvalid parameter: already has buffer\n"); - return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */ - } - - hr = DSOUND_CreateDirectSoundCaptureBuffer( This, lpcDSCBufferDesc, - (LPVOID*)lplpDSCaptureBuffer ); - - if (hr != DS_OK) - WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n"); - - return hr; -} - -static HRESULT WINAPI -IDirectSoundCaptureImpl_GetCaps( - LPDIRECTSOUNDCAPTURE iface, - LPDSCCAPS lpDSCCaps ) -{ - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - TRACE("(%p,%p)\n",This,lpDSCCaps); - - if (lpDSCCaps== NULL) { - WARN("invalid parameter: lpDSCCaps== NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) { - WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n", - lpDSCCaps->dwSize, sizeof(*lpDSCCaps)); - return DSERR_INVALIDPARAM; - } - - if ( !(This->initialized) ) { - WARN("not initialized\n"); - return DSERR_UNINITIALIZED; - } - - lpDSCCaps->dwFlags = This->drvcaps.dwFlags; - lpDSCCaps->dwFormats = This->drvcaps.dwFormats; - lpDSCCaps->dwChannels = This->drvcaps.dwChannels; - - TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags, - lpDSCCaps->dwFormats, lpDSCCaps->dwChannels); - - return DS_OK; -} - -static HRESULT WINAPI -IDirectSoundCaptureImpl_Initialize( - LPDIRECTSOUNDCAPTURE iface, - LPCGUID lpcGUID ) -{ - HRESULT err = DSERR_INVALIDPARAM; - unsigned wid, widn; - IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; - TRACE("(%p)\n", This); - - if (!This) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->initialized) { - WARN("already initialized\n"); - return DSERR_ALREADYINITIALIZED; - } - - widn = waveInGetNumDevs(); - - if (!widn) { - WARN("no audio devices found\n"); - return DSERR_NODRIVER; - } - - /* Get dsound configuration */ - setup_dsound_options(); - - /* enumerate WINMM audio devices and find the one we want */ - for (wid=0; widdriver),0)); - if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) { - WARN("WineWaveInMessage failed; err=%lx\n",err); - return err; - } - err = DS_OK; - - /* Disable the direct sound driver to force emulation if requested. */ - if (ds_hw_accel == DS_HW_ACCEL_EMULATION) - This->driver = NULL; - - /* Get driver description */ - if (This->driver) { - TRACE("using DirectSound driver\n"); - err = IDsCaptureDriver_GetDriverDesc(This->driver, &(This->drvdesc)); - if (err != DS_OK) { - WARN("IDsCaptureDriver_GetDriverDesc failed\n"); - return err; - } - } else { - TRACE("using WINMM\n"); - /* if no DirectSound interface available, use WINMM API instead */ - This->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | - DSDDESC_DOMMSYSTEMSETFORMAT; - } - - This->drvdesc.dnDevNode = wid; - - /* open the DirectSound driver if available */ - if (This->driver && (err == DS_OK)) - err = IDsCaptureDriver_Open(This->driver); - - if (err == DS_OK) { - This->initialized = TRUE; - - /* the driver is now open, so it's now allowed to call GetCaps */ - if (This->driver) { - This->drvcaps.dwSize = sizeof(This->drvcaps); - err = IDsCaptureDriver_GetCaps(This->driver,&(This->drvcaps)); - if (err != DS_OK) { - WARN("IDsCaptureDriver_GetCaps failed\n"); - return err; - } - } else /*if (This->hwi)*/ { - WAVEINCAPSA wic; - err = mmErr(waveInGetDevCapsA((UINT)This->drvdesc.dnDevNode, &wic, sizeof(wic))); - - if (err == DS_OK) { - This->drvcaps.dwFlags = 0; - strncpy(This->drvdesc.szDrvname, wic.szPname, - sizeof(This->drvdesc.szDrvname)); - - This->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER; - This->drvcaps.dwFormats = wic.dwFormats; - This->drvcaps.dwChannels = wic.wChannels; - } - } - } - - return err; -} - -static IDirectSoundCaptureVtbl dscvt = -{ - /* IUnknown methods */ - IDirectSoundCaptureImpl_QueryInterface, - IDirectSoundCaptureImpl_AddRef, - IDirectSoundCaptureImpl_Release, - - /* IDirectSoundCapture methods */ - IDirectSoundCaptureImpl_CreateCaptureBuffer, - IDirectSoundCaptureImpl_GetCaps, - IDirectSoundCaptureImpl_Initialize -}; - -static HRESULT -DSOUND_CreateDirectSoundCaptureBuffer( - IDirectSoundCaptureImpl *ipDSC, - LPCDSCBUFFERDESC lpcDSCBufferDesc, - LPVOID* ppobj ) -{ - LPWAVEFORMATEX wfex; - TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj ); - - if (ipDSC == NULL) { - WARN("invalid parameter: ipDSC == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpcDSCBufferDesc == NULL) { - WARN("invalid parameter: lpcDSCBufferDesc == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (ppobj == NULL) { - WARN("invalid parameter: ppobj == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) && - (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) || - (lpcDSCBufferDesc->dwBufferBytes == 0) || - (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { - WARN("invalid lpcDSCBufferDesc\n"); - *ppobj = NULL; - return DSERR_INVALIDPARAM; - } - - if ( !ipDSC->initialized ) { - WARN("not initialized\n"); - *ppobj = NULL; - return DSERR_UNINITIALIZED; - } - - wfex = lpcDSCBufferDesc->lpwfxFormat; - - if (wfex) { - TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," - "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", - wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, - wfex->nAvgBytesPerSec, wfex->nBlockAlign, - wfex->wBitsPerSample, wfex->cbSize); - - if (wfex->wFormatTag == WAVE_FORMAT_PCM) { - ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)); - memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)); - ipDSC->pwfx->cbSize = 0; - } else { - ipDSC->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize); - memcpy(ipDSC->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize); - } - } else { - WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n"); - *ppobj = NULL; - return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */ - } - - *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - sizeof(IDirectSoundCaptureBufferImpl)); - - if ( *ppobj == NULL ) { - WARN("out of memory\n"); - *ppobj = NULL; - return DSERR_OUTOFMEMORY; - } else { - HRESULT err = DS_OK; - LPBYTE newbuf; - DWORD buflen; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj; - - This->ref = 1; - This->dsound = ipDSC; - This->dsound->capture_buffer = This; - This->notify = NULL; - This->nrofnotifies = 0; - This->hwnotify = NULL; - - This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - lpcDSCBufferDesc->dwSize); - if (This->pdscbd) - memcpy(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize); - else { - WARN("no memory\n"); - This->dsound->capture_buffer = 0; - HeapFree( GetProcessHeap(), 0, This ); - *ppobj = NULL; - return DSERR_OUTOFMEMORY; - } - - This->lpVtbl = &dscbvt; - - if (ipDSC->driver) { - if (This->dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) - FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n"); - - if (This->dsound->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { - /* allocate buffer from system memory */ - buflen = lpcDSCBufferDesc->dwBufferBytes; - TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer); - if (ipDSC->buffer) - newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen); - else - newbuf = HeapAlloc(GetProcessHeap(),0,buflen); - - if (newbuf == NULL) { - WARN("failed to allocate capture buffer\n"); - err = DSERR_OUTOFMEMORY; - /* but the old buffer might still exist and must be re-prepared */ - } else { - ipDSC->buffer = newbuf; - ipDSC->buflen = buflen; - } - } else { - /* let driver allocate memory */ - ipDSC->buflen = lpcDSCBufferDesc->dwBufferBytes; - /* FIXME: */ - if (ipDSC->buffer) - HeapFree( GetProcessHeap(), 0, ipDSC->buffer); - ipDSC->buffer = NULL; - } - - err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->driver, - ipDSC->pwfx,0,0,&(ipDSC->buflen),&(ipDSC->buffer),(LPVOID*)&(ipDSC->hwbuf)); - if (err != DS_OK) { - WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n"); - This->dsound->capture_buffer = 0; - HeapFree( GetProcessHeap(), 0, This ); - *ppobj = NULL; - return err; - } - } else { - DWORD flags = CALLBACK_FUNCTION; - if (ds_hw_accel != DS_HW_ACCEL_EMULATION) - flags |= WAVE_DIRECTSOUND; - err = mmErr(waveInOpen(&(ipDSC->hwi), - ipDSC->drvdesc.dnDevNode, ipDSC->pwfx, - (DWORD)DSOUND_capture_callback, (DWORD)ipDSC, flags)); - if (err != DS_OK) { - WARN("waveInOpen failed\n"); - This->dsound->capture_buffer = 0; - HeapFree( GetProcessHeap(), 0, This ); - *ppobj = NULL; - return err; - } - - buflen = lpcDSCBufferDesc->dwBufferBytes; - TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->buffer); - if (ipDSC->buffer) - newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->buffer,buflen); - else - newbuf = HeapAlloc(GetProcessHeap(),0,buflen); - if (newbuf == NULL) { - WARN("failed to allocate capture buffer\n"); - err = DSERR_OUTOFMEMORY; - /* but the old buffer might still exist and must be re-prepared */ - } else { - ipDSC->buffer = newbuf; - ipDSC->buflen = buflen; - } - } - } - - TRACE("returning DS_OK\n"); - return DS_OK; -} - -/******************************************************************************* - * IDirectSoundCaptureNotify - */ -static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface( - LPDIRECTSOUNDNOTIFY iface, - REFIID riid, - LPVOID *ppobj) -{ - IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - - if (This->dscb == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj); -} - -static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) -{ - IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) -{ - IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; - ULONG ref; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) { - if (This->dscb->hwnotify) - IDsDriverNotify_Release(This->dscb->hwnotify); - This->dscb->notify=NULL; - IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - return ref; -} - -static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions( - LPDIRECTSOUNDNOTIFY iface, - DWORD howmuch, - LPCDSBPOSITIONNOTIFY notify) -{ - IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; - TRACE("(%p,0x%08lx,%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;idscb->hwnotify) { - HRESULT hres; - hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify); - if (hres != DS_OK) - WARN("IDsDriverNotify_SetNotificationPositions failed\n"); - return hres; - } else if (howmuch > 0) { - /* Make an internal copy of the caller-supplied array. - * Replace the existing copy if one is already present. */ - if (This->dscb->notifies) - This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY)); - else - This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - howmuch * sizeof(DSBPOSITIONNOTIFY)); - - if (This->dscb->notifies == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } - memcpy(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY)); - This->dscb->nrofnotifies = howmuch; - } else { - if (This->dscb->notifies) { - HeapFree(GetProcessHeap(), 0, This->dscb->notifies); - This->dscb->notifies = NULL; - } - This->dscb->nrofnotifies = 0; - } - - return S_OK; -} - -IDirectSoundNotifyVtbl dscnvt = -{ - IDirectSoundCaptureNotifyImpl_QueryInterface, - IDirectSoundCaptureNotifyImpl_AddRef, - IDirectSoundCaptureNotifyImpl_Release, - IDirectSoundCaptureNotifyImpl_SetNotificationPositions, -}; - -HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create( - IDirectSoundCaptureBufferImpl *dscb, - IDirectSoundCaptureNotifyImpl **pdscn) -{ - IDirectSoundCaptureNotifyImpl * dscn; - TRACE("(%p,%p)\n",dscb,pdscn); - - dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn)); - - if (dscn == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } - - dscn->ref = 0; - dscn->lpVtbl = &dscnvt; - dscn->dscb = dscb; - dscb->notify = dscn; - IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb); - - *pdscn = dscn; - return DS_OK; -} - -/******************************************************************************* - * IDirectSoundCaptureBuffer - */ -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_QueryInterface( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - REFIID riid, - LPVOID* ppobj ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - HRESULT hres; - TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppobj = NULL; - - if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { - if (!This->notify) - hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify); - if (This->notify) { - if (This->dsound->hwbuf) { - hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->hwbuf, - &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify)); - if (hres != DS_OK) { - WARN("IDsCaptureDriverBuffer_QueryInterface failed\n"); - *ppobj = 0; - return hres; - } - } - - IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify); - *ppobj = (LPVOID)This->notify; - return DS_OK; - } - - WARN("IID_IDirectSoundNotify\n"); - return E_FAIL; - } - - if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) || - IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) { - IDirectSoundCaptureBuffer8_AddRef(iface); - *ppobj = This; - return NO_ERROR; - } - - FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) -{ - ULONG uRef; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - uRef = InterlockedDecrement(&(This->ref)); - if ( uRef == 0 ) { - TRACE("deleting object\n"); - if (This->dsound->state == STATE_CAPTURING) - This->dsound->state = STATE_STOPPING; - - if (This->pdscbd) - HeapFree(GetProcessHeap(),0, This->pdscbd); - - if (This->dsound->hwi) { - waveInReset(This->dsound->hwi); - waveInClose(This->dsound->hwi); - if (This->dsound->pwave) { - HeapFree(GetProcessHeap(),0, This->dsound->pwave); - This->dsound->pwave = 0; - } - This->dsound->hwi = 0; - } - - if (This->dsound->hwbuf) - IDsCaptureDriverBuffer_Release(This->dsound->hwbuf); - - /* remove from IDirectSoundCaptureImpl */ - if (This->dsound) - This->dsound->capture_buffer = NULL; - else - ERR("does not reference dsound\n"); - - if (This->notify) - IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify); - - if (This->notifies != NULL) - HeapFree(GetProcessHeap(), 0, This->notifies); - - HeapFree( GetProcessHeap(), 0, This ); - TRACE("(%p) released\n",This); - } - - return uRef; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetCaps( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPDSCBCAPS lpDSCBCaps ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p,%p)\n", This, lpDSCBCaps ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpDSCBCaps == NULL) { - WARN("invalid parameter: lpDSCBCaps == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) { - WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n", - lpDSCBCaps->dwSize, sizeof(DSCBCAPS)); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - lpDSCBCaps->dwSize = sizeof(DSCBCAPS); - lpDSCBCaps->dwFlags = This->flags; - lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes; - lpDSCBCaps->dwReserved = 0; - - TRACE("returning DS_OK\n"); - return DS_OK; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetCurrentPosition( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPDWORD lpdwCapturePosition, - LPDWORD lpdwReadPosition ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - HRESULT hres = DS_OK; - TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound->driver) { - hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->hwbuf, lpdwCapturePosition, lpdwReadPosition ); - if (hres != DS_OK) - WARN("IDsCaptureDriverBuffer_GetPosition failed\n"); - } else if (This->dsound->hwi) { - EnterCriticalSection(&(This->dsound->lock)); - TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]); - if (lpdwCapturePosition) { - MMTIME mtime; - mtime.wType = TIME_BYTES; - waveInGetPosition(This->dsound->hwi, &mtime, sizeof(mtime)); - TRACE("mtime.u.cb=%ld,This->dsound->buflen=%ld\n", mtime.u.cb, - This->dsound->buflen); - mtime.u.cb = mtime.u.cb % This->dsound->buflen; - *lpdwCapturePosition = mtime.u.cb; - } - - if (lpdwReadPosition) { - if (This->dsound->state == STATE_STARTING) { - if (lpdwCapturePosition) - This->dsound->read_position = *lpdwCapturePosition; - This->dsound->state = STATE_CAPTURING; - } - *lpdwReadPosition = This->dsound->read_position; - } - TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]); - LeaveCriticalSection(&(This->dsound->lock)); - if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition); - if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition); - } else { - WARN("no driver\n"); - hres = DSERR_NODRIVER; - } - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetFormat( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPWAVEFORMATEX lpwfxFormat, - DWORD dwSizeAllocated, - LPDWORD lpdwSizeWritten ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - HRESULT hres = DS_OK; - TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, - lpdwSizeWritten ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize)) - dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; - - if (lpwfxFormat) { /* NULL is valid (just want size) */ - memcpy(lpwfxFormat, This->dsound->pwfx, dwSizeAllocated); - if (lpdwSizeWritten) - *lpdwSizeWritten = dwSizeAllocated; - } else { - if (lpdwSizeWritten) - *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; - else { - TRACE("invalid parameter: lpdwSizeWritten = NULL\n"); - hres = DSERR_INVALIDPARAM; - } - } - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetStatus( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPDWORD lpdwStatus ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpdwStatus == NULL) { - WARN("invalid parameter: lpdwStatus == NULL\n"); - return DSERR_INVALIDPARAM; - } - - *lpdwStatus = 0; - EnterCriticalSection(&(This->dsound->lock)); - - TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n", - captureStateString[This->dsound->state],*lpdwStatus); - if ((This->dsound->state == STATE_STARTING) || - (This->dsound->state == STATE_CAPTURING)) { - *lpdwStatus |= DSCBSTATUS_CAPTURING; - if (This->flags & DSCBSTART_LOOPING) - *lpdwStatus |= DSCBSTATUS_LOOPING; - } - TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n", - captureStateString[This->dsound->state],*lpdwStatus); - LeaveCriticalSection(&(This->dsound->lock)); - - TRACE("status=%lx\n", *lpdwStatus); - TRACE("returning DS_OK\n"); - return DS_OK; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_Initialize( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPDIRECTSOUNDCAPTURE lpDSC, - LPCDSCBUFFERDESC lpcDSCBDesc ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - - FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc ); - - return DS_OK; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_Lock( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - DWORD dwReadCusor, - DWORD dwReadBytes, - LPVOID* lplpvAudioPtr1, - LPDWORD lpdwAudioBytes1, - LPVOID* lplpvAudioPtr2, - LPDWORD lpdwAudioBytes2, - DWORD dwFlags ) -{ - HRESULT hres = DS_OK; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor, - dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, - lpdwAudioBytes2, dwFlags, GetTickCount() ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lplpvAudioPtr1 == NULL) { - WARN("invalid parameter: lplpvAudioPtr1 == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpdwAudioBytes1 == NULL) { - WARN("invalid parameter: lpdwAudioBytes1 == NULL\n"); - return DSERR_INVALIDPARAM; - } - - EnterCriticalSection(&(This->dsound->lock)); - - if (This->dsound->driver) { - hres = IDsCaptureDriverBuffer_Lock(This->dsound->hwbuf, lplpvAudioPtr1, - lpdwAudioBytes1, lplpvAudioPtr2, - lpdwAudioBytes2, dwReadCusor, - dwReadBytes, dwFlags); - if (hres != DS_OK) - WARN("IDsCaptureDriverBuffer_Lock failed\n"); - } else if (This->dsound->hwi) { - *lplpvAudioPtr1 = This->dsound->buffer + dwReadCusor; - if ( (dwReadCusor + dwReadBytes) > This->dsound->buflen) { - *lpdwAudioBytes1 = This->dsound->buflen - dwReadCusor; - if (lplpvAudioPtr2) - *lplpvAudioPtr2 = This->dsound->buffer; - if (lpdwAudioBytes2) - *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1; - } else { - *lpdwAudioBytes1 = dwReadBytes; - if (lplpvAudioPtr2) - *lplpvAudioPtr2 = 0; - if (lpdwAudioBytes2) - *lpdwAudioBytes2 = 0; - } - } else { - TRACE("invalid call\n"); - hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */ - } - - LeaveCriticalSection(&(This->dsound->lock)); - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_Start( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - DWORD dwFlags ) -{ - HRESULT hres = DS_OK; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p,0x%08lx)\n", This, dwFlags ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if ( (This->dsound->driver == 0) && (This->dsound->hwi == 0) ) { - WARN("no driver\n"); - return DSERR_NODRIVER; - } - - EnterCriticalSection(&(This->dsound->lock)); - - This->flags = dwFlags; - TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]); - if (This->dsound->state == STATE_STOPPED) - This->dsound->state = STATE_STARTING; - else if (This->dsound->state == STATE_STOPPING) - This->dsound->state = STATE_CAPTURING; - TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]); - - LeaveCriticalSection(&(This->dsound->lock)); - - if (This->dsound->driver) { - hres = IDsCaptureDriverBuffer_Start(This->dsound->hwbuf, dwFlags); - if (hres != DS_OK) - WARN("IDsCaptureDriverBuffer_Start failed\n"); - } else if (This->dsound->hwi) { - IDirectSoundCaptureImpl* ipDSC = This->dsound; - - if (ipDSC->buffer) { - if (This->nrofnotifies) { - int c; - - ipDSC->nrofpwaves = This->nrofnotifies; - TRACE("nrofnotifies=%d\n", This->nrofnotifies); - - /* prepare headers */ - if (ipDSC->pwave) - ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave, - ipDSC->nrofpwaves*sizeof(WAVEHDR)); - else - ipDSC->pwave = HeapAlloc(GetProcessHeap(),0, - ipDSC->nrofpwaves*sizeof(WAVEHDR)); - - for (c = 0; c < ipDSC->nrofpwaves; c++) { - if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) { - TRACE("got DSBPN_OFFSETSTOP\n"); - ipDSC->nrofpwaves = c; - break; - } - if (c == 0) { - ipDSC->pwave[0].lpData = ipDSC->buffer; - ipDSC->pwave[0].dwBufferLength = - This->notifies[0].dwOffset + 1; - } else { - ipDSC->pwave[c].lpData = ipDSC->buffer + - This->notifies[c-1].dwOffset + 1; - ipDSC->pwave[c].dwBufferLength = - This->notifies[c].dwOffset - - This->notifies[c-1].dwOffset; - } - ipDSC->pwave[c].dwBytesRecorded = 0; - ipDSC->pwave[c].dwUser = (DWORD)ipDSC; - ipDSC->pwave[c].dwFlags = 0; - ipDSC->pwave[c].dwLoops = 0; - hres = mmErr(waveInPrepareHeader(ipDSC->hwi, - &(ipDSC->pwave[c]),sizeof(WAVEHDR))); - if (hres != DS_OK) { - WARN("waveInPrepareHeader failed\n"); - while (c--) - waveInUnprepareHeader(ipDSC->hwi, - &(ipDSC->pwave[c]),sizeof(WAVEHDR)); - break; - } - - hres = mmErr(waveInAddBuffer(ipDSC->hwi, - &(ipDSC->pwave[c]), sizeof(WAVEHDR))); - if (hres != DS_OK) { - WARN("waveInAddBuffer failed\n"); - while (c--) - waveInUnprepareHeader(ipDSC->hwi, - &(ipDSC->pwave[c]),sizeof(WAVEHDR)); - break; - } - } - - memset(ipDSC->buffer, - (ipDSC->pwfx->wBitsPerSample == 8) ? 128 : 0, ipDSC->buflen); - } else { - TRACE("no notifiers specified\n"); - /* no notifiers specified so just create a single default header */ - ipDSC->nrofpwaves = 1; - if (ipDSC->pwave) - ipDSC->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->pwave,sizeof(WAVEHDR)); - else - ipDSC->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR)); - - ipDSC->pwave[0].lpData = ipDSC->buffer; - ipDSC->pwave[0].dwBufferLength = ipDSC->buflen; - ipDSC->pwave[0].dwBytesRecorded = 0; - ipDSC->pwave[0].dwUser = (DWORD)ipDSC; - ipDSC->pwave[0].dwFlags = 0; - ipDSC->pwave[0].dwLoops = 0; - - hres = mmErr(waveInPrepareHeader(ipDSC->hwi, - &(ipDSC->pwave[0]),sizeof(WAVEHDR))); - if (hres != DS_OK) { - WARN("waveInPrepareHeader failed\n"); - waveInUnprepareHeader(ipDSC->hwi, - &(ipDSC->pwave[0]),sizeof(WAVEHDR)); - } - hres = mmErr(waveInAddBuffer(ipDSC->hwi, - &(ipDSC->pwave[0]), sizeof(WAVEHDR))); - if (hres != DS_OK) { - WARN("waveInAddBuffer failed\n"); - waveInUnprepareHeader(ipDSC->hwi, - &(ipDSC->pwave[0]),sizeof(WAVEHDR)); - } - } - } - - ipDSC->index = 0; - ipDSC->read_position = 0; - - if (hres == DS_OK) { - /* start filling the first buffer */ - hres = mmErr(waveInStart(ipDSC->hwi)); - if (hres != DS_OK) - WARN("waveInStart failed\n"); - } - - if (hres != DS_OK) { - WARN("calling waveInClose because of error\n"); - waveInClose(This->dsound->hwi); - This->dsound->hwi = 0; - } - } else { - WARN("no driver\n"); - hres = DSERR_NODRIVER; - } - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) -{ - HRESULT hres = DS_OK; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p)\n", This ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound == NULL) { - WARN("invalid parameter: This->dsound == NULL\n"); - return DSERR_INVALIDPARAM; - } - - EnterCriticalSection(&(This->dsound->lock)); - - TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->state]); - if (This->dsound->state == STATE_CAPTURING) - This->dsound->state = STATE_STOPPING; - else if (This->dsound->state == STATE_STARTING) - This->dsound->state = STATE_STOPPED; - TRACE("new This->dsound->state=%s\n",captureStateString[This->dsound->state]); - - LeaveCriticalSection(&(This->dsound->lock)); - - if (This->dsound->driver) { - hres = IDsCaptureDriverBuffer_Stop(This->dsound->hwbuf); - if (hres != DS_OK) - WARN("IDsCaptureDriverBuffer_Stop() failed\n"); - } else if (This->dsound->hwi) { - hres = mmErr(waveInReset(This->dsound->hwi)); - if (hres != DS_OK) - WARN("waveInReset() failed\n"); - } else { - WARN("no driver\n"); - hres = DSERR_NODRIVER; - } - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_Unlock( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - LPVOID lpvAudioPtr1, - DWORD dwAudioBytes1, - LPVOID lpvAudioPtr2, - DWORD dwAudioBytes2 ) -{ - HRESULT hres = DS_OK; - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, - lpvAudioPtr2, dwAudioBytes2 ); - - if (This == NULL) { - WARN("invalid parameter: This == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpvAudioPtr1 == NULL) { - WARN("invalid parameter: lpvAudioPtr1 == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (This->dsound->driver) { - hres = IDsCaptureDriverBuffer_Unlock(This->dsound->hwbuf, lpvAudioPtr1, - dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); - if (hres != DS_OK) - WARN("IDsCaptureDriverBuffer_Unlock failed\n"); - } else if (This->dsound->hwi) { - This->dsound->read_position = (This->dsound->read_position + - (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->buflen; - } else { - WARN("invalid call\n"); - hres = DSERR_INVALIDCALL; - } - - TRACE("returning %08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetObjectInPath( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - REFGUID rguidObject, - DWORD dwIndex, - REFGUID rguidInterface, - LPVOID* ppObject ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - - FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), - dwIndex, debugstr_guid(rguidInterface), ppObject ); - - return DS_OK; -} - -static HRESULT WINAPI -IDirectSoundCaptureBufferImpl_GetFXStatus( - LPDIRECTSOUNDCAPTUREBUFFER8 iface, - DWORD dwFXCount, - LPDWORD pdwFXStatus ) -{ - IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; - - FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus ); - - return DS_OK; -} - -static IDirectSoundCaptureBuffer8Vtbl dscbvt = -{ - /* IUnknown methods */ - IDirectSoundCaptureBufferImpl_QueryInterface, - IDirectSoundCaptureBufferImpl_AddRef, - IDirectSoundCaptureBufferImpl_Release, - - /* IDirectSoundCaptureBuffer methods */ - IDirectSoundCaptureBufferImpl_GetCaps, - IDirectSoundCaptureBufferImpl_GetCurrentPosition, - IDirectSoundCaptureBufferImpl_GetFormat, - IDirectSoundCaptureBufferImpl_GetStatus, - IDirectSoundCaptureBufferImpl_Initialize, - IDirectSoundCaptureBufferImpl_Lock, - IDirectSoundCaptureBufferImpl_Start, - IDirectSoundCaptureBufferImpl_Stop, - IDirectSoundCaptureBufferImpl_Unlock, - - /* IDirectSoundCaptureBuffer methods */ - IDirectSoundCaptureBufferImpl_GetObjectInPath, - IDirectSoundCaptureBufferImpl_GetFXStatus -}; - -/******************************************************************************* - * DirectSoundCapture ClassFactory - */ - -static HRESULT WINAPI -DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -DSCCF_AddRef(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -DSCCF_Release(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedDecrement(&(This->ref)); -} - -static HRESULT WINAPI -DSCCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - - if (pOuter) { - WARN("aggregation not supported\n"); - return CLASS_E_NOAGGREGATION; - } - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppobj = NULL; - - if ( IsEqualGUID( &IID_IDirectSoundCapture8, riid ) ) - return DirectSoundCaptureCreate8(0,(LPDIRECTSOUNDCAPTURE8*)ppobj,pOuter); - - WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static HRESULT WINAPI -DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl DSCCF_Vtbl = -{ - DSCCF_QueryInterface, - DSCCF_AddRef, - DSCCF_Release, - DSCCF_CreateInstance, - DSCCF_LockServer -}; - -IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 }; - -/*************************************************************************** - * DirectSoundFullDuplexCreate [DSOUND.10] - * - * Create and initialize a DirectSoundFullDuplex interface. - * - * PARAMS - * pcGuidCaptureDevice [I] Address of sound capture device GUID. - * pcGuidRenderDevice [I] Address of sound render device GUID. - * pcDSCBufferDesc [I] Address of capture buffer description. - * pcDSBufferDesc [I] Address of render buffer description. - * hWnd [I] Handle to application window. - * dwLevel [I] Cooperative level. - * ppDSFD [O] Address where full duplex interface returned. - * ppDSCBuffer8 [0] Address where capture buffer interface returned. - * ppDSBuffer8 [0] Address where render buffer interface returned. - * pUnkOuter [I] Must be NULL. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, - * DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER - */ -HRESULT WINAPI -DirectSoundFullDuplexCreate( - LPCGUID pcGuidCaptureDevice, - LPCGUID pcGuidRenderDevice, - LPCDSCBUFFERDESC pcDSCBufferDesc, - LPCDSBUFFERDESC pcDSBufferDesc, - HWND hWnd, - DWORD dwLevel, - LPDIRECTSOUNDFULLDUPLEX *ppDSFD, - LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, - LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, - LPUNKNOWN pUnkOuter) -{ - IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD; - TRACE("(%s,%s,%p,%p,%lx,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), - debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc, - (DWORD)hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter); - - if ( pUnkOuter ) { - WARN("pUnkOuter != 0\n"); - return DSERR_NOAGGREGATION; - } - - *ippDSFD = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl)); - - if (*ippDSFD == NULL) { - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } else { - HRESULT hres; - IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD; - - This->ref = 1; - This->lpVtbl = &dsfdvt; - - InitializeCriticalSection( &(This->lock) ); - This->lock.DebugInfo->Spare[1] = (DWORD)"DSDUPLEX_lock"; - - hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This, - pcGuidCaptureDevice, pcGuidRenderDevice, - pcDSCBufferDesc, pcDSBufferDesc, - hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8); - if (hres != DS_OK) - WARN("IDirectSoundFullDuplexImpl_Initialize failed\n"); - return hres; - } - - return DSERR_GENERIC; -} - -static HRESULT WINAPI -IDirectSoundFullDuplexImpl_QueryInterface( - LPDIRECTSOUNDFULLDUPLEX iface, - REFIID riid, - LPVOID* ppobj ) -{ - IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; - TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppobj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI -IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface ) -{ - IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface ) -{ - ULONG uRef; - IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - - uRef = InterlockedDecrement(&(This->ref)); - if ( uRef == 0 ) { - This->lock.DebugInfo->Spare[1] = 0; - DeleteCriticalSection( &(This->lock) ); - HeapFree( GetProcessHeap(), 0, This ); - TRACE("(%p) released\n",This); - } - - return uRef; -} - -static HRESULT WINAPI -IDirectSoundFullDuplexImpl_Initialize( - LPDIRECTSOUNDFULLDUPLEX iface, - LPCGUID pCaptureGuid, - LPCGUID pRendererGuid, - LPCDSCBUFFERDESC lpDscBufferDesc, - LPCDSBUFFERDESC lpDsBufferDesc, - HWND hWnd, - DWORD dwLevel, - LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, - LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 ) -{ - IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; - IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8; - IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8; - - FIXME( "(%p,%s,%s,%p,%p,%lx,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid), - debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, (DWORD)hWnd, dwLevel, - ippdscb, ippdsc); - - return E_FAIL; -} - -static IDirectSoundFullDuplexVtbl dsfdvt = -{ - /* IUnknown methods */ - IDirectSoundFullDuplexImpl_QueryInterface, - IDirectSoundFullDuplexImpl_AddRef, - IDirectSoundFullDuplexImpl_Release, - - /* IDirectSoundFullDuplex methods */ - IDirectSoundFullDuplexImpl_Initialize -}; - -/******************************************************************************* - * DirectSoundFullDuplex ClassFactory - */ - -static HRESULT WINAPI -DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -DSFDCF_AddRef(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -DSFDCF_Release(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedDecrement(&(This->ref)); -} - -static HRESULT WINAPI -DSFDCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - - if (pOuter) { - WARN("aggregation not supported\n"); - return CLASS_E_NOAGGREGATION; - } - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppobj = NULL; - - if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) { - /* FIXME: how do we do this one ? */ - FIXME("not implemented\n"); - return E_NOINTERFACE; - } - - WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static HRESULT WINAPI -DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl DSFDCF_Vtbl = -{ - DSFDCF_QueryInterface, - DSFDCF_AddRef, - DSFDCF_Release, - DSFDCF_CreateInstance, - DSFDCF_LockServer -}; - -IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 }; +/* DirectSoundCapture + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Rob Riggs + * Copyright 2000-2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * TODO: + * Implement FX support. + * Implement both IDirectSoundCaptureBuffer and IDirectSoundCaptureBuffer8 + * Make DirectSoundCaptureCreate and DirectSoundCaptureCreate8 behave differently + */ + +#include + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "mmddk.h" +#include "winreg.h" +#include "winternl.h" +#include "winnls.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +static HRESULT WINAPI IDirectSoundCaptureImpl_Initialize( + LPDIRECTSOUNDCAPTURE iface, + LPCGUID lpcGUID ); +static ULONG WINAPI IDirectSoundCaptureImpl_Release( + LPDIRECTSOUNDCAPTURE iface ); +static ULONG WINAPI IDirectSoundCaptureBufferImpl_Release( + LPDIRECTSOUNDCAPTUREBUFFER8 iface ); +static HRESULT DSOUND_CreateDirectSoundCaptureBuffer( + IDirectSoundCaptureImpl *ipDSC, + LPCDSCBUFFERDESC lpcDSCBufferDesc, + LPVOID* ppobj ); + +static const IDirectSoundCaptureVtbl dscvt; +static const IDirectSoundCaptureBuffer8Vtbl dscbvt; + +DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS]; + +static const char * captureStateString[] = { + "STATE_STOPPED", + "STATE_STARTING", + "STATE_CAPTURING", + "STATE_STOPPING" +}; + +HRESULT WINAPI IDirectSoundCaptureImpl_Create( + LPDIRECTSOUNDCAPTURE8 * ppDSC) +{ + IDirectSoundCaptureImpl *pDSC; + TRACE("(%p)\n", ppDSC); + + /* Allocate memory */ + pDSC = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(IDirectSoundCaptureImpl)); + if (pDSC == NULL) { + WARN("out of memory\n"); + *ppDSC = NULL; + return DSERR_OUTOFMEMORY; + } + + pDSC->lpVtbl = &dscvt; + pDSC->ref = 0; + pDSC->device = NULL; + + *ppDSC = (LPDIRECTSOUNDCAPTURE8)pDSC; + + return DS_OK; +} + +HRESULT WINAPI DSOUND_CaptureCreate( + LPDIRECTSOUNDCAPTURE *ppDSC, + IUnknown *pUnkOuter) +{ + LPDIRECTSOUNDCAPTURE pDSC; + HRESULT hr; + TRACE("(%p,%p)\n",ppDSC,pUnkOuter); + + /* Get dsound configuration */ + setup_dsound_options(); + + hr = IDirectSoundCaptureImpl_Create(&pDSC); + if (hr == DS_OK) { + IDirectSoundCapture_AddRef(pDSC); + *ppDSC = pDSC; + } else { + WARN("IDirectSoundCaptureImpl_Create failed\n"); + *ppDSC = 0; + } + + return hr; +} + +HRESULT WINAPI DSOUND_CaptureCreate8( + LPDIRECTSOUNDCAPTURE8 *ppDSC8, + IUnknown *pUnkOuter) +{ + LPDIRECTSOUNDCAPTURE8 pDSC8; + HRESULT hr; + TRACE("(%p,%p)\n",ppDSC8,pUnkOuter); + + /* Get dsound configuration */ + setup_dsound_options(); + + hr = IDirectSoundCaptureImpl_Create(&pDSC8); + if (hr == DS_OK) { + IDirectSoundCapture_AddRef(pDSC8); + *ppDSC8 = pDSC8; + } else { + WARN("IDirectSoundCaptureImpl_Create failed\n"); + *ppDSC8 = 0; + } + + return hr; +} + +/*************************************************************************** + * DirectSoundCaptureCreate [DSOUND.6] + * + * Create and initialize a DirectSoundCapture interface. + * + * PARAMS + * lpcGUID [I] Address of the GUID that identifies the sound capture device. + * lplpDSC [O] Address of a variable to receive the interface pointer. + * pUnkOuter [I] Must be NULL. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, + * DSERR_OUTOFMEMORY + * + * NOTES + * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate + * or NULL for the default device or DSDEVID_DefaultCapture or + * DSDEVID_DefaultVoiceCapture. + * + * DSERR_ALLOCATED is returned for sound devices that do not support full duplex. + */ +HRESULT WINAPI DirectSoundCaptureCreate( + LPCGUID lpcGUID, + LPDIRECTSOUNDCAPTURE *ppDSC, + LPUNKNOWN pUnkOuter) +{ + HRESULT hr; + LPDIRECTSOUNDCAPTURE pDSC; + TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC, pUnkOuter); + + if (ppDSC == NULL) { + WARN("invalid parameter: ppDSC == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (pUnkOuter) { + WARN("invalid parameter: pUnkOuter != NULL\n"); + *ppDSC = NULL; + return DSERR_NOAGGREGATION; + } + + hr = DSOUND_CaptureCreate(&pDSC, (IUnknown *)pUnkOuter); + if (hr == DS_OK) { + hr = IDirectSoundCapture_Initialize(pDSC, lpcGUID); + if (hr != DS_OK) { + IDirectSoundCapture_Release(pDSC); + pDSC = 0; + } + } + + *ppDSC = pDSC; + + return hr; +} + +/*************************************************************************** + * DirectSoundCaptureCreate8 [DSOUND.12] + * + * Create and initialize a DirectSoundCapture interface. + * + * PARAMS + * lpcGUID [I] Address of the GUID that identifies the sound capture device. + * lplpDSC [O] Address of a variable to receive the interface pointer. + * pUnkOuter [I] Must be NULL. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, + * DSERR_OUTOFMEMORY + * + * NOTES + * lpcGUID must be one of the values returned from DirectSoundCaptureEnumerate + * or NULL for the default device or DSDEVID_DefaultCapture or + * DSDEVID_DefaultVoiceCapture. + * + * DSERR_ALLOCATED is returned for sound devices that do not support full duplex. + */ +HRESULT WINAPI DirectSoundCaptureCreate8( + LPCGUID lpcGUID, + LPDIRECTSOUNDCAPTURE8 *ppDSC8, + LPUNKNOWN pUnkOuter) +{ + HRESULT hr; + LPDIRECTSOUNDCAPTURE8 pDSC8; + TRACE("(%s,%p,%p)\n", debugstr_guid(lpcGUID), ppDSC8, pUnkOuter); + + if (ppDSC8 == NULL) { + WARN("invalid parameter: ppDSC8 == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (pUnkOuter) { + WARN("invalid parameter: pUnkOuter != NULL\n"); + *ppDSC8 = NULL; + return DSERR_NOAGGREGATION; + } + + hr = DSOUND_CaptureCreate8(&pDSC8, (IUnknown *)pUnkOuter); + if (hr == DS_OK) { + hr = IDirectSoundCapture_Initialize(pDSC8, lpcGUID); + if (hr != DS_OK) { + IDirectSoundCapture_Release(pDSC8); + pDSC8 = 0; + } + } + + *ppDSC8 = pDSC8; + + return hr; +} + +static HRESULT DirectSoundCaptureDevice_Create( + DirectSoundCaptureDevice ** ppDevice) +{ + DirectSoundCaptureDevice * device; + TRACE("(%p)\n", ppDevice); + + /* Allocate memory */ + device = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DirectSoundCaptureDevice)); + + if (device == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + + device->ref = 1; + device->state = STATE_STOPPED; + + InitializeCriticalSection( &(device->lock) ); + device->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSCAPTURE_lock"; + + *ppDevice = device; + + return DS_OK; +} + +/*************************************************************************** + * DirectSoundCaptureEnumerateA [DSOUND.7] + * + * Enumerate all DirectSound drivers installed in the system. + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI +DirectSoundCaptureEnumerateA( + LPDSENUMCALLBACKA lpDSEnumCallback, + LPVOID lpContext) +{ + unsigned devs, wid; + DSDRIVERDESC desc; + GUID guid; + int err; + + TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + devs = waveInGetNumDevs(); + if (devs > 0) { + if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { + for (wid = 0; wid < devs; ++wid) { + if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", + "Primary Sound Capture Driver",desc.szDrvname,lpContext); + if (lpDSEnumCallback(NULL, "Primary Sound Capture Driver", desc.szDrvname, lpContext) == FALSE) + return DS_OK; + } + } + } + } + } + + for (wid = 0; wid < devs; ++wid) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", + debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); + if (lpDSEnumCallback(&DSOUND_capture_guids[wid], desc.szDesc, desc.szDrvname, lpContext) == FALSE) + return DS_OK; + } + } + + return DS_OK; +} + +/*************************************************************************** + * DirectSoundCaptureEnumerateW [DSOUND.8] + * + * Enumerate all DirectSound drivers installed in the system. + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI +DirectSoundCaptureEnumerateW( + LPDSENUMCALLBACKW lpDSEnumCallback, + LPVOID lpContext) +{ + unsigned devs, wid; + DSDRIVERDESC desc; + GUID guid; + int err; + WCHAR wDesc[MAXPNAMELEN]; + WCHAR wName[MAXPNAMELEN]; + + TRACE("(%p,%p)\n", lpDSEnumCallback, lpContext ); + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + devs = waveInGetNumDevs(); + if (devs > 0) { + if (GetDeviceID(&DSDEVID_DefaultCapture, &guid) == DS_OK) { + for (wid = 0; wid < devs; ++wid) { + if (IsEqualGUID( &guid, &DSOUND_capture_guids[wid] ) ) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", + "Primary Sound Capture Driver",desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, "Primary Sound Capture Driver", -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) + return DS_OK; + } + } + } + } + } + + for (wid = 0; wid < devs; ++wid) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", + debugstr_guid(&DSOUND_capture_guids[wid]),desc.szDesc,desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback((LPGUID)&DSOUND_capture_guids[wid], wDesc, wName, lpContext) == FALSE) + return DS_OK; + } + } + + return DS_OK; +} + +static void CALLBACK +DSOUND_capture_callback( + HWAVEIN hwi, + UINT msg, + DWORD dwUser, + DWORD dw1, + DWORD dw2 ) +{ + DirectSoundCaptureDevice * This = (DirectSoundCaptureDevice*)dwUser; + TRACE("(%p,%08x(%s),%08lx,%08lx,%08lx) entering at %ld\n",hwi,msg, + msg == MM_WIM_OPEN ? "MM_WIM_OPEN" : msg == MM_WIM_CLOSE ? "MM_WIM_CLOSE" : + msg == MM_WIM_DATA ? "MM_WIM_DATA" : "UNKNOWN",dwUser,dw1,dw2,GetTickCount()); + + if (msg == MM_WIM_DATA) { + LPWAVEHDR pHdr = (LPWAVEHDR)dw1; + EnterCriticalSection( &(This->lock) ); + TRACE("DirectSoundCapture msg=MM_WIM_DATA, old This->state=%s, old This->index=%d\n", + captureStateString[This->state],This->index); + if (This->state != STATE_STOPPED) { + int index = This->index; + if (This->state == STATE_STARTING) { + This->read_position = pHdr->dwBytesRecorded; + This->state = STATE_CAPTURING; + } + if (This->capture_buffer->nrofnotifies) + SetEvent(This->capture_buffer->notifies[This->index].hEventNotify); + This->index = (This->index + 1) % This->nrofpwaves; + if ( (This->index == 0) && !(This->capture_buffer->flags & DSCBSTART_LOOPING) ) { + TRACE("end of buffer\n"); + This->state = STATE_STOPPED; + } else { + if (This->state == STATE_CAPTURING) { + waveInAddBuffer(hwi, &(This->pwave[index]), sizeof(WAVEHDR)); + } else if (This->state == STATE_STOPPING) { + TRACE("stopping\n"); + This->state = STATE_STOPPED; + } + } + } + TRACE("DirectSoundCapture new This->state=%s, new This->index=%d\n", + captureStateString[This->state],This->index); + LeaveCriticalSection( &(This->lock) ); + } + + TRACE("completed\n"); +} + +static HRESULT WINAPI +IDirectSoundCaptureImpl_QueryInterface( + LPDIRECTSOUNDCAPTURE iface, + REFIID riid, + LPVOID* ppobj ) +{ + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppobj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) { + IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This); + *ppobj = This; + return DS_OK; + } else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) { + IDirectSoundCapture_AddRef((LPDIRECTSOUNDCAPTURE)This); + *ppobj = This; + return DS_OK; + } + + WARN("unsupported riid: %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +IDirectSoundCaptureImpl_AddRef( LPDIRECTSOUNDCAPTURE iface ) +{ + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG DirectSoundCaptureDevice_Release( + DirectSoundCaptureDevice * device) +{ + ULONG ref; + TRACE("(%p) ref was %lu\n", device, device->ref); + + device->ref--; + ref=device->ref; + if (device->ref == 0) { + TRACE("deleting object\n"); + if (device->capture_buffer) + IDirectSoundCaptureBufferImpl_Release( + (LPDIRECTSOUNDCAPTUREBUFFER8) device->capture_buffer); + + if (device->driver) { + IDsCaptureDriver_Close(device->driver); + IDsCaptureDriver_Release(device->driver); + } + + HeapFree(GetProcessHeap(), 0, device->pwfx); + device->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &(device->lock) ); + DSOUND_capture[device->drvdesc.dnDevNode] = NULL; + HeapFree(GetProcessHeap(), 0, device); + TRACE("(%p) released\n", device); + } + return ref; +} + +static ULONG WINAPI +IDirectSoundCaptureImpl_Release( LPDIRECTSOUNDCAPTURE iface ) +{ + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + if (This->device) + DirectSoundCaptureDevice_Release(This->device); + + HeapFree( GetProcessHeap(), 0, This ); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI +IDirectSoundCaptureImpl_CreateCaptureBuffer( + LPDIRECTSOUNDCAPTURE iface, + LPCDSCBUFFERDESC lpcDSCBufferDesc, + LPDIRECTSOUNDCAPTUREBUFFER* lplpDSCaptureBuffer, + LPUNKNOWN pUnk ) +{ + HRESULT hr; + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + + TRACE( "(%p,%p,%p,%p)\n",iface,lpcDSCBufferDesc,lplpDSCaptureBuffer,pUnk); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpcDSCBufferDesc == NULL) { + WARN("invalid parameter: lpcDSCBufferDesc == NULL)\n"); + return DSERR_INVALIDPARAM; + } + + if (lplpDSCaptureBuffer == NULL) { + WARN("invalid parameter: lplpDSCaptureBuffer == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (pUnk != NULL) { + WARN("invalid parameter: pUnk != NULL\n"); + return DSERR_INVALIDPARAM; + } + + /* FIXME: We can only have one buffer so what do we do here? */ + if (This->device->capture_buffer) { + WARN("lnvalid parameter: already has buffer\n"); + return DSERR_INVALIDPARAM; /* DSERR_GENERIC ? */ + } + + hr = DSOUND_CreateDirectSoundCaptureBuffer(This, lpcDSCBufferDesc, + (LPVOID*)lplpDSCaptureBuffer ); + + if (hr != DS_OK) + WARN("DSOUND_CreateDirectSoundCaptureBuffer failed\n"); + + return hr; +} + +static HRESULT WINAPI +IDirectSoundCaptureImpl_GetCaps( + LPDIRECTSOUNDCAPTURE iface, + LPDSCCAPS lpDSCCaps ) +{ + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + TRACE("(%p,%p)\n",This,lpDSCCaps); + + if (This->device == NULL) { + WARN("not initialized\n"); + return DSERR_UNINITIALIZED; + } + + if (lpDSCCaps== NULL) { + WARN("invalid parameter: lpDSCCaps== NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpDSCCaps->dwSize < sizeof(*lpDSCCaps)) { + WARN("invalid parameter: lpDSCCaps->dwSize = %ld < %d\n", + lpDSCCaps->dwSize, sizeof(*lpDSCCaps)); + return DSERR_INVALIDPARAM; + } + + lpDSCCaps->dwFlags = This->device->drvcaps.dwFlags; + lpDSCCaps->dwFormats = This->device->drvcaps.dwFormats; + lpDSCCaps->dwChannels = This->device->drvcaps.dwChannels; + + TRACE("(flags=0x%08lx,format=0x%08lx,channels=%ld)\n",lpDSCCaps->dwFlags, + lpDSCCaps->dwFormats, lpDSCCaps->dwChannels); + + return DS_OK; +} + +static HRESULT WINAPI +IDirectSoundCaptureImpl_Initialize( + LPDIRECTSOUNDCAPTURE iface, + LPCGUID lpcGUID ) +{ + HRESULT err = DSERR_INVALIDPARAM; + unsigned wid, widn; + BOOLEAN found = FALSE; + GUID devGUID; + IDirectSoundCaptureImpl *This = (IDirectSoundCaptureImpl *)iface; + DirectSoundCaptureDevice *device = This->device; + TRACE("(%p)\n", This); + + if (!This) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (device != NULL) { + WARN("already initialized\n"); + return DSERR_ALREADYINITIALIZED; + } + + /* Default device? */ + if ( !lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL) ) + lpcGUID = &DSDEVID_DefaultCapture; + + if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) { + WARN("invalid parameter: lpcGUID\n"); + return DSERR_INVALIDPARAM; + } + + widn = waveInGetNumDevs(); + if (!widn) { + WARN("no audio devices found\n"); + return DSERR_NODRIVER; + } + + /* enumerate WINMM audio devices and find the one we want */ + for (wid=0; widdevice = device; + device->guid = devGUID; + + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&(This->device->driver),0)); + if ( (err != DS_OK) && (err != DSERR_UNSUPPORTED) ) { + WARN("WineWaveInMessage failed; err=%lx\n",err); + return err; + } + err = DS_OK; + + /* Disable the direct sound driver to force emulation if requested. */ + if (ds_hw_accel == DS_HW_ACCEL_EMULATION) + This->device->driver = NULL; + + /* Get driver description */ + if (This->device->driver) { + TRACE("using DirectSound driver\n"); + err = IDsCaptureDriver_GetDriverDesc(This->device->driver, &(This->device->drvdesc)); + if (err != DS_OK) { + WARN("IDsCaptureDriver_GetDriverDesc failed\n"); + return err; + } + } else { + TRACE("using WINMM\n"); + /* if no DirectSound interface available, use WINMM API instead */ + This->device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | + DSDDESC_DOMMSYSTEMSETFORMAT; + } + + This->device->drvdesc.dnDevNode = wid; + + /* open the DirectSound driver if available */ + if (This->device->driver && (err == DS_OK)) + err = IDsCaptureDriver_Open(This->device->driver); + + if (err == DS_OK) { + This->device = device; + + /* the driver is now open, so it's now allowed to call GetCaps */ + if (This->device->driver) { + This->device->drvcaps.dwSize = sizeof(This->device->drvcaps); + err = IDsCaptureDriver_GetCaps(This->device->driver,&(This->device->drvcaps)); + if (err != DS_OK) { + WARN("IDsCaptureDriver_GetCaps failed\n"); + return err; + } + } else /*if (This->hwi)*/ { + WAVEINCAPSA wic; + err = mmErr(waveInGetDevCapsA((UINT)This->device->drvdesc.dnDevNode, &wic, sizeof(wic))); + + if (err == DS_OK) { + This->device->drvcaps.dwFlags = 0; + lstrcpynA(This->device->drvdesc.szDrvname, wic.szPname, + sizeof(This->device->drvdesc.szDrvname)); + + This->device->drvcaps.dwFlags |= DSCCAPS_EMULDRIVER; + This->device->drvcaps.dwFormats = wic.dwFormats; + This->device->drvcaps.dwChannels = wic.wChannels; + } + } + } + + return err; +} + +static const IDirectSoundCaptureVtbl dscvt = +{ + /* IUnknown methods */ + IDirectSoundCaptureImpl_QueryInterface, + IDirectSoundCaptureImpl_AddRef, + IDirectSoundCaptureImpl_Release, + + /* IDirectSoundCapture methods */ + IDirectSoundCaptureImpl_CreateCaptureBuffer, + IDirectSoundCaptureImpl_GetCaps, + IDirectSoundCaptureImpl_Initialize +}; + +static HRESULT +DSOUND_CreateDirectSoundCaptureBuffer( + IDirectSoundCaptureImpl *ipDSC, + LPCDSCBUFFERDESC lpcDSCBufferDesc, + LPVOID* ppobj ) +{ + LPWAVEFORMATEX wfex; + TRACE( "(%p,%p)\n", lpcDSCBufferDesc, ppobj ); + + if (ipDSC == NULL) { + WARN("invalid parameter: ipDSC == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpcDSCBufferDesc == NULL) { + WARN("invalid parameter: lpcDSCBufferDesc == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (ppobj == NULL) { + WARN("invalid parameter: ppobj == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if ( ((lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC)) && + (lpcDSCBufferDesc->dwSize != sizeof(DSCBUFFERDESC1))) || + (lpcDSCBufferDesc->dwBufferBytes == 0) || + (lpcDSCBufferDesc->lpwfxFormat == NULL) ) { + WARN("invalid lpcDSCBufferDesc\n"); + *ppobj = NULL; + return DSERR_INVALIDPARAM; + } + + if ( !ipDSC->device) { + WARN("not initialized\n"); + *ppobj = NULL; + return DSERR_UNINITIALIZED; + } + + wfex = lpcDSCBufferDesc->lpwfxFormat; + + if (wfex) { + TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," + "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", + wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, + wfex->nAvgBytesPerSec, wfex->nBlockAlign, + wfex->wBitsPerSample, wfex->cbSize); + + if (wfex->wFormatTag == WAVE_FORMAT_PCM) { + ipDSC->device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)); + CopyMemory(ipDSC->device->pwfx, wfex, sizeof(WAVEFORMATEX)); + ipDSC->device->pwfx->cbSize = 0; + } else { + ipDSC->device->pwfx = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEFORMATEX)+wfex->cbSize); + CopyMemory(ipDSC->device->pwfx, wfex, sizeof(WAVEFORMATEX)+wfex->cbSize); + } + } else { + WARN("lpcDSCBufferDesc->lpwfxFormat == 0\n"); + *ppobj = NULL; + return DSERR_INVALIDPARAM; /* FIXME: DSERR_BADFORMAT ? */ + } + + *ppobj = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + sizeof(IDirectSoundCaptureBufferImpl)); + + if ( *ppobj == NULL ) { + WARN("out of memory\n"); + *ppobj = NULL; + return DSERR_OUTOFMEMORY; + } else { + HRESULT err = DS_OK; + LPBYTE newbuf; + DWORD buflen; + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)*ppobj; + + This->ref = 1; + This->dsound = ipDSC; + This->dsound->device->capture_buffer = This; + This->notify = NULL; + This->nrofnotifies = 0; + This->hwnotify = NULL; + + This->pdscbd = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + lpcDSCBufferDesc->dwSize); + if (This->pdscbd) + CopyMemory(This->pdscbd, lpcDSCBufferDesc, lpcDSCBufferDesc->dwSize); + else { + WARN("no memory\n"); + This->dsound->device->capture_buffer = 0; + HeapFree( GetProcessHeap(), 0, This ); + *ppobj = NULL; + return DSERR_OUTOFMEMORY; + } + + This->lpVtbl = &dscbvt; + + if (ipDSC->device->driver) { + if (This->dsound->device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) + FIXME("DSDDESC_DOMMSYSTEMOPEN not supported\n"); + + if (This->dsound->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { + /* allocate buffer from system memory */ + buflen = lpcDSCBufferDesc->dwBufferBytes; + TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->device->buffer); + if (ipDSC->device->buffer) + newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->buffer,buflen); + else + newbuf = HeapAlloc(GetProcessHeap(),0,buflen); + + if (newbuf == NULL) { + WARN("failed to allocate capture buffer\n"); + err = DSERR_OUTOFMEMORY; + /* but the old buffer might still exist and must be re-prepared */ + } else { + ipDSC->device->buffer = newbuf; + ipDSC->device->buflen = buflen; + } + } else { + /* let driver allocate memory */ + ipDSC->device->buflen = lpcDSCBufferDesc->dwBufferBytes; + /* FIXME: */ + HeapFree( GetProcessHeap(), 0, ipDSC->device->buffer); + ipDSC->device->buffer = NULL; + } + + err = IDsCaptureDriver_CreateCaptureBuffer(ipDSC->device->driver, + ipDSC->device->pwfx,0,0,&(ipDSC->device->buflen),&(ipDSC->device->buffer),(LPVOID*)&(ipDSC->device->hwbuf)); + if (err != DS_OK) { + WARN("IDsCaptureDriver_CreateCaptureBuffer failed\n"); + This->dsound->device->capture_buffer = 0; + HeapFree( GetProcessHeap(), 0, This ); + *ppobj = NULL; + return err; + } + } else { + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; + err = mmErr(waveInOpen(&(ipDSC->device->hwi), + ipDSC->device->drvdesc.dnDevNode, ipDSC->device->pwfx, + (DWORD_PTR)DSOUND_capture_callback, (DWORD)ipDSC->device, flags)); + if (err != DS_OK) { + WARN("waveInOpen failed\n"); + This->dsound->device->capture_buffer = 0; + HeapFree( GetProcessHeap(), 0, This ); + *ppobj = NULL; + return err; + } + + buflen = lpcDSCBufferDesc->dwBufferBytes; + TRACE("desired buflen=%ld, old buffer=%p\n", buflen, ipDSC->device->buffer); + if (ipDSC->device->buffer) + newbuf = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->buffer,buflen); + else + newbuf = HeapAlloc(GetProcessHeap(),0,buflen); + if (newbuf == NULL) { + WARN("failed to allocate capture buffer\n"); + err = DSERR_OUTOFMEMORY; + /* but the old buffer might still exist and must be re-prepared */ + } else { + ipDSC->device->buffer = newbuf; + ipDSC->device->buflen = buflen; + } + } + } + + TRACE("returning DS_OK\n"); + return DS_OK; +} + +/******************************************************************************* + * IDirectSoundCaptureNotify + */ +static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_QueryInterface( + LPDIRECTSOUNDNOTIFY iface, + REFIID riid, + LPVOID *ppobj) +{ + IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + + if (This->dscb == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + return IDirectSoundCaptureBuffer_QueryInterface((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb, riid, ppobj); +} + +static ULONG WINAPI IDirectSoundCaptureNotifyImpl_AddRef(LPDIRECTSOUNDNOTIFY iface) +{ + IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectSoundCaptureNotifyImpl_Release(LPDIRECTSOUNDNOTIFY iface) +{ + IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + if (This->dscb->hwnotify) + IDsDriverNotify_Release(This->dscb->hwnotify); + This->dscb->notify=NULL; + IDirectSoundCaptureBuffer_Release((LPDIRECTSOUNDCAPTUREBUFFER)This->dscb); + HeapFree(GetProcessHeap(),0,This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI IDirectSoundCaptureNotifyImpl_SetNotificationPositions( + LPDIRECTSOUNDNOTIFY iface, + DWORD howmuch, + LPCDSBPOSITIONNOTIFY notify) +{ + IDirectSoundCaptureNotifyImpl *This = (IDirectSoundCaptureNotifyImpl *)iface; + TRACE("(%p,0x%08lx,%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;idscb->hwnotify) { + HRESULT hres; + hres = IDsDriverNotify_SetNotificationPositions(This->dscb->hwnotify, howmuch, notify); + if (hres != DS_OK) + WARN("IDsDriverNotify_SetNotificationPositions failed\n"); + return hres; + } else if (howmuch > 0) { + /* Make an internal copy of the caller-supplied array. + * Replace the existing copy if one is already present. */ + if (This->dscb->notifies) + This->dscb->notifies = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->dscb->notifies, howmuch * sizeof(DSBPOSITIONNOTIFY)); + else + This->dscb->notifies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + howmuch * sizeof(DSBPOSITIONNOTIFY)); + + if (This->dscb->notifies == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + CopyMemory(This->dscb->notifies, notify, howmuch * sizeof(DSBPOSITIONNOTIFY)); + This->dscb->nrofnotifies = howmuch; + } else { + HeapFree(GetProcessHeap(), 0, This->dscb->notifies); + This->dscb->notifies = NULL; + This->dscb->nrofnotifies = 0; + } + + return S_OK; +} + +static const IDirectSoundNotifyVtbl dscnvt = +{ + IDirectSoundCaptureNotifyImpl_QueryInterface, + IDirectSoundCaptureNotifyImpl_AddRef, + IDirectSoundCaptureNotifyImpl_Release, + IDirectSoundCaptureNotifyImpl_SetNotificationPositions, +}; + +HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create( + IDirectSoundCaptureBufferImpl *dscb, + IDirectSoundCaptureNotifyImpl **pdscn) +{ + IDirectSoundCaptureNotifyImpl * dscn; + TRACE("(%p,%p)\n",dscb,pdscn); + + dscn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(dscn)); + + if (dscn == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + + dscn->ref = 0; + dscn->lpVtbl = &dscnvt; + dscn->dscb = dscb; + dscb->notify = dscn; + IDirectSoundCaptureBuffer_AddRef((LPDIRECTSOUNDCAPTUREBUFFER)dscb); + + *pdscn = dscn; + return DS_OK; +} + +/******************************************************************************* + * IDirectSoundCaptureBuffer + */ +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_QueryInterface( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + REFIID riid, + LPVOID* ppobj ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + HRESULT hres; + TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppobj = NULL; + + if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { + if (!This->notify) + hres = IDirectSoundCaptureNotifyImpl_Create(This, &This->notify); + if (This->notify) { + if (This->dsound->device->hwbuf) { + hres = IDsCaptureDriverBuffer_QueryInterface(This->dsound->device->hwbuf, + &IID_IDsDriverNotify, (LPVOID*)&(This->hwnotify)); + if (hres != DS_OK) { + WARN("IDsCaptureDriverBuffer_QueryInterface failed\n"); + *ppobj = 0; + return hres; + } + } + + IDirectSoundNotify_AddRef((LPDIRECTSOUNDNOTIFY)This->notify); + *ppobj = (LPVOID)This->notify; + return DS_OK; + } + + WARN("IID_IDirectSoundNotify\n"); + return E_FAIL; + } + + if ( IsEqualGUID( &IID_IDirectSoundCaptureBuffer, riid ) || + IsEqualGUID( &IID_IDirectSoundCaptureBuffer8, riid ) ) { + IDirectSoundCaptureBuffer8_AddRef(iface); + *ppobj = This; + return NO_ERROR; + } + + FIXME("(%p,%s,%p) unsupported GUID\n", This, debugstr_guid(riid), ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI +IDirectSoundCaptureBufferImpl_AddRef( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI +IDirectSoundCaptureBufferImpl_Release( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + TRACE("deleting object\n"); + if (This->dsound->device->state == STATE_CAPTURING) + This->dsound->device->state = STATE_STOPPING; + + HeapFree(GetProcessHeap(),0, This->pdscbd); + + if (This->dsound->device->hwi) { + waveInReset(This->dsound->device->hwi); + waveInClose(This->dsound->device->hwi); + HeapFree(GetProcessHeap(),0, This->dsound->device->pwave); + This->dsound->device->pwave = 0; + This->dsound->device->hwi = 0; + } + + if (This->dsound->device->hwbuf) + IDsCaptureDriverBuffer_Release(This->dsound->device->hwbuf); + + /* remove from IDirectSoundCaptureImpl */ + if (This->dsound) + This->dsound->device->capture_buffer = NULL; + else + ERR("does not reference dsound\n"); + + if (This->notify) + IDirectSoundNotify_Release((LPDIRECTSOUNDNOTIFY)This->notify); + + HeapFree(GetProcessHeap(), 0, This->notifies); + HeapFree( GetProcessHeap(), 0, This ); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetCaps( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPDSCBCAPS lpDSCBCaps ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p,%p)\n", This, lpDSCBCaps ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpDSCBCaps == NULL) { + WARN("invalid parameter: lpDSCBCaps == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpDSCBCaps->dwSize < sizeof(DSCBCAPS)) { + WARN("invalid parameter: lpDSCBCaps->dwSize = %ld < %d\n", + lpDSCBCaps->dwSize, sizeof(DSCBCAPS)); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + lpDSCBCaps->dwSize = sizeof(DSCBCAPS); + lpDSCBCaps->dwFlags = This->flags; + lpDSCBCaps->dwBufferBytes = This->pdscbd->dwBufferBytes; + lpDSCBCaps->dwReserved = 0; + + TRACE("returning DS_OK\n"); + return DS_OK; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetCurrentPosition( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPDWORD lpdwCapturePosition, + LPDWORD lpdwReadPosition ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + HRESULT hres = DS_OK; + TRACE( "(%p,%p,%p)\n", This, lpdwCapturePosition, lpdwReadPosition ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound->device->driver) { + hres = IDsCaptureDriverBuffer_GetPosition(This->dsound->device->hwbuf, lpdwCapturePosition, lpdwReadPosition ); + if (hres != DS_OK) + WARN("IDsCaptureDriverBuffer_GetPosition failed\n"); + } else if (This->dsound->device->hwi) { + EnterCriticalSection(&(This->dsound->device->lock)); + TRACE("old This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]); + if (lpdwCapturePosition) { + MMTIME mtime; + mtime.wType = TIME_BYTES; + waveInGetPosition(This->dsound->device->hwi, &mtime, sizeof(mtime)); + TRACE("mtime.u.cb=%ld,This->dsound->device->buflen=%ld\n", mtime.u.cb, + This->dsound->device->buflen); + mtime.u.cb = mtime.u.cb % This->dsound->device->buflen; + *lpdwCapturePosition = mtime.u.cb; + } + + if (lpdwReadPosition) { + if (This->dsound->device->state == STATE_STARTING) { + if (lpdwCapturePosition) + This->dsound->device->read_position = *lpdwCapturePosition; + This->dsound->device->state = STATE_CAPTURING; + } + *lpdwReadPosition = This->dsound->device->read_position; + } + TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]); + LeaveCriticalSection(&(This->dsound->device->lock)); + if (lpdwCapturePosition) TRACE("*lpdwCapturePosition=%ld\n",*lpdwCapturePosition); + if (lpdwReadPosition) TRACE("*lpdwReadPosition=%ld\n",*lpdwReadPosition); + } else { + WARN("no driver\n"); + hres = DSERR_NODRIVER; + } + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetFormat( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPWAVEFORMATEX lpwfxFormat, + DWORD dwSizeAllocated, + LPDWORD lpdwSizeWritten ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + HRESULT hres = DS_OK; + TRACE( "(%p,%p,0x%08lx,%p)\n", This, lpwfxFormat, dwSizeAllocated, + lpdwSizeWritten ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (dwSizeAllocated > (sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize)) + dwSizeAllocated = sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize; + + if (lpwfxFormat) { /* NULL is valid (just want size) */ + CopyMemory(lpwfxFormat, This->dsound->device->pwfx, dwSizeAllocated); + if (lpdwSizeWritten) + *lpdwSizeWritten = dwSizeAllocated; + } else { + if (lpdwSizeWritten) + *lpdwSizeWritten = sizeof(WAVEFORMATEX) + This->dsound->device->pwfx->cbSize; + else { + TRACE("invalid parameter: lpdwSizeWritten = NULL\n"); + hres = DSERR_INVALIDPARAM; + } + } + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetStatus( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPDWORD lpdwStatus ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p, %p), thread is %04lx\n", This, lpdwStatus, GetCurrentThreadId() ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpdwStatus == NULL) { + WARN("invalid parameter: lpdwStatus == NULL\n"); + return DSERR_INVALIDPARAM; + } + + *lpdwStatus = 0; + EnterCriticalSection(&(This->dsound->device->lock)); + + TRACE("old This->dsound->state=%s, old lpdwStatus=%08lx\n", + captureStateString[This->dsound->device->state],*lpdwStatus); + if ((This->dsound->device->state == STATE_STARTING) || + (This->dsound->device->state == STATE_CAPTURING)) { + *lpdwStatus |= DSCBSTATUS_CAPTURING; + if (This->flags & DSCBSTART_LOOPING) + *lpdwStatus |= DSCBSTATUS_LOOPING; + } + TRACE("new This->dsound->state=%s, new lpdwStatus=%08lx\n", + captureStateString[This->dsound->device->state],*lpdwStatus); + LeaveCriticalSection(&(This->dsound->device->lock)); + + TRACE("status=%lx\n", *lpdwStatus); + TRACE("returning DS_OK\n"); + return DS_OK; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_Initialize( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPDIRECTSOUNDCAPTURE lpDSC, + LPCDSCBUFFERDESC lpcDSCBDesc ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + + FIXME( "(%p,%p,%p): stub\n", This, lpDSC, lpcDSCBDesc ); + + return DS_OK; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_Lock( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + DWORD dwReadCusor, + DWORD dwReadBytes, + LPVOID* lplpvAudioPtr1, + LPDWORD lpdwAudioBytes1, + LPVOID* lplpvAudioPtr2, + LPDWORD lpdwAudioBytes2, + DWORD dwFlags ) +{ + HRESULT hres = DS_OK; + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p,%08lu,%08lu,%p,%p,%p,%p,0x%08lx) at %ld\n", This, dwReadCusor, + dwReadBytes, lplpvAudioPtr1, lpdwAudioBytes1, lplpvAudioPtr2, + lpdwAudioBytes2, dwFlags, GetTickCount() ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lplpvAudioPtr1 == NULL) { + WARN("invalid parameter: lplpvAudioPtr1 == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpdwAudioBytes1 == NULL) { + WARN("invalid parameter: lpdwAudioBytes1 == NULL\n"); + return DSERR_INVALIDPARAM; + } + + EnterCriticalSection(&(This->dsound->device->lock)); + + if (This->dsound->device->driver) { + hres = IDsCaptureDriverBuffer_Lock(This->dsound->device->hwbuf, lplpvAudioPtr1, + lpdwAudioBytes1, lplpvAudioPtr2, + lpdwAudioBytes2, dwReadCusor, + dwReadBytes, dwFlags); + if (hres != DS_OK) + WARN("IDsCaptureDriverBuffer_Lock failed\n"); + } else if (This->dsound->device->hwi) { + *lplpvAudioPtr1 = This->dsound->device->buffer + dwReadCusor; + if ( (dwReadCusor + dwReadBytes) > This->dsound->device->buflen) { + *lpdwAudioBytes1 = This->dsound->device->buflen - dwReadCusor; + if (lplpvAudioPtr2) + *lplpvAudioPtr2 = This->dsound->device->buffer; + if (lpdwAudioBytes2) + *lpdwAudioBytes2 = dwReadBytes - *lpdwAudioBytes1; + } else { + *lpdwAudioBytes1 = dwReadBytes; + if (lplpvAudioPtr2) + *lplpvAudioPtr2 = 0; + if (lpdwAudioBytes2) + *lpdwAudioBytes2 = 0; + } + } else { + TRACE("invalid call\n"); + hres = DSERR_INVALIDCALL; /* DSERR_NODRIVER ? */ + } + + LeaveCriticalSection(&(This->dsound->device->lock)); + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_Start( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + DWORD dwFlags ) +{ + HRESULT hres = DS_OK; + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p,0x%08lx)\n", This, dwFlags ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if ( (This->dsound->device->driver == 0) && (This->dsound->device->hwi == 0) ) { + WARN("no driver\n"); + return DSERR_NODRIVER; + } + + EnterCriticalSection(&(This->dsound->device->lock)); + + This->flags = dwFlags; + TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->device->state]); + if (This->dsound->device->state == STATE_STOPPED) + This->dsound->device->state = STATE_STARTING; + else if (This->dsound->device->state == STATE_STOPPING) + This->dsound->device->state = STATE_CAPTURING; + TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]); + + LeaveCriticalSection(&(This->dsound->device->lock)); + + if (This->dsound->device->driver) { + hres = IDsCaptureDriverBuffer_Start(This->dsound->device->hwbuf, dwFlags); + if (hres != DS_OK) + WARN("IDsCaptureDriverBuffer_Start failed\n"); + } else if (This->dsound->device->hwi) { + IDirectSoundCaptureImpl* ipDSC = This->dsound; + + if (ipDSC->device->buffer) { + if (This->nrofnotifies) { + int c; + + ipDSC->device->nrofpwaves = This->nrofnotifies; + TRACE("nrofnotifies=%d\n", This->nrofnotifies); + + /* prepare headers */ + if (ipDSC->device->pwave) + ipDSC->device->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->pwave, + ipDSC->device->nrofpwaves*sizeof(WAVEHDR)); + else + ipDSC->device->pwave = HeapAlloc(GetProcessHeap(),0, + ipDSC->device->nrofpwaves*sizeof(WAVEHDR)); + + for (c = 0; c < ipDSC->device->nrofpwaves; c++) { + if (This->notifies[c].dwOffset == DSBPN_OFFSETSTOP) { + TRACE("got DSBPN_OFFSETSTOP\n"); + ipDSC->device->nrofpwaves = c; + break; + } + if (c == 0) { + ipDSC->device->pwave[0].lpData = (LPSTR)ipDSC->device->buffer; + ipDSC->device->pwave[0].dwBufferLength = + This->notifies[0].dwOffset + 1; + } else { + ipDSC->device->pwave[c].lpData = (LPSTR)ipDSC->device->buffer + + This->notifies[c-1].dwOffset + 1; + ipDSC->device->pwave[c].dwBufferLength = + This->notifies[c].dwOffset - + This->notifies[c-1].dwOffset; + } + ipDSC->device->pwave[c].dwBytesRecorded = 0; + ipDSC->device->pwave[c].dwUser = (DWORD)ipDSC; + ipDSC->device->pwave[c].dwFlags = 0; + ipDSC->device->pwave[c].dwLoops = 0; + hres = mmErr(waveInPrepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[c]),sizeof(WAVEHDR))); + if (hres != DS_OK) { + WARN("waveInPrepareHeader failed\n"); + while (c--) + waveInUnprepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[c]),sizeof(WAVEHDR)); + break; + } + + hres = mmErr(waveInAddBuffer(ipDSC->device->hwi, + &(ipDSC->device->pwave[c]), sizeof(WAVEHDR))); + if (hres != DS_OK) { + WARN("waveInAddBuffer failed\n"); + while (c--) + waveInUnprepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[c]),sizeof(WAVEHDR)); + break; + } + } + + FillMemory(ipDSC->device->buffer, ipDSC->device->buflen, + (ipDSC->device->pwfx->wBitsPerSample == 8) ? 128 : 0); + } else { + TRACE("no notifiers specified\n"); + /* no notifiers specified so just create a single default header */ + ipDSC->device->nrofpwaves = 1; + if (ipDSC->device->pwave) + ipDSC->device->pwave = HeapReAlloc(GetProcessHeap(),0,ipDSC->device->pwave,sizeof(WAVEHDR)); + else + ipDSC->device->pwave = HeapAlloc(GetProcessHeap(),0,sizeof(WAVEHDR)); + + ipDSC->device->pwave[0].lpData = (LPSTR)ipDSC->device->buffer; + ipDSC->device->pwave[0].dwBufferLength = ipDSC->device->buflen; + ipDSC->device->pwave[0].dwBytesRecorded = 0; + ipDSC->device->pwave[0].dwUser = (DWORD)ipDSC; + ipDSC->device->pwave[0].dwFlags = 0; + ipDSC->device->pwave[0].dwLoops = 0; + + hres = mmErr(waveInPrepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[0]),sizeof(WAVEHDR))); + if (hres != DS_OK) { + WARN("waveInPrepareHeader failed\n"); + waveInUnprepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[0]),sizeof(WAVEHDR)); + } + hres = mmErr(waveInAddBuffer(ipDSC->device->hwi, + &(ipDSC->device->pwave[0]), sizeof(WAVEHDR))); + if (hres != DS_OK) { + WARN("waveInAddBuffer failed\n"); + waveInUnprepareHeader(ipDSC->device->hwi, + &(ipDSC->device->pwave[0]),sizeof(WAVEHDR)); + } + } + } + + ipDSC->device->index = 0; + ipDSC->device->read_position = 0; + + if (hres == DS_OK) { + /* start filling the first buffer */ + hres = mmErr(waveInStart(ipDSC->device->hwi)); + if (hres != DS_OK) + WARN("waveInStart failed\n"); + } + + if (hres != DS_OK) { + WARN("calling waveInClose because of error\n"); + waveInClose(This->dsound->device->hwi); + This->dsound->device->hwi = 0; + } + } else { + WARN("no driver\n"); + hres = DSERR_NODRIVER; + } + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface ) +{ + HRESULT hres = DS_OK; + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p)\n", This ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound == NULL) { + WARN("invalid parameter: This->dsound == NULL\n"); + return DSERR_INVALIDPARAM; + } + + EnterCriticalSection(&(This->dsound->device->lock)); + + TRACE("old This->dsound->state=%s\n",captureStateString[This->dsound->device->state]); + if (This->dsound->device->state == STATE_CAPTURING) + This->dsound->device->state = STATE_STOPPING; + else if (This->dsound->device->state == STATE_STARTING) + This->dsound->device->state = STATE_STOPPED; + TRACE("new This->dsound->device->state=%s\n",captureStateString[This->dsound->device->state]); + + LeaveCriticalSection(&(This->dsound->device->lock)); + + if (This->dsound->device->driver) { + hres = IDsCaptureDriverBuffer_Stop(This->dsound->device->hwbuf); + if (hres != DS_OK) + WARN("IDsCaptureDriverBuffer_Stop() failed\n"); + } else if (This->dsound->device->hwi) { + hres = mmErr(waveInReset(This->dsound->device->hwi)); + if (hres != DS_OK) + WARN("waveInReset() failed\n"); + } else { + WARN("no driver\n"); + hres = DSERR_NODRIVER; + } + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_Unlock( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + LPVOID lpvAudioPtr1, + DWORD dwAudioBytes1, + LPVOID lpvAudioPtr2, + DWORD dwAudioBytes2 ) +{ + HRESULT hres = DS_OK; + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + TRACE( "(%p,%p,%08lu,%p,%08lu)\n", This, lpvAudioPtr1, dwAudioBytes1, + lpvAudioPtr2, dwAudioBytes2 ); + + if (This == NULL) { + WARN("invalid parameter: This == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpvAudioPtr1 == NULL) { + WARN("invalid parameter: lpvAudioPtr1 == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (This->dsound->device->driver) { + hres = IDsCaptureDriverBuffer_Unlock(This->dsound->device->hwbuf, lpvAudioPtr1, + dwAudioBytes1, lpvAudioPtr2, dwAudioBytes2); + if (hres != DS_OK) + WARN("IDsCaptureDriverBuffer_Unlock failed\n"); + } else if (This->dsound->device->hwi) { + This->dsound->device->read_position = (This->dsound->device->read_position + + (dwAudioBytes1 + dwAudioBytes2)) % This->dsound->device->buflen; + } else { + WARN("invalid call\n"); + hres = DSERR_INVALIDCALL; + } + + TRACE("returning %08lx\n", hres); + return hres; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetObjectInPath( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + REFGUID rguidObject, + DWORD dwIndex, + REFGUID rguidInterface, + LPVOID* ppObject ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + + FIXME( "(%p,%s,%lu,%s,%p): stub\n", This, debugstr_guid(rguidObject), + dwIndex, debugstr_guid(rguidInterface), ppObject ); + + return DS_OK; +} + +static HRESULT WINAPI +IDirectSoundCaptureBufferImpl_GetFXStatus( + LPDIRECTSOUNDCAPTUREBUFFER8 iface, + DWORD dwFXCount, + LPDWORD pdwFXStatus ) +{ + IDirectSoundCaptureBufferImpl *This = (IDirectSoundCaptureBufferImpl *)iface; + + FIXME( "(%p,%lu,%p): stub\n", This, dwFXCount, pdwFXStatus ); + + return DS_OK; +} + +static const IDirectSoundCaptureBuffer8Vtbl dscbvt = +{ + /* IUnknown methods */ + IDirectSoundCaptureBufferImpl_QueryInterface, + IDirectSoundCaptureBufferImpl_AddRef, + IDirectSoundCaptureBufferImpl_Release, + + /* IDirectSoundCaptureBuffer methods */ + IDirectSoundCaptureBufferImpl_GetCaps, + IDirectSoundCaptureBufferImpl_GetCurrentPosition, + IDirectSoundCaptureBufferImpl_GetFormat, + IDirectSoundCaptureBufferImpl_GetStatus, + IDirectSoundCaptureBufferImpl_Initialize, + IDirectSoundCaptureBufferImpl_Lock, + IDirectSoundCaptureBufferImpl_Start, + IDirectSoundCaptureBufferImpl_Stop, + IDirectSoundCaptureBufferImpl_Unlock, + + /* IDirectSoundCaptureBuffer methods */ + IDirectSoundCaptureBufferImpl_GetObjectInPath, + IDirectSoundCaptureBufferImpl_GetFXStatus +}; + +/******************************************************************************* + * DirectSoundCapture ClassFactory + */ + +static HRESULT WINAPI +DSCCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI +DSCCF_AddRef(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI +DSCCF_Release(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + /* static class, won't be freed */ + return ref; +} + +static HRESULT WINAPI +DSCCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + if (pOuter) { + WARN("aggregation not supported\n"); + return CLASS_E_NOAGGREGATION; + } + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppobj = NULL; + + if ( IsEqualGUID( &IID_IDirectSoundCapture, riid ) ) + return DSOUND_CaptureCreate8((LPDIRECTSOUNDCAPTURE*)ppobj,pOuter); + + WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI +DSCCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DSCCF_Vtbl = +{ + DSCCF_QueryInterface, + DSCCF_AddRef, + DSCCF_Release, + DSCCF_CreateInstance, + DSCCF_LockServer +}; + +IClassFactoryImpl DSOUND_CAPTURE_CF = { &DSCCF_Vtbl, 1 }; diff --git a/reactos/lib/dsound/dsound.c b/reactos/lib/dsound/dsound.c index 88611fb0890..bb060238db1 100644 --- a/reactos/lib/dsound/dsound.c +++ b/reactos/lib/dsound/dsound.c @@ -20,38 +20,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "config.h" -#include "wine/port.h" - #include #include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include #define NONAMELESSSTRUCT #define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "winreg.h" -#include "winuser.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" #include "mmsystem.h" #include "winternl.h" #include "mmddk.h" -#include "wine/windef16.h" -#include "wine/winbase16.h" #include "wine/debug.h" #include "dsound.h" #include "dsdriver.h" #include "dsound_private.h" -#include "dsconf.h" WINE_DEFAULT_DEBUG_CHANNEL(dsound); @@ -61,6 +44,9 @@ static ULONG WINAPI IDirectSound8_IUnknown_AddRef(LPUNKNOWN iface); static ULONG WINAPI IDirectSound8_IDirectSound_AddRef(LPDIRECTSOUND iface); static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef(LPDIRECTSOUND8 iface); +static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice); +static ULONG DirectSoundDevice_Release(DirectSoundDevice * device); + static const char * dumpCooperativeLevel(DWORD level) { static char unknown[32]; @@ -79,7 +65,7 @@ static const char * dumpCooperativeLevel(DWORD level) static void _dump_DSCAPS(DWORD xmask) { struct { DWORD mask; - char *name; + const char *name; } flags[] = { #define FE(x) { x, #x }, FE(DSCAPS_PRIMARYMONO) @@ -105,7 +91,7 @@ static void _dump_DSCAPS(DWORD xmask) { static void _dump_DSBCAPS(DWORD xmask) { struct { DWORD mask; - char *name; + const char *name; } flags[] = { #define FE(x) { x, #x }, FE(DSBCAPS_PRIMARYBUFFER) @@ -247,68 +233,25 @@ static ULONG WINAPI IDirectSoundImpl_AddRef( LPDIRECTSOUND8 iface) { IDirectSoundImpl *This = (IDirectSoundImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSoundImpl_Release( LPDIRECTSOUND8 iface) { IDirectSoundImpl *This = (IDirectSoundImpl *)iface; - ULONG ref; - TRACE("(%p) ref was %ld, thread is %04lx\n", - This, This->ref, GetCurrentThreadId()); + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) { - HRESULT hres; - INT i; + if (!ref) { + if (This->device) + DirectSoundDevice_Release(This->device); - timeKillEvent(This->timerID); - timeEndPeriod(DS_TIME_RES); - /* wait for timer to expire */ - Sleep(DS_TIME_RES+1); - - /* The sleep above should have allowed the timer process to expire - * but try to grab the lock just in case. Can't hold lock because - * IDirectSoundBufferImpl_Destroy also grabs the lock */ - RtlAcquireResourceShared(&(This->buffer_list_lock), TRUE); - RtlReleaseResource(&(This->buffer_list_lock)); - - /* It is allowed to release this object even when buffers are playing */ - if (This->buffers) { - WARN("%d secondary buffers not released\n", This->nrofbuffers); - for( i=0;inrofbuffers;i++) - IDirectSoundBufferImpl_Destroy(This->buffers[i]); - } - - if (This->primary) { - WARN("primary buffer not released\n"); - IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)This->primary); - } - - hres = DSOUND_PrimaryDestroy(This); - if (hres != DS_OK) - WARN("DSOUND_PrimaryDestroy failed\n"); - - if (This->driver) - IDsDriver_Close(This->driver); - - if (This->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) - waveOutClose(This->hwo); - - if (This->driver) - IDsDriver_Release(This->driver); - - RtlDeleteResource(&This->buffer_list_lock); - This->mixlock.DebugInfo->Spare[1] = 0; - DeleteCriticalSection(&This->mixlock); HeapFree(GetProcessHeap(),0,This); - dsound = NULL; - TRACE("(%p) released\n",This); + TRACE("(%p) released\n", This); } - return ref; } @@ -340,7 +283,7 @@ static HRESULT WINAPI DSOUND_CreateSoundBuffer( return DSERR_INVALIDPARAM; } - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } @@ -377,16 +320,16 @@ static HRESULT WINAPI DSOUND_CreateSoundBuffer( return DSERR_INVALIDPARAM; } - if (This->primary) { + if (This->device->primary) { WARN("Primary Buffer already created\n"); - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary)); - *ppdsb = (LPDIRECTSOUNDBUFFER)(This->primary); + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary)); + *ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary); } else { - This->dsbd = *dsbd; - hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->primary), &(This->dsbd)); - if (This->primary) { - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->primary)); - *ppdsb = (LPDIRECTSOUNDBUFFER)(This->primary); + This->device->dsbd = *dsbd; + hres = PrimaryBufferImpl_Create(This, (PrimaryBufferImpl**)&(This->device->primary), &(This->device->dsbd)); + if (This->device->primary) { + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)(This->device->primary)); + *ppdsb = (LPDIRECTSOUNDBUFFER)(This->device->primary); } else WARN("PrimaryBufferImpl_Create failed\n"); } @@ -432,6 +375,7 @@ static HRESULT WINAPI IDirectSoundImpl_GetCaps( LPDSCAPS lpDSCaps) { IDirectSoundImpl *This = (IDirectSoundImpl *)iface; + DirectSoundDevice *device; TRACE("(%p,%p)\n",This,lpDSCaps); if (This == NULL) { @@ -439,7 +383,9 @@ static HRESULT WINAPI IDirectSoundImpl_GetCaps( return DSERR_INVALIDPARAM; } - if (This->initialized == FALSE) { + device = This->device; + + if (device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } @@ -456,30 +402,30 @@ static HRESULT WINAPI IDirectSoundImpl_GetCaps( return DSERR_INVALIDPARAM; } - lpDSCaps->dwFlags = This->drvcaps.dwFlags; + lpDSCaps->dwFlags = device->drvcaps.dwFlags; if (TRACE_ON(dsound)) { TRACE("(flags=0x%08lx:\n",lpDSCaps->dwFlags); _dump_DSCAPS(lpDSCaps->dwFlags); DPRINTF(")\n"); } - lpDSCaps->dwMinSecondarySampleRate = This->drvcaps.dwMinSecondarySampleRate; - lpDSCaps->dwMaxSecondarySampleRate = This->drvcaps.dwMaxSecondarySampleRate; - lpDSCaps->dwPrimaryBuffers = This->drvcaps.dwPrimaryBuffers; - lpDSCaps->dwMaxHwMixingAllBuffers = This->drvcaps.dwMaxHwMixingAllBuffers; - lpDSCaps->dwMaxHwMixingStaticBuffers = This->drvcaps.dwMaxHwMixingStaticBuffers; - lpDSCaps->dwMaxHwMixingStreamingBuffers = This->drvcaps.dwMaxHwMixingStreamingBuffers; - lpDSCaps->dwFreeHwMixingAllBuffers = This->drvcaps.dwFreeHwMixingAllBuffers; - lpDSCaps->dwFreeHwMixingStaticBuffers = This->drvcaps.dwFreeHwMixingStaticBuffers; - lpDSCaps->dwFreeHwMixingStreamingBuffers = This->drvcaps.dwFreeHwMixingStreamingBuffers; - lpDSCaps->dwMaxHw3DAllBuffers = This->drvcaps.dwMaxHw3DAllBuffers; - lpDSCaps->dwMaxHw3DStaticBuffers = This->drvcaps.dwMaxHw3DStaticBuffers; - lpDSCaps->dwMaxHw3DStreamingBuffers = This->drvcaps.dwMaxHw3DStreamingBuffers; - lpDSCaps->dwFreeHw3DAllBuffers = This->drvcaps.dwFreeHw3DAllBuffers; - lpDSCaps->dwFreeHw3DStaticBuffers = This->drvcaps.dwFreeHw3DStaticBuffers; - lpDSCaps->dwFreeHw3DStreamingBuffers = This->drvcaps.dwFreeHw3DStreamingBuffers; - lpDSCaps->dwTotalHwMemBytes = This->drvcaps.dwTotalHwMemBytes; - lpDSCaps->dwFreeHwMemBytes = This->drvcaps.dwFreeHwMemBytes; - lpDSCaps->dwMaxContigFreeHwMemBytes = This->drvcaps.dwMaxContigFreeHwMemBytes; + lpDSCaps->dwMinSecondarySampleRate = device->drvcaps.dwMinSecondarySampleRate; + lpDSCaps->dwMaxSecondarySampleRate = device->drvcaps.dwMaxSecondarySampleRate; + lpDSCaps->dwPrimaryBuffers = device->drvcaps.dwPrimaryBuffers; + lpDSCaps->dwMaxHwMixingAllBuffers = device->drvcaps.dwMaxHwMixingAllBuffers; + lpDSCaps->dwMaxHwMixingStaticBuffers = device->drvcaps.dwMaxHwMixingStaticBuffers; + lpDSCaps->dwMaxHwMixingStreamingBuffers = device->drvcaps.dwMaxHwMixingStreamingBuffers; + lpDSCaps->dwFreeHwMixingAllBuffers = device->drvcaps.dwFreeHwMixingAllBuffers; + lpDSCaps->dwFreeHwMixingStaticBuffers = device->drvcaps.dwFreeHwMixingStaticBuffers; + lpDSCaps->dwFreeHwMixingStreamingBuffers = device->drvcaps.dwFreeHwMixingStreamingBuffers; + lpDSCaps->dwMaxHw3DAllBuffers = device->drvcaps.dwMaxHw3DAllBuffers; + lpDSCaps->dwMaxHw3DStaticBuffers = device->drvcaps.dwMaxHw3DStaticBuffers; + lpDSCaps->dwMaxHw3DStreamingBuffers = device->drvcaps.dwMaxHw3DStreamingBuffers; + lpDSCaps->dwFreeHw3DAllBuffers = device->drvcaps.dwFreeHw3DAllBuffers; + lpDSCaps->dwFreeHw3DStaticBuffers = device->drvcaps.dwFreeHw3DStaticBuffers; + lpDSCaps->dwFreeHw3DStreamingBuffers = device->drvcaps.dwFreeHw3DStreamingBuffers; + lpDSCaps->dwTotalHwMemBytes = device->drvcaps.dwTotalHwMemBytes; + lpDSCaps->dwFreeHwMemBytes = device->drvcaps.dwFreeHwMemBytes; + lpDSCaps->dwMaxContigFreeHwMemBytes = device->drvcaps.dwMaxContigFreeHwMemBytes; /* driver doesn't have these */ lpDSCaps->dwUnlockTransferRateHwBuffers = 4096; /* But we have none... */ @@ -506,7 +452,7 @@ static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer( return DSERR_INVALIDPARAM; } - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } @@ -522,7 +468,7 @@ static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer( } /* FIXME: hack to make sure we have a secondary buffer */ - if ((DWORD)((SecondaryBufferImpl *)psb)->dsb == (DWORD)This) { + if ((IDirectSoundImpl *)((SecondaryBufferImpl *)psb)->dsb == This) { WARN("trying to duplicate primary buffer\n"); *ppdsb = NULL; return DSERR_INVALIDCALL; @@ -538,17 +484,17 @@ static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer( return DSERR_OUTOFMEMORY; } - memcpy(dsb, pdsb, sizeof(IDirectSoundBufferImpl)); + CopyMemory(dsb, pdsb, sizeof(IDirectSoundBufferImpl)); if (pdsb->hwbuf) { TRACE("duplicating hardware buffer\n"); - hres = IDsDriver_DuplicateSoundBuffer(This->driver, pdsb->hwbuf, (LPVOID *)&dsb->hwbuf); + hres = IDsDriver_DuplicateSoundBuffer(This->device->driver, pdsb->hwbuf, (LPVOID *)&dsb->hwbuf); if (hres != DS_OK) { TRACE("IDsDriver_DuplicateSoundBuffer failed, falling back to software buffer\n"); dsb->hwbuf = NULL; /* allocate buffer */ - if (This->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { + if (This->device->drvdesc.dwFlags & DSDDESC_USESYSTEMMEMORY) { dsb->buffer = HeapAlloc(GetProcessHeap(),0,sizeof(*(dsb->buffer))); if (dsb->buffer == NULL) { WARN("out of memory\n"); @@ -596,16 +542,16 @@ static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer( return DSERR_OUTOFMEMORY; } - memcpy(dsb->pwfx, pdsb->pwfx, size); + CopyMemory(dsb->pwfx, pdsb->pwfx, size); InitializeCriticalSection(&(dsb->lock)); - dsb->lock.DebugInfo->Spare[1] = (DWORD)"DSOUNDBUFFER_lock"; + dsb->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUNDBUFFER_lock"; /* register buffer */ hres = DSOUND_AddBuffer(This, dsb); if (hres != DS_OK) { IDirectSoundBuffer8_Release(psb); - dsb->lock.DebugInfo->Spare[1] = 0; + dsb->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&(dsb->lock)); HeapFree(GetProcessHeap(),0,dsb->buffer); HeapFree(GetProcessHeap(),0,dsb->pwfx); @@ -629,13 +575,13 @@ static HRESULT WINAPI IDirectSoundImpl_SetCooperativeLevel( DWORD level) { IDirectSoundImpl *This = (IDirectSoundImpl *)iface; - TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level)); + TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); if (level==DSSCL_PRIORITY || level==DSSCL_EXCLUSIVE) { - FIXME("level=%s not fully supported\n", - level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE"); + WARN("level=%s not fully supported\n", + level==DSSCL_PRIORITY ? "DSSCL_PRIORITY" : "DSSCL_EXCLUSIVE"); } - This->priolevel = level; + This->device->priolevel = level; return DS_OK; } @@ -645,12 +591,12 @@ static HRESULT WINAPI IDirectSoundImpl_Compact( IDirectSoundImpl *This = (IDirectSoundImpl *)iface; TRACE("(%p)\n",This); - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } - if (This->priolevel != DSSCL_PRIORITY) { + if (This->device->priolevel != DSSCL_PRIORITY) { WARN("incorrect priority level\n"); return DSERR_PRIOLEVELNEEDED; } @@ -665,7 +611,7 @@ static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig( IDirectSoundImpl *This = (IDirectSoundImpl *)iface; TRACE("(%p, %p)\n",This,lpdwSpeakerConfig); - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } @@ -676,7 +622,7 @@ static HRESULT WINAPI IDirectSoundImpl_GetSpeakerConfig( } WARN("not fully functional\n"); - *lpdwSpeakerConfig = This->speaker_config; + *lpdwSpeakerConfig = This->device->speaker_config; return DS_OK; } @@ -687,26 +633,196 @@ static HRESULT WINAPI IDirectSoundImpl_SetSpeakerConfig( IDirectSoundImpl *This = (IDirectSoundImpl *)iface; TRACE("(%p,0x%08lx)\n",This,config); - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } - This->speaker_config = config; + This->device->speaker_config = config; WARN("not fully functional\n"); return DS_OK; } static HRESULT WINAPI IDirectSoundImpl_Initialize( LPDIRECTSOUND8 iface, - LPCGUID lpcGuid) + LPCGUID lpcGUID) { IDirectSoundImpl *This = (IDirectSoundImpl *)iface; - TRACE("(%p,%s)\n",This,debugstr_guid(lpcGuid)); + DirectSoundDevice *device = This->device; + HRESULT hr = DS_OK; + unsigned wod, wodn; + BOOLEAN found = FALSE; + GUID devGUID; + TRACE("(%p,%s)\n",This,debugstr_guid(lpcGUID)); - This->initialized = TRUE; + if (device != NULL) { + WARN("already initialized\n"); + return DSERR_ALREADYINITIALIZED; + } - return DS_OK; + /* Default device? */ + if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) + lpcGUID = &DSDEVID_DefaultPlayback; + + if (GetDeviceID(lpcGUID, &devGUID) != DS_OK) { + WARN("invalid parameter: lpcGUID\n"); + return DSERR_INVALIDPARAM; + } + + /* Enumerate WINMM audio devices and find the one we want */ + wodn = waveOutGetNumDevs(); + if (!wodn) { + WARN("no driver\n"); + return DSERR_NODRIVER; + } + + for (wod=0; wodguid)) { + device = DSOUND_renderer[wod]; + device->ref++; + This->device = device; + return DS_OK; + } else { + ERR("device GUID doesn't match\n"); + hr = DSERR_GENERIC; + return hr; + } + } else { + hr = DirectSoundDevice_Create(&(device)); + if (hr != DS_OK) { + WARN("DirectSoundDevice_Create failed\n"); + return hr; + } + } + + This->device = device; + device->guid = devGUID; + + /* DRV_QUERYDSOUNDIFACE is a "Wine extension" to get the DSound interface */ + WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&device->driver, 0); + + /* Disable the direct sound driver to force emulation if requested. */ + if (ds_hw_accel == DS_HW_ACCEL_EMULATION) + device->driver = NULL; + + /* Get driver description */ + if (device->driver) { + hr = IDsDriver_GetDriverDesc(device->driver,&(device->drvdesc)); + if (hr != DS_OK) { + WARN("IDsDriver_GetDriverDesc failed\n"); + return hr; + } + } else { + /* if no DirectSound interface available, use WINMM API instead */ + device->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT; + } + + device->drvdesc.dnDevNode = wod; + + /* If the driver requests being opened through MMSYSTEM + * (which is recommended by the DDK), it is supposed to happen + * before the DirectSound interface is opened */ + if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) + { + DWORD flags = CALLBACK_FUNCTION; + + /* disable direct sound if requested */ + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; + + hr = mmErr(waveOutOpen(&(device->hwo), + device->drvdesc.dnDevNode, device->pwfx, + (DWORD_PTR)DSOUND_callback, (DWORD)device, + flags)); + if (hr != DS_OK) { + WARN("waveOutOpen failed\n"); + return hr; + } + } + + if (device->driver) { + hr = IDsDriver_Open(device->driver); + if (hr != DS_OK) { + WARN("IDsDriver_Open failed\n"); + return hr; + } + + /* the driver is now open, so it's now allowed to call GetCaps */ + hr = IDsDriver_GetCaps(device->driver,&(device->drvcaps)); + if (hr != DS_OK) { + WARN("IDsDriver_GetCaps failed\n"); + return hr; + } + } else { + WAVEOUTCAPSA woc; + hr = mmErr(waveOutGetDevCapsA(device->drvdesc.dnDevNode, &woc, sizeof(woc))); + if (hr != DS_OK) { + WARN("waveOutGetDevCaps failed\n"); + return hr; + } + ZeroMemory(&device->drvcaps, sizeof(device->drvcaps)); + if ((woc.dwFormats & WAVE_FORMAT_1M08) || + (woc.dwFormats & WAVE_FORMAT_2M08) || + (woc.dwFormats & WAVE_FORMAT_4M08) || + (woc.dwFormats & WAVE_FORMAT_48M08) || + (woc.dwFormats & WAVE_FORMAT_96M08)) { + device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; + device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; + } + if ((woc.dwFormats & WAVE_FORMAT_1M16) || + (woc.dwFormats & WAVE_FORMAT_2M16) || + (woc.dwFormats & WAVE_FORMAT_4M16) || + (woc.dwFormats & WAVE_FORMAT_48M16) || + (woc.dwFormats & WAVE_FORMAT_96M16)) { + device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; + device->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; + } + if ((woc.dwFormats & WAVE_FORMAT_1S08) || + (woc.dwFormats & WAVE_FORMAT_2S08) || + (woc.dwFormats & WAVE_FORMAT_4S08) || + (woc.dwFormats & WAVE_FORMAT_48S08) || + (woc.dwFormats & WAVE_FORMAT_96S08)) { + device->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; + device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; + } + if ((woc.dwFormats & WAVE_FORMAT_1S16) || + (woc.dwFormats & WAVE_FORMAT_2S16) || + (woc.dwFormats & WAVE_FORMAT_4S16) || + (woc.dwFormats & WAVE_FORMAT_48S16) || + (woc.dwFormats & WAVE_FORMAT_96S16)) { + device->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; + device->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; + } + if (ds_emuldriver) + device->drvcaps.dwFlags |= DSCAPS_EMULDRIVER; + device->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; + device->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; + device->drvcaps.dwPrimaryBuffers = 1; + } + + hr = DSOUND_PrimaryCreate(device); + if (hr == DS_OK) { + DSOUND_renderer[device->drvdesc.dnDevNode] = device; + timeBeginPeriod(DS_TIME_RES); + DSOUND_renderer[device->drvdesc.dnDevNode]->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer, + (DWORD_PTR)DSOUND_renderer[device->drvdesc.dnDevNode], TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + } else { + WARN("DSOUND_PrimaryCreate failed\n"); + } + + return hr; } static HRESULT WINAPI IDirectSoundImpl_VerifyCertification( @@ -716,19 +832,19 @@ static HRESULT WINAPI IDirectSoundImpl_VerifyCertification( IDirectSoundImpl *This = (IDirectSoundImpl *)iface; TRACE("(%p, %p)\n",This,pdwCertified); - if (This->initialized == FALSE) { + if (This->device == NULL) { WARN("not initialized\n"); return DSERR_UNINITIALIZED; } - if (This->drvcaps.dwFlags & DSCAPS_CERTIFIED) + if (This->device->drvcaps.dwFlags & DSCAPS_CERTIFIED) *pdwCertified = DS_CERTIFIED; else *pdwCertified = DS_UNCERTIFIED; return DS_OK; } -static IDirectSound8Vtbl IDirectSoundImpl_Vtbl = +static const IDirectSound8Vtbl IDirectSoundImpl_Vtbl = { IDirectSoundImpl_QueryInterface, IDirectSoundImpl_AddRef, @@ -744,46 +860,148 @@ static IDirectSound8Vtbl IDirectSoundImpl_Vtbl = IDirectSoundImpl_VerifyCertification }; +static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) +{ + DirectSoundDevice * device; + TRACE("(%p)\n", ppDevice); + + /* Allocate memory */ + device = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DirectSoundDevice)); + if (device == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + + device->ref = 1; + device->driver = NULL; + device->priolevel = DSSCL_NORMAL; + device->fraglen = 0; + device->hwbuf = NULL; + device->buffer = NULL; + device->buflen = 0; + device->writelead = 0; + device->state = STATE_STOPPED; + device->nrofbuffers = 0; + device->buffers = NULL; + device->primary = NULL; + device->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16); + device->tmp_buffer = NULL; + device->tmp_buffer_len = 0; + + /* 3D listener initial parameters */ + device->listener = NULL; + device->ds3dl.dwSize = sizeof(DS3DLISTENER); + device->ds3dl.vPosition.x = 0.0; + device->ds3dl.vPosition.y = 0.0; + device->ds3dl.vPosition.z = 0.0; + device->ds3dl.vVelocity.x = 0.0; + device->ds3dl.vVelocity.y = 0.0; + device->ds3dl.vVelocity.z = 0.0; + device->ds3dl.vOrientFront.x = 0.0; + device->ds3dl.vOrientFront.y = 0.0; + device->ds3dl.vOrientFront.z = 1.0; + device->ds3dl.vOrientTop.x = 0.0; + device->ds3dl.vOrientTop.y = 1.0; + device->ds3dl.vOrientTop.z = 0.0; + device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; + device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; + device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; + + device->prebuf = ds_snd_queue_max; + device->guid = GUID_NULL; + + /* Set default wave format (may need it for waveOutOpen) */ + device->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX)); + if (device->pwfx == NULL) { + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,device); + return DSERR_OUTOFMEMORY; + } + + /* We rely on the sound driver to return the actual sound format of + * the device if it does not support 22050x8x2 and is given the + * WAVE_DIRECTSOUND flag. + */ + device->pwfx->wFormatTag = WAVE_FORMAT_PCM; + device->pwfx->nSamplesPerSec = 22050; + device->pwfx->wBitsPerSample = 8; + device->pwfx->nChannels = 2; + device->pwfx->nBlockAlign = device->pwfx->wBitsPerSample * device->pwfx->nChannels / 8; + device->pwfx->nAvgBytesPerSec = device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign; + device->pwfx->cbSize = 0; + + InitializeCriticalSection(&(device->mixlock)); + device->mixlock.DebugInfo->Spare[0] = (DWORD_PTR)"DSOUND_mixlock"; + + RtlInitializeResource(&(device->buffer_list_lock)); + + *ppDevice = device; + + return DS_OK; +} + +static ULONG DirectSoundDevice_Release(DirectSoundDevice * device) +{ + int i; + HRESULT hr; + TRACE("(%p) ref was %lu\n", device, device->ref); + + device->ref--; + if (device->ref == 0) { + timeKillEvent(device->timerID); + timeEndPeriod(DS_TIME_RES); + /* wait for timer to expire */ + Sleep(DS_TIME_RES+1); + + /* The sleep above should have allowed the timer process to expire + * but try to grab the lock just in case. Can't hold lock because + * IDirectSoundBufferImpl_Destroy also grabs the lock */ + RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE); + RtlReleaseResource(&(device->buffer_list_lock)); + + /* It is allowed to release this object even when buffers are playing */ + if (device->buffers) { + WARN("%d secondary buffers not released\n", device->nrofbuffers); + for( i=0;inrofbuffers;i++) + IDirectSoundBufferImpl_Destroy(device->buffers[i]); + } + + if (device->primary) { + WARN("primary buffer not released\n"); + IDirectSoundBuffer8_Release((LPDIRECTSOUNDBUFFER8)device->primary); + } + + hr = DSOUND_PrimaryDestroy(device); + if (hr != DS_OK) + WARN("DSOUND_PrimaryDestroy failed\n"); + + if (device->driver) + IDsDriver_Close(device->driver); + + if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) + waveOutClose(device->hwo); + + if (device->driver) + IDsDriver_Release(device->driver); + + DSOUND_renderer[device->drvdesc.dnDevNode] = NULL; + + HeapFree(GetProcessHeap(),0,device->tmp_buffer); + HeapFree(GetProcessHeap(),0,device->buffer); + RtlDeleteResource(&device->buffer_list_lock); + device->mixlock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&device->mixlock); + HeapFree(GetProcessHeap(),0,device); + TRACE("(%p) released\n", device); + } + return device->ref; +} + HRESULT WINAPI IDirectSoundImpl_Create( - LPCGUID lpcGUID, LPDIRECTSOUND8 * ppDS) { - HRESULT err; - PIDSDRIVER drv = NULL; IDirectSoundImpl* pDS; - unsigned wod, wodn; - BOOLEAN found = FALSE; - TRACE("(%s,%p)\n",debugstr_guid(lpcGUID),ppDS); - - /* Enumerate WINMM audio devices and find the one we want */ - wodn = waveOutGetNumDevs(); - if (!wodn) { - WARN("no driver\n"); - *ppDS = NULL; - return DSERR_NODRIVER; - } - - TRACE(" expecting GUID %s.\n", debugstr_guid(lpcGUID)); - - for (wod=0; wodlpVtbl = &IDirectSoundImpl_Vtbl; - pDS->ref = 0; - - pDS->driver = drv; - pDS->priolevel = DSSCL_NORMAL; - pDS->fraglen = 0; - pDS->hwbuf = NULL; - pDS->buffer = NULL; - pDS->buflen = 0; - pDS->writelead = 0; - pDS->state = STATE_STOPPED; - pDS->nrofbuffers = 0; - pDS->buffers = NULL; - pDS->primary = NULL; - pDS->speaker_config = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16); - pDS->initialized = FALSE; - - /* 3D listener initial parameters */ - pDS->listener = NULL; - pDS->ds3dl.dwSize = sizeof(DS3DLISTENER); - pDS->ds3dl.vPosition.x = 0.0; - pDS->ds3dl.vPosition.y = 0.0; - pDS->ds3dl.vPosition.z = 0.0; - pDS->ds3dl.vVelocity.x = 0.0; - pDS->ds3dl.vVelocity.y = 0.0; - pDS->ds3dl.vVelocity.z = 0.0; - pDS->ds3dl.vOrientFront.x = 0.0; - pDS->ds3dl.vOrientFront.y = 0.0; - pDS->ds3dl.vOrientFront.z = 1.0; - pDS->ds3dl.vOrientTop.x = 0.0; - pDS->ds3dl.vOrientTop.y = 1.0; - pDS->ds3dl.vOrientTop.z = 0.0; - pDS->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; - pDS->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; - pDS->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; - - pDS->prebuf = ds_snd_queue_max; - pDS->guid = *lpcGUID; - - /* Get driver description */ - if (drv) { - err = IDsDriver_GetDriverDesc(drv,&(pDS->drvdesc)); - if (err != DS_OK) { - WARN("IDsDriver_GetDriverDesc failed\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return err; - } - } else { - /* if no DirectSound interface available, use WINMM API instead */ - pDS->drvdesc.dwFlags = DSDDESC_DOMMSYSTEMOPEN | DSDDESC_DOMMSYSTEMSETFORMAT; - } - - pDS->drvdesc.dnDevNode = wod; - - /* Set default wave format (may need it for waveOutOpen) */ - pDS->pwfx = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEFORMATEX)); - if (pDS->pwfx == NULL) { - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return DSERR_OUTOFMEMORY; - } - - pDS->pwfx->wFormatTag = WAVE_FORMAT_PCM; - /* We rely on the sound driver to return the actual sound format of - * the device if it does not support 22050x8x2 and is given the - * WAVE_DIRECTSOUND flag. - */ - pDS->pwfx->nSamplesPerSec = 22050; - pDS->pwfx->wBitsPerSample = 8; - pDS->pwfx->nChannels = 2; - pDS->pwfx->nBlockAlign = pDS->pwfx->wBitsPerSample * pDS->pwfx->nChannels / 8; - pDS->pwfx->nAvgBytesPerSec = pDS->pwfx->nSamplesPerSec * pDS->pwfx->nBlockAlign; - pDS->pwfx->cbSize = 0; - - /* If the driver requests being opened through MMSYSTEM - * (which is recommended by the DDK), it is supposed to happen - * before the DirectSound interface is opened */ - if (pDS->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMOPEN) - { - DWORD flags = CALLBACK_FUNCTION; - - /* disable direct sound if requested */ - if (ds_hw_accel != DS_HW_ACCEL_EMULATION) - flags |= WAVE_DIRECTSOUND; - - err = mmErr(waveOutOpen(&(pDS->hwo), - pDS->drvdesc.dnDevNode, pDS->pwfx, - (DWORD)DSOUND_callback, (DWORD)pDS, - flags)); - if (err != DS_OK) { - WARN("waveOutOpen failed\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return err; - } - } - - if (drv) { - err = IDsDriver_Open(drv); - if (err != DS_OK) { - WARN("IDsDriver_Open failed\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return err; - } - - /* the driver is now open, so it's now allowed to call GetCaps */ - err = IDsDriver_GetCaps(drv,&(pDS->drvcaps)); - if (err != DS_OK) { - WARN("IDsDriver_GetCaps failed\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return err; - } - } else { - WAVEOUTCAPSA woc; - err = mmErr(waveOutGetDevCapsA(pDS->drvdesc.dnDevNode, &woc, sizeof(woc))); - if (err != DS_OK) { - WARN("waveOutGetDevCaps failed\n"); - HeapFree(GetProcessHeap(),0,pDS); - *ppDS = NULL; - return err; - } - ZeroMemory(&pDS->drvcaps, sizeof(pDS->drvcaps)); - if ((woc.dwFormats & WAVE_FORMAT_1M08) || - (woc.dwFormats & WAVE_FORMAT_2M08) || - (woc.dwFormats & WAVE_FORMAT_4M08) || - (woc.dwFormats & WAVE_FORMAT_48M08) || - (woc.dwFormats & WAVE_FORMAT_96M08)) { - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; - } - if ((woc.dwFormats & WAVE_FORMAT_1M16) || - (woc.dwFormats & WAVE_FORMAT_2M16) || - (woc.dwFormats & WAVE_FORMAT_4M16) || - (woc.dwFormats & WAVE_FORMAT_48M16) || - (woc.dwFormats & WAVE_FORMAT_96M16)) { - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARYMONO; - } - if ((woc.dwFormats & WAVE_FORMAT_1S08) || - (woc.dwFormats & WAVE_FORMAT_2S08) || - (woc.dwFormats & WAVE_FORMAT_4S08) || - (woc.dwFormats & WAVE_FORMAT_48S08) || - (woc.dwFormats & WAVE_FORMAT_96S08)) { - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARY8BIT; - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; - } - if ((woc.dwFormats & WAVE_FORMAT_1S16) || - (woc.dwFormats & WAVE_FORMAT_2S16) || - (woc.dwFormats & WAVE_FORMAT_4S16) || - (woc.dwFormats & WAVE_FORMAT_48S16) || - (woc.dwFormats & WAVE_FORMAT_96S16)) { - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARY16BIT; - pDS->drvcaps.dwFlags |= DSCAPS_PRIMARYSTEREO; - } - if (ds_emuldriver) - pDS->drvcaps.dwFlags |= DSCAPS_EMULDRIVER; - pDS->drvcaps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN; - pDS->drvcaps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX; - pDS->drvcaps.dwPrimaryBuffers = 1; - } - - InitializeCriticalSection(&(pDS->mixlock)); - pDS->mixlock.DebugInfo->Spare[1] = (DWORD)"DSOUND_mixlock"; - - RtlInitializeResource(&(pDS->buffer_list_lock)); + pDS->lpVtbl = &IDirectSoundImpl_Vtbl; + pDS->ref = 0; + pDS->device = NULL; *ppDS = (LPDIRECTSOUND8)pDS; return DS_OK; } + /******************************************************************************* * IDirectSound_IUnknown */ @@ -984,26 +1037,26 @@ static ULONG WINAPI IDirectSound_IUnknown_AddRef( LPUNKNOWN iface) { IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSound_IUnknown_Release( LPUNKNOWN iface) { IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; - ULONG ulReturn; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - if (ulReturn == 0) { + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + if (!ref) { IDirectSoundImpl_Release(This->pds); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); } - return ulReturn; + return ref; } -static IUnknownVtbl DirectSound_Unknown_Vtbl = +static const IUnknownVtbl DirectSound_Unknown_Vtbl = { IDirectSound_IUnknown_QueryInterface, IDirectSound_IUnknown_AddRef, @@ -1062,23 +1115,23 @@ static ULONG WINAPI IDirectSound_IDirectSound_AddRef( LPDIRECTSOUND iface) { IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSound_IDirectSound_Release( LPDIRECTSOUND iface) { IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; - ULONG ulReturn; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&This->ref); - if (ulReturn == 0) { + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + if (!ref) { IDirectSoundImpl_Release(This->pds); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); } - return ulReturn; + return ref; } static HRESULT WINAPI IDirectSound_IDirectSound_CreateSoundBuffer( @@ -1117,7 +1170,7 @@ static HRESULT WINAPI IDirectSound_IDirectSound_SetCooperativeLevel( DWORD level) { IDirectSound_IDirectSound *This = (IDirectSound_IDirectSound *)iface; - TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level)); + TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level); } @@ -1156,7 +1209,7 @@ static HRESULT WINAPI IDirectSound_IDirectSound_Initialize( return IDirectSoundImpl_Initialize(This->pds,lpcGuid); } -static IDirectSoundVtbl DirectSound_DirectSound_Vtbl = +static const IDirectSoundVtbl DirectSound_DirectSound_Vtbl = { IDirectSound_IDirectSound_QueryInterface, IDirectSound_IDirectSound_AddRef, @@ -1223,26 +1276,26 @@ static ULONG WINAPI IDirectSound8_IUnknown_AddRef( LPUNKNOWN iface) { IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSound8_IUnknown_Release( LPUNKNOWN iface) { IDirectSound_IUnknown *This = (IDirectSound_IUnknown *)iface; - ULONG ulReturn; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - if (ulReturn == 0) { + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + if (!ref) { IDirectSoundImpl_Release(This->pds); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); } - return ulReturn; + return ref; } -static IUnknownVtbl DirectSound8_Unknown_Vtbl = +static const IUnknownVtbl DirectSound8_Unknown_Vtbl = { IDirectSound8_IUnknown_QueryInterface, IDirectSound8_IUnknown_AddRef, @@ -1301,23 +1354,23 @@ static ULONG WINAPI IDirectSound8_IDirectSound_AddRef( LPDIRECTSOUND iface) { IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSound8_IDirectSound_Release( LPDIRECTSOUND iface) { IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; - ULONG ulReturn; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - if (ulReturn == 0) { + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + if (!ref) { IDirectSoundImpl_Release(This->pds); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); } - return ulReturn; + return ref; } static HRESULT WINAPI IDirectSound8_IDirectSound_CreateSoundBuffer( @@ -1356,7 +1409,7 @@ static HRESULT WINAPI IDirectSound8_IDirectSound_SetCooperativeLevel( DWORD level) { IDirectSound8_IDirectSound *This = (IDirectSound8_IDirectSound *)iface; - TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level)); + TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level); } @@ -1395,7 +1448,7 @@ static HRESULT WINAPI IDirectSound8_IDirectSound_Initialize( return IDirectSoundImpl_Initialize(This->pds,lpcGuid); } -static IDirectSoundVtbl DirectSound8_DirectSound_Vtbl = +static const IDirectSoundVtbl DirectSound8_DirectSound_Vtbl = { IDirectSound8_IDirectSound_QueryInterface, IDirectSound8_IDirectSound_AddRef, @@ -1462,23 +1515,23 @@ static ULONG WINAPI IDirectSound8_IDirectSound8_AddRef( LPDIRECTSOUND8 iface) { IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; } static ULONG WINAPI IDirectSound8_IDirectSound8_Release( LPDIRECTSOUND8 iface) { IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; - ULONG ulReturn; - TRACE("(%p) ref was %ld, thread is %04lx\n", This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - if (ulReturn == 0) { + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + if (!ref) { IDirectSoundImpl_Release(This->pds); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); } - return ulReturn; + return ref; } static HRESULT WINAPI IDirectSound8_IDirectSound8_CreateSoundBuffer( @@ -1517,7 +1570,7 @@ static HRESULT WINAPI IDirectSound8_IDirectSound8_SetCooperativeLevel( DWORD level) { IDirectSound8_IDirectSound8 *This = (IDirectSound8_IDirectSound8 *)iface; - TRACE("(%p,%08lx,%s)\n",This,(DWORD)hwnd,dumpCooperativeLevel(level)); + TRACE("(%p,%p,%s)\n",This,hwnd,dumpCooperativeLevel(level)); return IDirectSoundImpl_SetCooperativeLevel(This->pds,hwnd,level); } @@ -1565,7 +1618,7 @@ static HRESULT WINAPI IDirectSound8_IDirectSound8_VerifyCertification( return IDirectSoundImpl_VerifyCertification(This->pds,pdwCertified); } -static IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl = +static const IDirectSound8Vtbl DirectSound8_DirectSound8_Vtbl = { IDirectSound8_IDirectSound8_QueryInterface, IDirectSound8_IDirectSound8_AddRef, @@ -1617,74 +1670,28 @@ HRESULT WINAPI IDirectSound8_IDirectSound8_Create( } HRESULT WINAPI DSOUND_Create( - LPCGUID lpcGUID, LPDIRECTSOUND *ppDS, IUnknown *pUnkOuter) { + LPDIRECTSOUND8 pDS; HRESULT hr; - GUID devGuid; - - TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); - - if (pUnkOuter != NULL) { - WARN("invalid parameter: pUnkOuter != NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (ppDS == NULL) { - WARN("invalid parameter: ppDS == NULL\n"); - return DSERR_INVALIDPARAM; - } + TRACE("(%p,%p)\n",ppDS,pUnkOuter); /* Get dsound configuration */ setup_dsound_options(); - /* Default device? */ - if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) - lpcGUID = &DSDEVID_DefaultPlayback; - - if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) { - WARN("invalid parameter: lpcGUID\n"); - *ppDS = NULL; - return DSERR_INVALIDPARAM; - } - - if (dsound) { - if (IsEqualGUID(&devGuid, &dsound->guid)) { - hr = IDirectSound_IDirectSound_Create((LPDIRECTSOUND8)dsound, ppDS); - if (*ppDS) - IDirectSound_IDirectSound_AddRef(*ppDS); - else - WARN("IDirectSound_IDirectSound_Create failed\n"); - } else { - ERR("different dsound already opened (only support one sound card at a time now)\n"); - *ppDS = NULL; - hr = DSERR_ALLOCATED; + hr = IDirectSoundImpl_Create(&pDS); + if (hr == DS_OK) { + hr = IDirectSound_IDirectSound_Create(pDS, ppDS); + if (*ppDS) + IDirectSound_IDirectSound_AddRef(*ppDS); + else { + WARN("IDirectSound_IDirectSound_Create failed\n"); + IDirectSound8_Release(pDS); } } else { - LPDIRECTSOUND8 pDS; - hr = IDirectSoundImpl_Create(&devGuid, &pDS); - if (hr == DS_OK) { - hr = DSOUND_PrimaryCreate((IDirectSoundImpl*)pDS); - if (hr == DS_OK) { - hr = IDirectSound_IDirectSound_Create(pDS, ppDS); - if (*ppDS) { - IDirectSound_IDirectSound_AddRef(*ppDS); - - dsound = (IDirectSoundImpl*)pDS; - timeBeginPeriod(DS_TIME_RES); - dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer, - (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); - } else { - WARN("IDirectSound_IDirectSound_Create failed\n"); - IDirectSound8_Release(pDS); - } - } else { - WARN("DSOUND_PrimaryCreate failed\n"); - IDirectSound8_Release(pDS); - } - } else - WARN("IDirectSoundImpl_Create failed\n"); + WARN("IDirectSoundImpl_Create failed\n"); + *ppDS = 0; } return hr; @@ -1711,85 +1718,61 @@ HRESULT WINAPI DirectSoundCreate( IUnknown *pUnkOuter) { HRESULT hr; + LPDIRECTSOUND pDS; TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); - hr = DSOUND_Create(lpcGUID, ppDS, pUnkOuter); - if (hr == DS_OK) - IDirectSoundImpl_Initialize((LPDIRECTSOUND8)dsound, lpcGUID); - - return hr; -} - -HRESULT WINAPI DSOUND_Create8( - LPCGUID lpcGUID, - LPDIRECTSOUND8 *ppDS, - IUnknown *pUnkOuter) -{ - HRESULT hr; - GUID devGuid; - - TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); - - if (pUnkOuter != NULL) { - WARN("invalid parameter: pUnkOuter != NULL\n"); - return DSERR_INVALIDPARAM; - } - if (ppDS == NULL) { WARN("invalid parameter: ppDS == NULL\n"); return DSERR_INVALIDPARAM; } - /* Get dsound configuration */ - setup_dsound_options(); - - /* Default device? */ - if (!lpcGUID || IsEqualGUID(lpcGUID, &GUID_NULL)) - lpcGUID = &DSDEVID_DefaultPlayback; - - if (GetDeviceID(lpcGUID, &devGuid) != DS_OK) { - WARN("invalid parameter: lpcGUID\n"); - *ppDS = NULL; + if (pUnkOuter != NULL) { + WARN("invalid parameter: pUnkOuter != NULL\n"); + *ppDS = 0; return DSERR_INVALIDPARAM; } - if (dsound) { - if (IsEqualGUID(&devGuid, &dsound->guid)) { - hr = IDirectSound8_IDirectSound8_Create((LPDIRECTSOUND8)dsound, ppDS); - if (*ppDS) - IDirectSound8_IDirectSound8_AddRef(*ppDS); - else - WARN("IDirectSound8_IDirectSound8_Create failed\n"); - } else { - ERR("different dsound already opened (only support one sound card at a time now)\n"); - *ppDS = NULL; - hr = DSERR_ALLOCATED; + hr = DSOUND_Create(&pDS, pUnkOuter); + if (hr == DS_OK) { + hr = IDirectSound_Initialize(pDS, lpcGUID); + if (hr != DS_OK) { + if (hr != DSERR_ALREADYINITIALIZED) { + IDirectSound_Release(pDS); + pDS = 0; + } else + hr = DS_OK; + } + } + + *ppDS = pDS; + + return hr; +} + +HRESULT WINAPI DSOUND_Create8( + LPDIRECTSOUND8 *ppDS, + IUnknown *pUnkOuter) +{ + LPDIRECTSOUND8 pDS; + HRESULT hr; + TRACE("(%p,%p)\n",ppDS,pUnkOuter); + + /* Get dsound configuration */ + setup_dsound_options(); + + hr = IDirectSoundImpl_Create(&pDS); + if (hr == DS_OK) { + hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS); + if (*ppDS) + IDirectSound8_IDirectSound8_AddRef(*ppDS); + else { + WARN("IDirectSound8_IDirectSound8_Create failed\n"); + IDirectSound8_Release(pDS); } } else { - LPDIRECTSOUND8 pDS; - hr = IDirectSoundImpl_Create(&devGuid, &pDS); - if (hr == DS_OK) { - hr = DSOUND_PrimaryCreate((IDirectSoundImpl*)pDS); - if (hr == DS_OK) { - hr = IDirectSound8_IDirectSound8_Create(pDS, ppDS); - if (*ppDS) { - IDirectSound8_IDirectSound8_AddRef(*ppDS); - - dsound = (IDirectSoundImpl*)pDS; - timeBeginPeriod(DS_TIME_RES); - dsound->timerID = timeSetEvent(DS_TIME_DEL, DS_TIME_RES, DSOUND_timer, - (DWORD)dsound, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); - } else { - WARN("IDirectSound8_IDirectSound8_Create failed\n"); - IDirectSound8_Release(pDS); - } - } else { - WARN("DSOUND_PrimaryCreate failed\n"); - IDirectSound8_Release(pDS); - } - } else - WARN("IDirectSoundImpl_Create failed\n"); + WARN("IDirectSoundImpl_Create failed\n"); + *ppDS = 0; } return hr; @@ -1816,12 +1799,34 @@ HRESULT WINAPI DirectSoundCreate8( IUnknown *pUnkOuter) { HRESULT hr; + LPDIRECTSOUND8 pDS; TRACE("(%s,%p,%p)\n",debugstr_guid(lpcGUID),ppDS,pUnkOuter); - hr = DSOUND_Create8(lpcGUID, ppDS, pUnkOuter); - if (hr == DS_OK) - IDirectSoundImpl_Initialize((LPDIRECTSOUND8)dsound, lpcGUID); + if (ppDS == NULL) { + WARN("invalid parameter: ppDS == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (pUnkOuter != NULL) { + WARN("invalid parameter: pUnkOuter != NULL\n"); + *ppDS = 0; + return DSERR_INVALIDPARAM; + } + + hr = DSOUND_Create8(&pDS, pUnkOuter); + if (hr == DS_OK) { + hr = IDirectSound8_Initialize(pDS, lpcGUID); + if (hr != DS_OK) { + if (hr != DSERR_ALREADYINITIALIZED) { + IDirectSound8_Release(pDS); + pDS = 0; + } else + hr = DS_OK; + } + } + + *ppDS = pDS; return hr; } @@ -1839,24 +1844,24 @@ HRESULT DSOUND_AddBuffer( TRACE("(%p, %p)\n", pDS, pDSB); - RtlAcquireResourceExclusive(&(pDS->buffer_list_lock), TRUE); + RtlAcquireResourceExclusive(&(pDS->device->buffer_list_lock), TRUE); - if (pDS->buffers) - newbuffers = HeapReAlloc(GetProcessHeap(),0,pDS->buffers,sizeof(IDirectSoundBufferImpl*)*(pDS->nrofbuffers+1)); + if (pDS->device->buffers) + newbuffers = HeapReAlloc(GetProcessHeap(),0,pDS->device->buffers,sizeof(IDirectSoundBufferImpl*)*(pDS->device->nrofbuffers+1)); else - newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(pDS->nrofbuffers+1)); + newbuffers = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSoundBufferImpl*)*(pDS->device->nrofbuffers+1)); if (newbuffers) { - pDS->buffers = newbuffers; - pDS->buffers[pDS->nrofbuffers] = pDSB; - pDS->nrofbuffers++; - TRACE("buffer count is now %d\n", pDS->nrofbuffers); + pDS->device->buffers = newbuffers; + pDS->device->buffers[pDS->device->nrofbuffers] = pDSB; + pDS->device->nrofbuffers++; + TRACE("buffer count is now %d\n", pDS->device->nrofbuffers); } else { - ERR("out of memory for buffer list! Current buffer count is %d\n", pDS->nrofbuffers); + ERR("out of memory for buffer list! Current buffer count is %d\n", pDS->device->nrofbuffers); hr = DSERR_OUTOFMEMORY; } - RtlReleaseResource(&(pDS->buffer_list_lock)); + RtlReleaseResource(&(pDS->device->buffer_list_lock)); return hr; } @@ -1874,26 +1879,26 @@ HRESULT DSOUND_RemoveBuffer( TRACE("(%p, %p)\n", pDS, pDSB); - RtlAcquireResourceExclusive(&(pDS->buffer_list_lock), TRUE); + RtlAcquireResourceExclusive(&(pDS->device->buffer_list_lock), TRUE); - for (i = 0; i < pDS->nrofbuffers; i++) - if (pDS->buffers[i] == pDSB) + for (i = 0; i < pDS->device->nrofbuffers; i++) + if (pDS->device->buffers[i] == pDSB) break; - if (i < pDS->nrofbuffers) { + if (i < pDS->device->nrofbuffers) { /* Put the last buffer of the list in the (now empty) position */ - pDS->buffers[i] = pDS->buffers[pDS->nrofbuffers - 1]; - pDS->nrofbuffers--; - pDS->buffers = HeapReAlloc(GetProcessHeap(),0,pDS->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*pDS->nrofbuffers); - TRACE("buffer count is now %d\n", pDS->nrofbuffers); + pDS->device->buffers[i] = pDS->device->buffers[pDS->device->nrofbuffers - 1]; + pDS->device->nrofbuffers--; + pDS->device->buffers = HeapReAlloc(GetProcessHeap(),0,pDS->device->buffers,sizeof(LPDIRECTSOUNDBUFFER8)*pDS->device->nrofbuffers); + TRACE("buffer count is now %d\n", pDS->device->nrofbuffers); } - if (pDS->nrofbuffers == 0) { - HeapFree(GetProcessHeap(),0,pDS->buffers); - pDS->buffers = NULL; + if (pDS->device->nrofbuffers == 0) { + HeapFree(GetProcessHeap(),0,pDS->device->buffers); + pDS->device->buffers = NULL; } - RtlReleaseResource(&(pDS->buffer_list_lock)); + RtlReleaseResource(&(pDS->device->buffer_list_lock)); return hr; } diff --git a/reactos/lib/dsound/dsound.spec b/reactos/lib/dsound/dsound.spec index b1968752006..e4878a81692 100644 --- a/reactos/lib/dsound/dsound.spec +++ b/reactos/lib/dsound/dsound.spec @@ -1,14 +1,14 @@ -1 stdcall DirectSoundCreate(ptr ptr ptr) -2 stdcall DirectSoundEnumerateA(ptr ptr) -3 stdcall DirectSoundEnumerateW(ptr ptr) -4 stdcall -private DllCanUnloadNow() DSOUND_DllCanUnloadNow -5 stdcall -private DllGetClassObject(ptr ptr ptr) DSOUND_DllGetClassObject -6 stdcall DirectSoundCaptureCreate(ptr ptr ptr) DirectSoundCaptureCreate8 -7 stdcall DirectSoundCaptureEnumerateA(ptr ptr) -8 stdcall DirectSoundCaptureEnumerateW(ptr ptr) -9 stdcall GetDeviceID(ptr ptr) -10 stdcall DirectSoundFullDuplexCreate(ptr ptr ptr ptr long long ptr ptr ptr ptr) -11 stdcall DirectSoundCreate8(ptr ptr ptr) -12 stdcall DirectSoundCaptureCreate8(ptr ptr ptr) -@ stdcall -private DllRegisterServer() DSOUND_DllRegisterServer -@ stdcall -private DllUnregisterServer() DSOUND_DllUnregisterServer +1 stdcall DirectSoundCreate(ptr ptr ptr) +2 stdcall DirectSoundEnumerateA(ptr ptr) +3 stdcall DirectSoundEnumerateW(ptr ptr) +6 stdcall DirectSoundCaptureCreate(ptr ptr ptr) +7 stdcall DirectSoundCaptureEnumerateA(ptr ptr) +8 stdcall DirectSoundCaptureEnumerateW(ptr ptr) +9 stdcall GetDeviceID(ptr ptr) +10 stdcall DirectSoundFullDuplexCreate(ptr ptr ptr ptr long long ptr ptr ptr ptr) +11 stdcall DirectSoundCreate8(ptr ptr ptr) +12 stdcall DirectSoundCaptureCreate8(ptr ptr ptr) +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/reactos/lib/dsound/dsound.xml b/reactos/lib/dsound/dsound.xml index 69d552d321e..7fd857cd401 100644 --- a/reactos/lib/dsound/dsound.xml +++ b/reactos/lib/dsound/dsound.xml @@ -20,6 +20,7 @@ capture.c dsound.c dsound_main.c + duplex.c mixer.c primary.c propset.c diff --git a/reactos/lib/dsound/dsound_main.c b/reactos/lib/dsound/dsound_main.c index d276ae77a82..1f216b7a55f 100644 --- a/reactos/lib/dsound/dsound_main.c +++ b/reactos/lib/dsound/dsound_main.c @@ -1,699 +1,684 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * Most thread locking is complete. There may be a few race - * conditions still lurking. - * - * Tested with a Soundblaster clone, a Gravis UltraSound Classic, - * and a Turtle Beach Tropez+. - * - * TODO: - * Implement SetCooperativeLevel properly (need to address focus issues) - * Implement DirectSound3DBuffers (stubs in place) - * Use hardware 3D support if available - * Add critical section locking inside Release and AddRef methods - * Handle static buffers - put those in hardware, non-static not in hardware - * Hardware DuplicateSoundBuffer - * Proper volume calculation, and setting volume in HEL primary buffer - * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include - -#define COBJMACROS -#define NONAMELESSSTRUCT -#define NONAMELESSUNION - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winternl.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/winbase16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" -#include "dsconf.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - -/* these are eligible for tuning... they must be high on slow machines... */ -/* some stuff may get more responsive with lower values though... */ -#define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept - emulated dsound devices. set to 0 ! */ -#define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers - * (keep this close or equal to DS_HEL_QUEUE for best results) */ -#define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver - * (this will affect HEL sound reliability and latency) */ - -#define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */ -#define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */ - -IDirectSoundImpl* dsound = NULL; -GUID renderer_guids[MAXWAVEDRIVERS]; -GUID capture_guids[MAXWAVEDRIVERS]; - -HRESULT mmErr(UINT err) -{ - switch(err) { - case MMSYSERR_NOERROR: - return DS_OK; - case MMSYSERR_ALLOCATED: - return DSERR_ALLOCATED; - case MMSYSERR_ERROR: - case MMSYSERR_INVALHANDLE: - case WAVERR_STILLPLAYING: - return DSERR_GENERIC; /* FIXME */ - case MMSYSERR_NODRIVER: - return DSERR_NODRIVER; - case MMSYSERR_NOMEM: - return DSERR_OUTOFMEMORY; - case MMSYSERR_INVALPARAM: - case WAVERR_BADFORMAT: - case WAVERR_UNPREPARED: - return DSERR_INVALIDPARAM; - case MMSYSERR_NOTSUPPORTED: - return DSERR_UNSUPPORTED; - default: - FIXME("Unknown MMSYS error %d\n",err); - return DSERR_GENERIC; - } -} - -int ds_emuldriver = DS_EMULDRIVER; -int ds_hel_margin = DS_HEL_MARGIN; -int ds_hel_queue = DS_HEL_QUEUE; -int ds_snd_queue_max = DS_SND_QUEUE_MAX; -int ds_snd_queue_min = DS_SND_QUEUE_MIN; -int ds_hw_accel = DS_HW_ACCEL_FULL; -int ds_default_playback = 0; -int ds_default_capture = 0; - -/* - * Get a config key from either the app-specific or the default config - */ - -inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, - char *buffer, DWORD size ) -{ - if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0; - return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size ); -} - - -/* - * Setup the dsound options. - */ - -void setup_dsound_options(void) -{ - char buffer[MAX_PATH+1]; - HKEY hkey, appkey = 0; - DWORD len; - - buffer[MAX_PATH]='\0'; - - if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\dsound", 0, NULL, - REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL )) - { - ERR("Cannot create config registry key\n" ); - ExitProcess(1); - } - - len = GetModuleFileNameA( 0, buffer, MAX_PATH ); - if (len && len < MAX_PATH) - { - HKEY tmpkey; - - if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey )) - { - char appname[MAX_PATH+16]; - char *p = strrchr( buffer, '\\' ); - if (p!=NULL) { - appname[MAX_PATH]='\0'; - strncpy(appname,p+1,MAX_PATH); - strcat(appname,"\\dsound"); - TRACE("appname = [%s] \n",appname); - if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; - RegCloseKey( tmpkey ); - } - } - } - - /* get options */ - - if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH )) - ds_emuldriver = strcmp(buffer, "N"); - - if (!get_config_key( hkey, appkey, "HELmargin", buffer, MAX_PATH )) - ds_hel_margin = atoi(buffer); - - if (!get_config_key( hkey, appkey, "HELqueue", buffer, MAX_PATH )) - ds_hel_queue = atoi(buffer); - - if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH )) - ds_snd_queue_max = atoi(buffer); - - if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH )) - ds_snd_queue_min = atoi(buffer); - - if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { - if (strcmp(buffer, "Full") == 0) - ds_hw_accel = DS_HW_ACCEL_FULL; - else if (strcmp(buffer, "Standard") == 0) - ds_hw_accel = DS_HW_ACCEL_STANDARD; - else if (strcmp(buffer, "Basic") == 0) - ds_hw_accel = DS_HW_ACCEL_BASIC; - else if (strcmp(buffer, "Emulation") == 0) - ds_hw_accel = DS_HW_ACCEL_EMULATION; - } - FIXME("dsound are Hardcode to software emulation until we fix it in ros"); - ds_hw_accel = DS_HW_ACCEL_EMULATION; - - if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH )) - ds_default_playback = atoi(buffer); - - if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH )) - ds_default_capture = atoi(buffer); - - if (appkey) RegCloseKey( appkey ); - RegCloseKey( hkey ); - - if (ds_emuldriver != DS_EMULDRIVER ) - WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver, DS_EMULDRIVER); - if (ds_hel_margin != DS_HEL_MARGIN ) - WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin, DS_HEL_MARGIN ); - if (ds_hel_queue != DS_HEL_QUEUE ) - WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE ); - if (ds_snd_queue_max != DS_SND_QUEUE_MAX) - WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX); - if (ds_snd_queue_min != DS_SND_QUEUE_MIN) - WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN); - if (ds_hw_accel != DS_HW_ACCEL_FULL) - WARN("ds_hw_accel = %s (default=Full)\n", - ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : - ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" : - ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" : - ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" : - "Unknown"); - if (ds_default_playback != 0) - WARN("ds_default_playback = %d (default=0)\n",ds_default_playback); - if (ds_default_capture != 0) - WARN("ds_default_capture = %d (default=0)\n",ds_default_playback); -} - -const char * get_device_id(LPCGUID pGuid) -{ - if (IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid)) - return "DSDEVID_DefaultPlayback"; - else if (IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuid)) - return "DSDEVID_DefaultVoicePlayback"; - else if (IsEqualGUID(&DSDEVID_DefaultCapture, pGuid)) - return "DSDEVID_DefaultCapture"; - else if (IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuid)) - return "DSDEVID_DefaultVoiceCapture"; - return debugstr_guid(pGuid); -} - -/*************************************************************************** - * GetDeviceID [DSOUND.9] - * - * Retrieves unique identifier of default device specified - * - * PARAMS - * pGuidSrc [I] Address of device GUID. - * pGuidDest [O] Address to receive unique device GUID. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - * - * NOTES - * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback, - * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or - * DSDEVID_DefaultVoiceCapture. - * Returns pGuidSrc if pGuidSrc is a valid device or the device - * GUID for the specified constants. - */ -HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest) -{ - TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest); - - if ( pGuidSrc == NULL) { - WARN("invalid parameter: pGuidSrc == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if ( pGuidDest == NULL ) { - WARN("invalid parameter: pGuidDest == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) || - IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) { - memcpy(pGuidDest, &renderer_guids[ds_default_playback], sizeof(GUID)); - TRACE("returns %s\n", get_device_id(pGuidDest)); - return DS_OK; - } - - if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) || - IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) { - memcpy(pGuidDest, &capture_guids[ds_default_capture], sizeof(GUID)); - TRACE("returns %s\n", get_device_id(pGuidDest)); - return DS_OK; - } - - memcpy(pGuidDest, pGuidSrc, sizeof(GUID)); - TRACE("returns %s\n", get_device_id(pGuidDest)); - - return DS_OK; -} - - -/*************************************************************************** - * DirectSoundEnumerateA [DSOUND.2] - * - * Enumerate all DirectSound drivers installed in the system - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI DirectSoundEnumerateA( - LPDSENUMCALLBACKA lpDSEnumCallback, - LPVOID lpContext) -{ - unsigned devs, wod; - DSDRIVERDESC desc; - GUID guid; - int err; - - TRACE("lpDSEnumCallback = %p, lpContext = %p\n", - lpDSEnumCallback, lpContext); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveOutGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { - for (wod = 0; wod < devs; ++wod) { - if (IsEqualGUID( &guid, &renderer_guids[wod]) ) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Driver",desc.szDrvname,lpContext); - if (lpDSEnumCallback(NULL, "Primary Sound Driver", desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wod = 0; wod < devs; ++wod) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); - if (lpDSEnumCallback(&renderer_guids[wod], desc.szDesc, desc.szDrvname, lpContext) == FALSE) - return DS_OK; - } - } - return DS_OK; -} - -/*************************************************************************** - * DirectSoundEnumerateW [DSOUND.3] - * - * Enumerate all DirectSound drivers installed in the system - * - * PARAMS - * lpDSEnumCallback [I] Address of callback function. - * lpContext [I] Address of user defined context passed to callback function. - * - * RETURNS - * Success: DS_OK - * Failure: DSERR_INVALIDPARAM - */ -HRESULT WINAPI DirectSoundEnumerateW( - LPDSENUMCALLBACKW lpDSEnumCallback, - LPVOID lpContext ) -{ - unsigned devs, wod; - DSDRIVERDESC desc; - GUID guid; - int err; - WCHAR wDesc[MAXPNAMELEN]; - WCHAR wName[MAXPNAMELEN]; - - TRACE("lpDSEnumCallback = %p, lpContext = %p\n", - lpDSEnumCallback, lpContext); - - if (lpDSEnumCallback == NULL) { - WARN("invalid parameter: lpDSEnumCallback == NULL\n"); - return DSERR_INVALIDPARAM; - } - - devs = waveOutGetNumDevs(); - if (devs > 0) { - if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { - for (wod = 0; wod < devs; ++wod) { - if (IsEqualGUID( &guid, &renderer_guids[wod] ) ) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", - "Primary Sound Driver",desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - } - } - } - - for (wod = 0; wod < devs; ++wod) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", - debugstr_guid(&renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, - wDesc, sizeof(wDesc)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, - wName, sizeof(wName)/sizeof(WCHAR) ); - if (lpDSEnumCallback(&renderer_guids[wod], wDesc, wName, lpContext) == FALSE) - return DS_OK; - } - } - return DS_OK; -} - -/******************************************************************************* - * DirectSound ClassFactory - */ - -static HRESULT WINAPI -DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -DSCF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedDecrement(&(This->ref)); -} - -static HRESULT WINAPI DSCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj -) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return DSERR_INVALIDPARAM; - } - - *ppobj = NULL; - - if ( IsEqualIID( &IID_IDirectSound, riid ) ) - return DSOUND_Create(0,(LPDIRECTSOUND*)ppobj,pOuter); - - if ( IsEqualIID( &IID_IDirectSound8, riid ) ) - return DSOUND_Create8(0,(LPDIRECTSOUND8*)ppobj,pOuter); - - WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl DSCF_Vtbl = { - DSCF_QueryInterface, - DSCF_AddRef, - DSCF_Release, - DSCF_CreateInstance, - DSCF_LockServer -}; - -static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 }; - -/******************************************************************************* - * DirectSoundPrivate ClassFactory - */ - -static HRESULT WINAPI -DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -DSPCF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI -DSPCF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedDecrement(&(This->ref)); -} - -static HRESULT WINAPI -DSPCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj -) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return DSERR_INVALIDPARAM; - } - - *ppobj = NULL; - - if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { - return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl**)ppobj); - } - - WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static HRESULT WINAPI -DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl DSPCF_Vtbl = { - DSPCF_QueryInterface, - DSPCF_AddRef, - DSPCF_Release, - DSPCF_CreateInstance, - DSPCF_LockServer -}; - -static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 }; - -/******************************************************************************* - * DllGetClassObject [DSOUND.5] - * Retrieves class object from a DLL object - * - * NOTES - * Docs say returns STDAPI - * - * PARAMS - * rclsid [I] CLSID for the class object - * riid [I] Reference to identifier of interface for class object - * ppv [O] Address of variable to receive interface pointer for riid - * - * RETURNS - * Success: S_OK - * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, - * E_UNEXPECTED - */ -DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv) -{ - TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - - if (ppv == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppv = NULL; - - if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) || - IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) { - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DSOUND_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - WARN("(%s,%s,%p): no interface found.\n", - debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return S_FALSE; - } - - if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) || - IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) { - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DSOUND_CAPTURE_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - WARN("(%s,%s,%p): no interface found.\n", - debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return S_FALSE; - } - - if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) { - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - WARN("(%s,%s,%p): no interface found.\n", - debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return S_FALSE; - } - - if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) { - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DSOUND_PRIVATE_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - WARN("(%s,%s,%p): no interface found.\n", - debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return S_FALSE; - } - - WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return CLASS_E_CLASSNOTAVAILABLE; -} - - -/******************************************************************************* - * DllCanUnloadNow [DSOUND.4] - * Determines whether the DLL is in use. - * - * RETURNS - * Success: S_OK - * Failure: S_FALSE - */ -DWORD WINAPI DSOUND_DllCanUnloadNow(void) -{ - FIXME("(void): stub\n"); - return S_FALSE; -} - -#define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2; \ - guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3; \ - guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6; \ - guid.Data4[6] = b7; guid.Data4[7] = b8; - -/*********************************************************************** - * DllMain (DSOUND.init) - */ -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - int i; - TRACE("(%p 0x%lx %p)\n", hInstDLL, fdwReason, lpvReserved); - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - TRACE("DLL_PROCESS_ATTACH\n"); - for (i = 0; i < MAXWAVEDRIVERS; i++) { - INIT_GUID(renderer_guids[i], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); - INIT_GUID(capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); - } - break; - case DLL_PROCESS_DETACH: - TRACE("DLL_PROCESS_DETACH\n"); - break; - case DLL_THREAD_ATTACH: - TRACE("DLL_THREAD_ATTACH\n"); - break; - case DLL_THREAD_DETACH: - TRACE("DLL_THREAD_DETACH\n"); - break; - default: - TRACE("UNKNOWN REASON\n"); - break; - } - return TRUE; -} +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Most thread locking is complete. There may be a few race + * conditions still lurking. + * + * Tested with a Soundblaster clone, a Gravis UltraSound Classic, + * and a Turtle Beach Tropez+. + * + * TODO: + * Implement SetCooperativeLevel properly (need to address focus issues) + * Implement DirectSound3DBuffers (stubs in place) + * Use hardware 3D support if available + * Add critical section locking inside Release and AddRef methods + * Handle static buffers - put those in hardware, non-static not in hardware + * Hardware DuplicateSoundBuffer + * Proper volume calculation, and setting volume in HEL primary buffer + * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN + */ + +#include + +#define COBJMACROS +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "mmsystem.h" +#include "winternl.h" +#include "mmddk.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" +#include "dsconf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +/* these are eligible for tuning... they must be high on slow machines... */ +/* some stuff may get more responsive with lower values though... */ +#define DS_EMULDRIVER 0 /* some games (Quake 2, UT) refuse to accept + emulated dsound devices. set to 0 ! */ +#define DS_HEL_MARGIN 5 /* HEL only: number of waveOut fragments ahead to mix in new buffers + * (keep this close or equal to DS_HEL_QUEUE for best results) */ +#define DS_HEL_QUEUE 5 /* HEL only: number of waveOut fragments ahead to queue to driver + * (this will affect HEL sound reliability and latency) */ + +#define DS_SND_QUEUE_MAX 28 /* max number of fragments to prebuffer */ +#define DS_SND_QUEUE_MIN 12 /* min number of fragments to prebuffer */ + +DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS]; +GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; +GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; + +HRESULT mmErr(UINT err) +{ + switch(err) { + case MMSYSERR_NOERROR: + return DS_OK; + case MMSYSERR_ALLOCATED: + return DSERR_ALLOCATED; + case MMSYSERR_ERROR: + case MMSYSERR_INVALHANDLE: + case WAVERR_STILLPLAYING: + return DSERR_GENERIC; /* FIXME */ + case MMSYSERR_NODRIVER: + return DSERR_NODRIVER; + case MMSYSERR_NOMEM: + return DSERR_OUTOFMEMORY; + case MMSYSERR_INVALPARAM: + case WAVERR_BADFORMAT: + case WAVERR_UNPREPARED: + return DSERR_INVALIDPARAM; + case MMSYSERR_NOTSUPPORTED: + return DSERR_UNSUPPORTED; + default: + FIXME("Unknown MMSYS error %d\n",err); + return DSERR_GENERIC; + } +} + +int ds_emuldriver = DS_EMULDRIVER; +int ds_hel_margin = DS_HEL_MARGIN; +int ds_hel_queue = DS_HEL_QUEUE; +int ds_snd_queue_max = DS_SND_QUEUE_MAX; +int ds_snd_queue_min = DS_SND_QUEUE_MIN; +int ds_hw_accel = DS_HW_ACCEL_FULL; +int ds_default_playback = 0; +int ds_default_capture = 0; + +/* + * Get a config key from either the app-specific or the default config + */ + +inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, + char *buffer, DWORD size ) +{ + if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; + return ERROR_FILE_NOT_FOUND; +} + + +/* + * Setup the dsound options. + */ + +void setup_dsound_options(void) +{ + char buffer[MAX_PATH+16]; + HKEY hkey, appkey = 0; + DWORD len; + + buffer[MAX_PATH]='\0'; + + /* @@ Wine registry key: HKCU\Software\Wine\DirectSound */ + if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DirectSound", &hkey )) hkey = 0; + + len = GetModuleFileNameA( 0, buffer, MAX_PATH ); + if (len && len < MAX_PATH) + { + HKEY tmpkey; + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectSound */ + if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) + { + char *p, *appname = buffer; + if ((p = strrchr( appname, '/' ))) appname = p + 1; + if ((p = strrchr( appname, '\\' ))) appname = p + 1; + strcat( appname, "\\DirectSound" ); + TRACE("appname = [%s] \n",appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + RegCloseKey( tmpkey ); + } + } + + /* get options */ + + if (!get_config_key( hkey, appkey, "EmulDriver", buffer, MAX_PATH )) + ds_emuldriver = strcmp(buffer, "N"); + + if (!get_config_key( hkey, appkey, "HELmargin", buffer, MAX_PATH )) + ds_hel_margin = atoi(buffer); + + if (!get_config_key( hkey, appkey, "HELqueue", buffer, MAX_PATH )) + ds_hel_queue = atoi(buffer); + + if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH )) + ds_snd_queue_max = atoi(buffer); + + if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH )) + ds_snd_queue_min = atoi(buffer); + + if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { + if (strcmp(buffer, "Full") == 0) + ds_hw_accel = DS_HW_ACCEL_FULL; + else if (strcmp(buffer, "Standard") == 0) + ds_hw_accel = DS_HW_ACCEL_STANDARD; + else if (strcmp(buffer, "Basic") == 0) + ds_hw_accel = DS_HW_ACCEL_BASIC; + else if (strcmp(buffer, "Emulation") == 0) + ds_hw_accel = DS_HW_ACCEL_EMULATION; + } + FIXME("dsound are Hardcode to software emulation until we fix it in ros"); + ds_hw_accel = DS_HW_ACCEL_EMULATION; + + if (!get_config_key( hkey, appkey, "DefaultPlayback", buffer, MAX_PATH )) + ds_default_playback = atoi(buffer); + + if (!get_config_key( hkey, appkey, "DefaultCapture", buffer, MAX_PATH )) + ds_default_capture = atoi(buffer); + + if (appkey) RegCloseKey( appkey ); + if (hkey) RegCloseKey( hkey ); + + if (ds_emuldriver != DS_EMULDRIVER ) + WARN("ds_emuldriver = %d (default=%d)\n",ds_emuldriver, DS_EMULDRIVER); + if (ds_hel_margin != DS_HEL_MARGIN ) + WARN("ds_hel_margin = %d (default=%d)\n",ds_hel_margin, DS_HEL_MARGIN ); + if (ds_hel_queue != DS_HEL_QUEUE ) + WARN("ds_hel_queue = %d (default=%d)\n",ds_hel_queue, DS_HEL_QUEUE ); + if (ds_snd_queue_max != DS_SND_QUEUE_MAX) + WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX); + if (ds_snd_queue_min != DS_SND_QUEUE_MIN) + WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN); + if (ds_hw_accel != DS_HW_ACCEL_FULL) + WARN("ds_hw_accel = %s (default=Full)\n", + ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : + ds_hw_accel==DS_HW_ACCEL_STANDARD ? "Standard" : + ds_hw_accel==DS_HW_ACCEL_BASIC ? "Basic" : + ds_hw_accel==DS_HW_ACCEL_EMULATION ? "Emulation" : + "Unknown"); + if (ds_default_playback != 0) + WARN("ds_default_playback = %d (default=0)\n",ds_default_playback); + if (ds_default_capture != 0) + WARN("ds_default_capture = %d (default=0)\n",ds_default_playback); +} + +const char * get_device_id(LPCGUID pGuid) +{ + if (IsEqualGUID(&DSDEVID_DefaultPlayback, pGuid)) + return "DSDEVID_DefaultPlayback"; + else if (IsEqualGUID(&DSDEVID_DefaultVoicePlayback, pGuid)) + return "DSDEVID_DefaultVoicePlayback"; + else if (IsEqualGUID(&DSDEVID_DefaultCapture, pGuid)) + return "DSDEVID_DefaultCapture"; + else if (IsEqualGUID(&DSDEVID_DefaultVoiceCapture, pGuid)) + return "DSDEVID_DefaultVoiceCapture"; + return debugstr_guid(pGuid); +} + +/*************************************************************************** + * GetDeviceID [DSOUND.9] + * + * Retrieves unique identifier of default device specified + * + * PARAMS + * pGuidSrc [I] Address of device GUID. + * pGuidDest [O] Address to receive unique device GUID. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + * + * NOTES + * pGuidSrc is a valid device GUID or DSDEVID_DefaultPlayback, + * DSDEVID_DefaultCapture, DSDEVID_DefaultVoicePlayback, or + * DSDEVID_DefaultVoiceCapture. + * Returns pGuidSrc if pGuidSrc is a valid device or the device + * GUID for the specified constants. + */ +HRESULT WINAPI GetDeviceID(LPCGUID pGuidSrc, LPGUID pGuidDest) +{ + TRACE("(%s,%p)\n", get_device_id(pGuidSrc),pGuidDest); + + if ( pGuidSrc == NULL) { + WARN("invalid parameter: pGuidSrc == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if ( pGuidDest == NULL ) { + WARN("invalid parameter: pGuidDest == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if ( IsEqualGUID( &DSDEVID_DefaultPlayback, pGuidSrc ) || + IsEqualGUID( &DSDEVID_DefaultVoicePlayback, pGuidSrc ) ) { + CopyMemory(pGuidDest, &DSOUND_renderer_guids[ds_default_playback], sizeof(GUID)); + TRACE("returns %s\n", get_device_id(pGuidDest)); + return DS_OK; + } + + if ( IsEqualGUID( &DSDEVID_DefaultCapture, pGuidSrc ) || + IsEqualGUID( &DSDEVID_DefaultVoiceCapture, pGuidSrc ) ) { + CopyMemory(pGuidDest, &DSOUND_capture_guids[ds_default_capture], sizeof(GUID)); + TRACE("returns %s\n", get_device_id(pGuidDest)); + return DS_OK; + } + + CopyMemory(pGuidDest, pGuidSrc, sizeof(GUID)); + TRACE("returns %s\n", get_device_id(pGuidDest)); + + return DS_OK; +} + + +/*************************************************************************** + * DirectSoundEnumerateA [DSOUND.2] + * + * Enumerate all DirectSound drivers installed in the system + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI DirectSoundEnumerateA( + LPDSENUMCALLBACKA lpDSEnumCallback, + LPVOID lpContext) +{ + unsigned devs, wod; + DSDRIVERDESC desc; + GUID guid; + int err; + + TRACE("lpDSEnumCallback = %p, lpContext = %p\n", + lpDSEnumCallback, lpContext); + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + devs = waveOutGetNumDevs(); + if (devs > 0) { + if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { + for (wod = 0; wod < devs; ++wod) { + if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod]) ) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", + "Primary Sound Driver",desc.szDrvname,lpContext); + if (lpDSEnumCallback(NULL, "Primary Sound Driver", desc.szDrvname, lpContext) == FALSE) + return DS_OK; + } + } + } + } + } + + for (wod = 0; wod < devs; ++wod) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", + debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); + if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], desc.szDesc, desc.szDrvname, lpContext) == FALSE) + return DS_OK; + } + } + return DS_OK; +} + +/*************************************************************************** + * DirectSoundEnumerateW [DSOUND.3] + * + * Enumerate all DirectSound drivers installed in the system + * + * PARAMS + * lpDSEnumCallback [I] Address of callback function. + * lpContext [I] Address of user defined context passed to callback function. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_INVALIDPARAM + */ +HRESULT WINAPI DirectSoundEnumerateW( + LPDSENUMCALLBACKW lpDSEnumCallback, + LPVOID lpContext ) +{ + unsigned devs, wod; + DSDRIVERDESC desc; + GUID guid; + int err; + WCHAR wDesc[MAXPNAMELEN]; + WCHAR wName[MAXPNAMELEN]; + + TRACE("lpDSEnumCallback = %p, lpContext = %p\n", + lpDSEnumCallback, lpContext); + + if (lpDSEnumCallback == NULL) { + WARN("invalid parameter: lpDSEnumCallback == NULL\n"); + return DSERR_INVALIDPARAM; + } + + devs = waveOutGetNumDevs(); + if (devs > 0) { + if (GetDeviceID(&DSDEVID_DefaultPlayback, &guid) == DS_OK) { + for (wod = 0; wod < devs; ++wod) { + if (IsEqualGUID( &guid, &DSOUND_renderer_guids[wod] ) ) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(NULL,\"%s\",\"%s\",%p)\n", + "Primary Sound Driver",desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, "Primary Sound Driver", -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback(NULL, wDesc, wName, lpContext) == FALSE) + return DS_OK; + } + } + } + } + } + + for (wod = 0; wod < devs; ++wod) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + TRACE("calling lpDSEnumCallback(%s,\"%s\",\"%s\",%p)\n", + debugstr_guid(&DSOUND_renderer_guids[wod]),desc.szDesc,desc.szDrvname,lpContext); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, + wDesc, sizeof(wDesc)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, + wName, sizeof(wName)/sizeof(WCHAR) ); + if (lpDSEnumCallback(&DSOUND_renderer_guids[wod], wDesc, wName, lpContext) == FALSE) + return DS_OK; + } + } + return DS_OK; +} + +/******************************************************************************* + * DirectSound ClassFactory + */ + +static HRESULT WINAPI +DSCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI DSCF_AddRef(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI DSCF_Release(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + /* static class, won't be freed */ + return ref; +} + +static HRESULT WINAPI DSCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + if (pOuter) + return CLASS_E_NOAGGREGATION; + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return DSERR_INVALIDPARAM; + } + + *ppobj = NULL; + + if ( IsEqualIID( &IID_IDirectSound, riid ) ) + return DSOUND_Create((LPDIRECTSOUND*)ppobj,pOuter); + + if ( IsEqualIID( &IID_IDirectSound8, riid ) ) + return DSOUND_Create8((LPDIRECTSOUND8*)ppobj,pOuter); + + WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DSCF_Vtbl = { + DSCF_QueryInterface, + DSCF_AddRef, + DSCF_Release, + DSCF_CreateInstance, + DSCF_LockServer +}; + +static IClassFactoryImpl DSOUND_CF = { &DSCF_Vtbl, 1 }; + +/******************************************************************************* + * DirectSoundPrivate ClassFactory + */ + +static HRESULT WINAPI +DSPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI DSPCF_AddRef(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI DSPCF_Release(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + /* static class, won't be freed */ + return ref; +} + +static HRESULT WINAPI +DSPCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return DSERR_INVALIDPARAM; + } + + *ppobj = NULL; + + if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { + return IKsPrivatePropertySetImpl_Create((IKsPrivatePropertySetImpl**)ppobj); + } + + WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI +DSPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DSPCF_Vtbl = { + DSPCF_QueryInterface, + DSPCF_AddRef, + DSPCF_Release, + DSPCF_CreateInstance, + DSPCF_LockServer +}; + +static IClassFactoryImpl DSOUND_PRIVATE_CF = { &DSPCF_Vtbl, 1 }; + +/******************************************************************************* + * DllGetClassObject [DSOUND.@] + * Retrieves class object from a DLL object + * + * NOTES + * Docs say returns STDAPI + * + * PARAMS + * rclsid [I] CLSID for the class object + * riid [I] Reference to identifier of interface for class object + * ppv [O] Address of variable to receive interface pointer for riid + * + * RETURNS + * Success: S_OK + * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, + * E_UNEXPECTED + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if (ppv == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppv = NULL; + + if ( IsEqualCLSID( &CLSID_DirectSound, rclsid ) || + IsEqualCLSID( &CLSID_DirectSound8, rclsid ) ) { + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DSOUND_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + WARN("(%s,%s,%p): no interface found.\n", + debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return S_FALSE; + } + + if ( IsEqualCLSID( &CLSID_DirectSoundCapture, rclsid ) || + IsEqualCLSID( &CLSID_DirectSoundCapture8, rclsid ) ) { + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DSOUND_CAPTURE_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + WARN("(%s,%s,%p): no interface found.\n", + debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return S_FALSE; + } + + if ( IsEqualCLSID( &CLSID_DirectSoundFullDuplex, rclsid ) ) { + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DSOUND_FULLDUPLEX_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + WARN("(%s,%s,%p): no interface found.\n", + debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return S_FALSE; + } + + if ( IsEqualCLSID( &CLSID_DirectSoundPrivate, rclsid ) ) { + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DSOUND_PRIVATE_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + WARN("(%s,%s,%p): no interface found.\n", + debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return S_FALSE; + } + + WARN("(%s,%s,%p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} + + +/******************************************************************************* + * DllCanUnloadNow [DSOUND.4] + * Determines whether the DLL is in use. + * + * RETURNS + * Success: S_OK + * Failure: S_FALSE + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + FIXME("(void): stub\n"); + return S_FALSE; +} + +#define INIT_GUID(guid, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + guid.Data1 = l; guid.Data2 = w1; guid.Data3 = w2; \ + guid.Data4[0] = b1; guid.Data4[1] = b2; guid.Data4[2] = b3; \ + guid.Data4[3] = b4; guid.Data4[4] = b5; guid.Data4[5] = b6; \ + guid.Data4[6] = b7; guid.Data4[7] = b8; + +/*********************************************************************** + * DllMain (DSOUND.init) + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + int i; + TRACE("(%p %ld %p)\n", hInstDLL, fdwReason, lpvReserved); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + TRACE("DLL_PROCESS_ATTACH\n"); + for (i = 0; i < MAXWAVEDRIVERS; i++) { + DSOUND_renderer[i] = NULL; + DSOUND_capture[i] = NULL; + INIT_GUID(DSOUND_renderer_guids[i], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); + INIT_GUID(DSOUND_capture_guids[i], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + i); + } + break; + case DLL_PROCESS_DETACH: + TRACE("DLL_PROCESS_DETACH\n"); + break; + case DLL_THREAD_ATTACH: + TRACE("DLL_THREAD_ATTACH\n"); + break; + case DLL_THREAD_DETACH: + TRACE("DLL_THREAD_DETACH\n"); + break; + default: + TRACE("UNKNOWN REASON\n"); + break; + } + return TRUE; +} diff --git a/reactos/lib/dsound/dsound_private.h b/reactos/lib/dsound/dsound_private.h index 87b87db87f8..76f91cf7f04 100644 --- a/reactos/lib/dsound/dsound_private.h +++ b/reactos/lib/dsound/dsound_private.h @@ -1,506 +1,526 @@ -/* DirectSound - * - * Copyright 1998 Marcus Meissner - * Copyright 1998 Rob Riggs - * Copyright 2000-2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Linux does not support better timing than 10ms */ -#define DS_TIME_RES 10 /* Resolution of multimedia timer */ -#define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */ - -#define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer - * (changing this won't help you) */ - -/* wine spec */ -#include "dxroslayer/dxros_layer.h" - - -/* direct sound hardware acceleration levels */ -#define DS_HW_ACCEL_FULL 0 /* default on Windows 98 */ -#define DS_HW_ACCEL_STANDARD 1 /* default on Windows 2000 */ -#define DS_HW_ACCEL_BASIC 2 -#define DS_HW_ACCEL_EMULATION 3 - -extern int ds_emuldriver; -extern int ds_hel_margin; -extern int ds_hel_queue; -extern int ds_snd_queue_max; -extern int ds_snd_queue_min; -extern int ds_hw_accel; -extern int ds_default_playback; -extern int ds_default_capture; - -/***************************************************************************** - * Predeclare the interface implementation structures - */ -typedef struct IDirectSoundImpl IDirectSoundImpl; -typedef struct IDirectSound_IUnknown IDirectSound_IUnknown; -typedef struct IDirectSound_IDirectSound IDirectSound_IDirectSound; -typedef struct IDirectSound8_IUnknown IDirectSound8_IUnknown; -typedef struct IDirectSound8_IDirectSound IDirectSound8_IDirectSound; -typedef struct IDirectSound8_IDirectSound8 IDirectSound8_IDirectSound8; -typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl; -typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl; -typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl; -typedef struct IDirectSoundFullDuplexImpl IDirectSoundFullDuplexImpl; -typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl; -typedef struct IDirectSoundCaptureNotifyImpl IDirectSoundCaptureNotifyImpl; -typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl; -typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl; -typedef struct IKsBufferPropertySetImpl IKsBufferPropertySetImpl; -typedef struct IKsPrivatePropertySetImpl IKsPrivatePropertySetImpl; -typedef struct PrimaryBufferImpl PrimaryBufferImpl; -typedef struct SecondaryBufferImpl SecondaryBufferImpl; -typedef struct IClassFactoryImpl IClassFactoryImpl; - -/***************************************************************************** - * IDirectSound implementation structure - */ -struct IDirectSoundImpl -{ - /* IUnknown fields */ - IDirectSound8Vtbl *lpVtbl; - DWORD ref; - /* IDirectSoundImpl fields */ - GUID guid; - PIDSDRIVER driver; - DSDRIVERDESC drvdesc; - DSDRIVERCAPS drvcaps; - DWORD priolevel; - PWAVEFORMATEX pwfx; - HWAVEOUT hwo; - LPWAVEHDR pwave[DS_HEL_FRAGS]; - UINT timerID, pwplay, pwwrite, pwqueue, prebuf, precount; - DWORD fraglen; - PIDSDRIVERBUFFER hwbuf; - LPBYTE buffer; - DWORD writelead, buflen, state, playpos, mixpos; - BOOL need_remix; - int nrofbuffers; - IDirectSoundBufferImpl** buffers; - RTL_RWLOCK buffer_list_lock; - CRITICAL_SECTION mixlock; - PrimaryBufferImpl* primary; - DSBUFFERDESC dsbd; - DWORD speaker_config; - BOOL initialized; - - /* DirectSound3DListener fields */ - IDirectSound3DListenerImpl* listener; - DS3DLISTENER ds3dl; - BOOL ds3dl_need_recalc; - - LPUNKNOWN pUnknown; - LPDIRECTSOUND pDS; - LPDIRECTSOUND8 pDS8; -}; - -/* reference counted buffer memory for duplicated buffer memory */ -typedef struct BufferMemory -{ - DWORD ref; - LPBYTE memory; -} BufferMemory; - -HRESULT WINAPI IDirectSoundImpl_Create( - LPCGUID lpcGUID, - LPDIRECTSOUND8 * ppds); - -HRESULT WINAPI DSOUND_Create( - LPCGUID lpcGUID, - LPDIRECTSOUND *ppDS, - IUnknown *pUnkOuter); - -HRESULT WINAPI DSOUND_Create8( - LPCGUID lpcGUID, - LPDIRECTSOUND8 *ppDS, - IUnknown *pUnkOuter); - -/***************************************************************************** - * IDirectSound COM components - */ -struct IDirectSound_IUnknown { - IUnknownVtbl *lpVtbl; - DWORD ref; - LPDIRECTSOUND8 pds; -}; - -HRESULT WINAPI IDirectSound_IUnknown_Create( - LPDIRECTSOUND8 pds, - LPUNKNOWN * ppunk); - -struct IDirectSound_IDirectSound { - IDirectSoundVtbl *lpVtbl; - DWORD ref; - LPDIRECTSOUND8 pds; -}; - -HRESULT WINAPI IDirectSound_IDirectSound_Create( - LPDIRECTSOUND8 pds, - LPDIRECTSOUND * ppds); - -/***************************************************************************** - * IDirectSound8 COM components - */ -struct IDirectSound8_IUnknown { - IUnknownVtbl *lpVtbl; - DWORD ref; - LPDIRECTSOUND8 pds; -}; - -HRESULT WINAPI IDirectSound8_IUnknown_Create( - LPDIRECTSOUND8 pds, - LPUNKNOWN * ppunk); - -struct IDirectSound8_IDirectSound { - IDirectSoundVtbl *lpVtbl; - DWORD ref; - LPDIRECTSOUND8 pds; -}; - -HRESULT WINAPI IDirectSound8_IDirectSound_Create( - LPDIRECTSOUND8 pds, - LPDIRECTSOUND * ppds); - -struct IDirectSound8_IDirectSound8 { - IDirectSound8Vtbl *lpVtbl; - DWORD ref; - LPDIRECTSOUND8 pds; -}; - -HRESULT WINAPI IDirectSound8_IDirectSound8_Create( - LPDIRECTSOUND8 pds, - LPDIRECTSOUND8 * ppds); - -/***************************************************************************** - * IDirectSoundBuffer implementation structure - */ -struct IDirectSoundBufferImpl -{ - /* FIXME: document */ - /* IUnknown fields */ - IDirectSoundBuffer8Vtbl *lpVtbl; - DWORD ref; - /* IDirectSoundBufferImpl fields */ - SecondaryBufferImpl* dsb; - IDirectSoundImpl* dsound; - CRITICAL_SECTION lock; - PIDSDRIVERBUFFER hwbuf; - PWAVEFORMATEX pwfx; - BufferMemory* buffer; - DWORD playflags,state,leadin; - DWORD playpos,startpos,writelead,buflen; - DWORD nAvgBytesPerSec; - DWORD freq; - DSVOLUMEPAN volpan, cvolpan; - DSBUFFERDESC dsbd; - /* used for frequency conversion (PerfectPitch) */ - ULONG freqAdjust, freqAcc; - /* used for intelligent (well, sort of) prebuffering */ - DWORD probably_valid_to, last_playpos; - DWORD primary_mixpos, buf_mixpos; - BOOL need_remix; - - /* IDirectSoundNotifyImpl fields */ - IDirectSoundNotifyImpl* notify; - LPDSBPOSITIONNOTIFY notifies; - int nrofnotifies; - PIDSDRIVERNOTIFY hwnotify; - - /* DirectSound3DBuffer fields */ - IDirectSound3DBufferImpl* ds3db; - DS3DBUFFER ds3db_ds3db; - LONG ds3db_lVolume; - BOOL ds3db_need_recalc; - - /* IKsPropertySet fields */ - IKsBufferPropertySetImpl* iks; -}; - -HRESULT WINAPI IDirectSoundBufferImpl_Create( - IDirectSoundImpl *ds, - IDirectSoundBufferImpl **pdsb, - LPCDSBUFFERDESC dsbd); -HRESULT WINAPI IDirectSoundBufferImpl_Destroy( - IDirectSoundBufferImpl *pdsb); - -/***************************************************************************** - * SecondaryBuffer implementation structure - */ -struct SecondaryBufferImpl -{ - IDirectSoundBuffer8Vtbl *lpVtbl; - DWORD ref; - IDirectSoundBufferImpl* dsb; -}; - -HRESULT WINAPI SecondaryBufferImpl_Create( - IDirectSoundBufferImpl *dsb, - SecondaryBufferImpl **pdsb); -HRESULT WINAPI SecondaryBufferImpl_Destroy( - SecondaryBufferImpl *pdsb); - -/***************************************************************************** - * PrimaryBuffer implementation structure - */ -struct PrimaryBufferImpl -{ - IDirectSoundBuffer8Vtbl *lpVtbl; - DWORD ref; - IDirectSoundImpl* dsound; -}; - -HRESULT WINAPI PrimaryBufferImpl_Create( - IDirectSoundImpl *ds, - PrimaryBufferImpl **pdsb, - LPCDSBUFFERDESC dsbd); - -/***************************************************************************** - * IDirectSoundCapture implementation structure - */ -struct IDirectSoundCaptureImpl -{ - /* IUnknown fields */ - IDirectSoundCaptureVtbl *lpVtbl; - DWORD ref; - - /* IDirectSoundCaptureImpl fields */ - GUID guid; - BOOL initialized; - - /* DirectSound driver stuff */ - PIDSCDRIVER driver; - DSDRIVERDESC drvdesc; - DSCDRIVERCAPS drvcaps; - PIDSCDRIVERBUFFER hwbuf; - - /* wave driver info */ - HWAVEIN hwi; - - /* more stuff */ - LPBYTE buffer; - DWORD buflen; - DWORD read_position; - - PWAVEFORMATEX pwfx; - - IDirectSoundCaptureBufferImpl* capture_buffer; - DWORD state; - LPWAVEHDR pwave; - int nrofpwaves; - int index; - CRITICAL_SECTION lock; -}; - -/***************************************************************************** - * IDirectSoundCaptureBuffer implementation structure - */ -struct IDirectSoundCaptureBufferImpl -{ - /* IUnknown fields */ - IDirectSoundCaptureBuffer8Vtbl *lpVtbl; - DWORD ref; - - /* IDirectSoundCaptureBufferImpl fields */ - IDirectSoundCaptureImpl* dsound; - /* FIXME: don't need this */ - LPDSCBUFFERDESC pdscbd; - DWORD flags; - - /* IDirectSoundCaptureNotifyImpl fields */ - IDirectSoundCaptureNotifyImpl* notify; - LPDSBPOSITIONNOTIFY notifies; - int nrofnotifies; - PIDSDRIVERNOTIFY hwnotify; -}; - -/***************************************************************************** - * IDirectSoundFullDuplex implementation structure - */ -struct IDirectSoundFullDuplexImpl -{ - /* IUnknown fields */ - IDirectSoundFullDuplexVtbl *lpVtbl; - DWORD ref; - - /* IDirectSoundFullDuplexImpl fields */ - CRITICAL_SECTION lock; -}; - -/***************************************************************************** - * IDirectSoundNotify implementation structure - */ -struct IDirectSoundNotifyImpl -{ - /* IUnknown fields */ - IDirectSoundNotifyVtbl *lpVtbl; - DWORD ref; - IDirectSoundBufferImpl* dsb; -}; - -HRESULT WINAPI IDirectSoundNotifyImpl_Create( - IDirectSoundBufferImpl *dsb, - IDirectSoundNotifyImpl **pdsn); -HRESULT WINAPI IDirectSoundNotifyImpl_Destroy( - IDirectSoundNotifyImpl *pdsn); - -/***************************************************************************** - * IDirectSoundCaptureNotify implementation structure - */ -struct IDirectSoundCaptureNotifyImpl -{ - /* IUnknown fields */ - IDirectSoundNotifyVtbl *lpVtbl; - DWORD ref; - IDirectSoundCaptureBufferImpl* dscb; -}; - -HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create( - IDirectSoundCaptureBufferImpl *dscb, - IDirectSoundCaptureNotifyImpl ** pdscn); - -/***************************************************************************** - * IDirectSound3DListener implementation structure - */ -struct IDirectSound3DListenerImpl -{ - /* IUnknown fields */ - IDirectSound3DListenerVtbl *lpVtbl; - DWORD ref; - /* IDirectSound3DListenerImpl fields */ - IDirectSoundImpl* dsound; -}; - -HRESULT WINAPI IDirectSound3DListenerImpl_Create( - PrimaryBufferImpl *pb, - IDirectSound3DListenerImpl **pdsl); - -/***************************************************************************** - * IKsBufferPropertySet implementation structure - */ -struct IKsBufferPropertySetImpl -{ - /* IUnknown fields */ - IKsPropertySetVtbl *lpVtbl; - DWORD ref; - /* IKsPropertySetImpl fields */ - IDirectSoundBufferImpl* dsb; -}; - -HRESULT WINAPI IKsBufferPropertySetImpl_Create( - IDirectSoundBufferImpl *dsb, - IKsBufferPropertySetImpl **piks); -HRESULT WINAPI IKsBufferPropertySetImpl_Destroy( - IKsBufferPropertySetImpl *piks); - -/***************************************************************************** - * IKsPrivatePropertySet implementation structure - */ -struct IKsPrivatePropertySetImpl -{ - /* IUnknown fields */ - IKsPropertySetVtbl *lpVtbl; - DWORD ref; -}; - -HRESULT WINAPI IKsPrivatePropertySetImpl_Create( - IKsPrivatePropertySetImpl **piks); - -/***************************************************************************** - * IDirectSound3DBuffer implementation structure - */ -struct IDirectSound3DBufferImpl -{ - /* IUnknown fields */ - IDirectSound3DBufferVtbl *lpVtbl; - DWORD ref; - /* IDirectSound3DBufferImpl fields */ - IDirectSoundBufferImpl* dsb; -}; - -HRESULT WINAPI IDirectSound3DBufferImpl_Create( - IDirectSoundBufferImpl *dsb, - IDirectSound3DBufferImpl **pds3db); -HRESULT WINAPI IDirectSound3DBufferImpl_Destroy( - IDirectSound3DBufferImpl *pds3db); - -/******************************************************************************* - * DirectSound ClassFactory implementation structure - */ -struct IClassFactoryImpl -{ - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; -}; - -extern IClassFactoryImpl DSOUND_CAPTURE_CF; -extern IClassFactoryImpl DSOUND_FULLDUPLEX_CF; - -void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan); -void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan); -void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb); - -/* dsound.c */ - -HRESULT DSOUND_AddBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB); -HRESULT DSOUND_RemoveBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB); - -/* primary.c */ - -HRESULT DSOUND_PrimaryCreate(IDirectSoundImpl *This); -HRESULT DSOUND_PrimaryDestroy(IDirectSoundImpl *This); -HRESULT DSOUND_PrimaryPlay(IDirectSoundImpl *This); -HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This); -HRESULT DSOUND_PrimaryGetPosition(IDirectSoundImpl *This, LPDWORD playpos, LPDWORD writepos); - -/* buffer.c */ - -DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, - DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix); - -/* mixer.c */ - -void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len); -void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb); -void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos); -void DSOUND_WaveQueue(IDirectSoundImpl *dsound, DWORD mixq); -void DSOUND_PerformMix(IDirectSoundImpl *dsound); -void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2); -void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2); - -/* sound3d.c */ - -void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb); - -#define STATE_STOPPED 0 -#define STATE_STARTING 1 -#define STATE_PLAYING 2 -#define STATE_CAPTURING 2 -#define STATE_STOPPING 3 - -#define DSOUND_FREQSHIFT (14) - -extern IDirectSoundImpl* dsound; - -extern GUID renderer_guids[MAXWAVEDRIVERS]; -extern GUID capture_guids[MAXWAVEDRIVERS]; - -extern HRESULT mmErr(UINT err); -extern void setup_dsound_options(void); -extern const char * get_device_id(LPCGUID pGuid); +/* DirectSound + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Rob Riggs + * Copyright 2000-2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Linux does not support better timing than 10ms */ +#define DS_TIME_RES 10 /* Resolution of multimedia timer */ +#define DS_TIME_DEL 10 /* Delay of multimedia timer callback, and duration of HEL fragment */ + +#define DS_HEL_FRAGS 48 /* HEL only: number of waveOut fragments in primary buffer + * (changing this won't help you) */ + +/* wine spec */ +#include "dxroslayer/dxros_layer.h" +/* direct sound hardware acceleration levels */ +#define DS_HW_ACCEL_FULL 0 /* default on Windows 98 */ +#define DS_HW_ACCEL_STANDARD 1 /* default on Windows 2000 */ +#define DS_HW_ACCEL_BASIC 2 +#define DS_HW_ACCEL_EMULATION 3 + +extern int ds_emuldriver; +extern int ds_hel_margin; +extern int ds_hel_queue; +extern int ds_snd_queue_max; +extern int ds_snd_queue_min; +extern int ds_hw_accel; +extern int ds_default_playback; +extern int ds_default_capture; + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +typedef struct IDirectSoundImpl IDirectSoundImpl; +typedef struct IDirectSound_IUnknown IDirectSound_IUnknown; +typedef struct IDirectSound_IDirectSound IDirectSound_IDirectSound; +typedef struct IDirectSound8_IUnknown IDirectSound8_IUnknown; +typedef struct IDirectSound8_IDirectSound IDirectSound8_IDirectSound; +typedef struct IDirectSound8_IDirectSound8 IDirectSound8_IDirectSound8; +typedef struct IDirectSoundBufferImpl IDirectSoundBufferImpl; +typedef struct IDirectSoundCaptureImpl IDirectSoundCaptureImpl; +typedef struct IDirectSoundCaptureBufferImpl IDirectSoundCaptureBufferImpl; +typedef struct IDirectSoundFullDuplexImpl IDirectSoundFullDuplexImpl; +typedef struct IDirectSoundNotifyImpl IDirectSoundNotifyImpl; +typedef struct IDirectSoundCaptureNotifyImpl IDirectSoundCaptureNotifyImpl; +typedef struct IDirectSound3DListenerImpl IDirectSound3DListenerImpl; +typedef struct IDirectSound3DBufferImpl IDirectSound3DBufferImpl; +typedef struct IKsBufferPropertySetImpl IKsBufferPropertySetImpl; +typedef struct IKsPrivatePropertySetImpl IKsPrivatePropertySetImpl; +typedef struct PrimaryBufferImpl PrimaryBufferImpl; +typedef struct SecondaryBufferImpl SecondaryBufferImpl; +typedef struct IClassFactoryImpl IClassFactoryImpl; +typedef struct DirectSoundDevice DirectSoundDevice; +typedef struct DirectSoundCaptureDevice DirectSoundCaptureDevice; + +/***************************************************************************** + * IDirectSound implementation structure + */ +struct IDirectSoundImpl +{ + /* IUnknown fields */ + const IDirectSound8Vtbl *lpVtbl; + LONG ref; + + DirectSoundDevice *device; + LPUNKNOWN pUnknown; + LPDIRECTSOUND pDS; + LPDIRECTSOUND8 pDS8; +}; + +struct DirectSoundDevice +{ + LONG ref; + + GUID guid; + PIDSDRIVER driver; + DSDRIVERDESC drvdesc; + DSDRIVERCAPS drvcaps; + DWORD priolevel; + PWAVEFORMATEX pwfx; + HWAVEOUT hwo; + LPWAVEHDR pwave[DS_HEL_FRAGS]; + UINT timerID, pwplay, pwwrite, pwqueue, prebuf, precount; + DWORD fraglen; + PIDSDRIVERBUFFER hwbuf; + LPBYTE buffer; + DWORD writelead, buflen, state, playpos, mixpos; + BOOL need_remix; + int nrofbuffers; + IDirectSoundBufferImpl** buffers; + RTL_RWLOCK buffer_list_lock; + CRITICAL_SECTION mixlock; + PrimaryBufferImpl* primary; + DSBUFFERDESC dsbd; + DWORD speaker_config; + LPBYTE tmp_buffer; + DWORD tmp_buffer_len; + + /* DirectSound3DListener fields */ + IDirectSound3DListenerImpl* listener; + DS3DLISTENER ds3dl; + BOOL ds3dl_need_recalc; +}; + +/* reference counted buffer memory for duplicated buffer memory */ +typedef struct BufferMemory +{ + LONG ref; + LPBYTE memory; +} BufferMemory; + +HRESULT WINAPI IDirectSoundImpl_Create( + LPDIRECTSOUND8 * ppds); + +HRESULT WINAPI DSOUND_Create( + LPDIRECTSOUND *ppDS, + IUnknown *pUnkOuter); + +HRESULT WINAPI DSOUND_Create8( + LPDIRECTSOUND8 *ppDS, + IUnknown *pUnkOuter); + +/***************************************************************************** + * IDirectSound COM components + */ +struct IDirectSound_IUnknown { + const IUnknownVtbl *lpVtbl; + LONG ref; + LPDIRECTSOUND8 pds; +}; + +HRESULT WINAPI IDirectSound_IUnknown_Create( + LPDIRECTSOUND8 pds, + LPUNKNOWN * ppunk); + +struct IDirectSound_IDirectSound { + const IDirectSoundVtbl *lpVtbl; + LONG ref; + LPDIRECTSOUND8 pds; +}; + +HRESULT WINAPI IDirectSound_IDirectSound_Create( + LPDIRECTSOUND8 pds, + LPDIRECTSOUND * ppds); + +/***************************************************************************** + * IDirectSound8 COM components + */ +struct IDirectSound8_IUnknown { + const IUnknownVtbl *lpVtbl; + LONG ref; + LPDIRECTSOUND8 pds; +}; + +HRESULT WINAPI IDirectSound8_IUnknown_Create( + LPDIRECTSOUND8 pds, + LPUNKNOWN * ppunk); + +struct IDirectSound8_IDirectSound { + const IDirectSoundVtbl *lpVtbl; + LONG ref; + LPDIRECTSOUND8 pds; +}; + +HRESULT WINAPI IDirectSound8_IDirectSound_Create( + LPDIRECTSOUND8 pds, + LPDIRECTSOUND * ppds); + +struct IDirectSound8_IDirectSound8 { + const IDirectSound8Vtbl *lpVtbl; + LONG ref; + LPDIRECTSOUND8 pds; +}; + +HRESULT WINAPI IDirectSound8_IDirectSound8_Create( + LPDIRECTSOUND8 pds, + LPDIRECTSOUND8 * ppds); + +/***************************************************************************** + * IDirectSoundBuffer implementation structure + */ +struct IDirectSoundBufferImpl +{ + /* FIXME: document */ + /* IUnknown fields */ + const IDirectSoundBuffer8Vtbl *lpVtbl; + LONG ref; + /* IDirectSoundBufferImpl fields */ + SecondaryBufferImpl* dsb; + IDirectSoundImpl* dsound; + CRITICAL_SECTION lock; + PIDSDRIVERBUFFER hwbuf; + PWAVEFORMATEX pwfx; + BufferMemory* buffer; + DWORD playflags,state,leadin; + DWORD playpos,startpos,writelead,buflen; + DWORD nAvgBytesPerSec; + DWORD freq; + DSVOLUMEPAN volpan, cvolpan; + DSBUFFERDESC dsbd; + /* used for frequency conversion (PerfectPitch) */ + ULONG freqAdjust, freqAcc; + /* used for intelligent (well, sort of) prebuffering */ + DWORD probably_valid_to, last_playpos; + DWORD primary_mixpos, buf_mixpos; + BOOL need_remix; + + /* IDirectSoundNotifyImpl fields */ + IDirectSoundNotifyImpl* notify; + LPDSBPOSITIONNOTIFY notifies; + int nrofnotifies; + PIDSDRIVERNOTIFY hwnotify; + + /* DirectSound3DBuffer fields */ + IDirectSound3DBufferImpl* ds3db; + DS3DBUFFER ds3db_ds3db; + LONG ds3db_lVolume; + BOOL ds3db_need_recalc; + + /* IKsPropertySet fields */ + IKsBufferPropertySetImpl* iks; +}; + +HRESULT WINAPI IDirectSoundBufferImpl_Create( + IDirectSoundImpl *ds, + IDirectSoundBufferImpl **pdsb, + LPCDSBUFFERDESC dsbd); +HRESULT WINAPI IDirectSoundBufferImpl_Destroy( + IDirectSoundBufferImpl *pdsb); + +/***************************************************************************** + * SecondaryBuffer implementation structure + */ +struct SecondaryBufferImpl +{ + const IDirectSoundBuffer8Vtbl *lpVtbl; + LONG ref; + IDirectSoundBufferImpl* dsb; +}; + +HRESULT WINAPI SecondaryBufferImpl_Create( + IDirectSoundBufferImpl *dsb, + SecondaryBufferImpl **pdsb); +HRESULT WINAPI SecondaryBufferImpl_Destroy( + SecondaryBufferImpl *pdsb); + +/***************************************************************************** + * PrimaryBuffer implementation structure + */ +struct PrimaryBufferImpl +{ + const IDirectSoundBuffer8Vtbl *lpVtbl; + LONG ref; + IDirectSoundImpl* dsound; +}; + +HRESULT WINAPI PrimaryBufferImpl_Create( + IDirectSoundImpl *ds, + PrimaryBufferImpl **pdsb, + LPCDSBUFFERDESC dsbd); + +/***************************************************************************** + * IDirectSoundCapture implementation structure + */ +struct IDirectSoundCaptureImpl +{ + /* IUnknown fields */ + const IDirectSoundCaptureVtbl *lpVtbl; + LONG ref; + + DirectSoundCaptureDevice *device; +}; + +struct DirectSoundCaptureDevice +{ + /* IDirectSoundCaptureImpl fields */ + GUID guid; + LONG ref; + + /* DirectSound driver stuff */ + PIDSCDRIVER driver; + DSDRIVERDESC drvdesc; + DSCDRIVERCAPS drvcaps; + PIDSCDRIVERBUFFER hwbuf; + + /* wave driver info */ + HWAVEIN hwi; + + /* more stuff */ + LPBYTE buffer; + DWORD buflen; + DWORD read_position; + + PWAVEFORMATEX pwfx; + + IDirectSoundCaptureBufferImpl* capture_buffer; + DWORD state; + LPWAVEHDR pwave; + int nrofpwaves; + int index; + CRITICAL_SECTION lock; +}; + +HRESULT WINAPI IDirectSoundCaptureImpl_Create( + LPDIRECTSOUNDCAPTURE8 * ppds); + +HRESULT WINAPI DSOUND_CaptureCreate( + LPDIRECTSOUNDCAPTURE *ppDSC, + IUnknown *pUnkOuter); + +HRESULT WINAPI DSOUND_CaptureCreate8( + LPDIRECTSOUNDCAPTURE8 *ppDSC8, + IUnknown *pUnkOuter); + +/***************************************************************************** + * IDirectSoundCaptureBuffer implementation structure + */ +struct IDirectSoundCaptureBufferImpl +{ + /* IUnknown fields */ + const IDirectSoundCaptureBuffer8Vtbl *lpVtbl; + LONG ref; + + /* IDirectSoundCaptureBufferImpl fields */ + IDirectSoundCaptureImpl* dsound; + /* FIXME: don't need this */ + LPDSCBUFFERDESC pdscbd; + DWORD flags; + + /* IDirectSoundCaptureNotifyImpl fields */ + IDirectSoundCaptureNotifyImpl* notify; + LPDSBPOSITIONNOTIFY notifies; + int nrofnotifies; + PIDSDRIVERNOTIFY hwnotify; +}; + +/***************************************************************************** + * IDirectSoundFullDuplex implementation structure + */ +struct IDirectSoundFullDuplexImpl +{ + /* IUnknown fields */ + const IDirectSoundFullDuplexVtbl *lpVtbl; + LONG ref; + + /* IDirectSoundFullDuplexImpl fields */ + CRITICAL_SECTION lock; +}; + +/***************************************************************************** + * IDirectSoundNotify implementation structure + */ +struct IDirectSoundNotifyImpl +{ + /* IUnknown fields */ + const IDirectSoundNotifyVtbl *lpVtbl; + LONG ref; + IDirectSoundBufferImpl* dsb; +}; + +HRESULT WINAPI IDirectSoundNotifyImpl_Create( + IDirectSoundBufferImpl *dsb, + IDirectSoundNotifyImpl **pdsn); +HRESULT WINAPI IDirectSoundNotifyImpl_Destroy( + IDirectSoundNotifyImpl *pdsn); + +/***************************************************************************** + * IDirectSoundCaptureNotify implementation structure + */ +struct IDirectSoundCaptureNotifyImpl +{ + /* IUnknown fields */ + const IDirectSoundNotifyVtbl *lpVtbl; + LONG ref; + IDirectSoundCaptureBufferImpl* dscb; +}; + +HRESULT WINAPI IDirectSoundCaptureNotifyImpl_Create( + IDirectSoundCaptureBufferImpl *dscb, + IDirectSoundCaptureNotifyImpl ** pdscn); + +/***************************************************************************** + * IDirectSound3DListener implementation structure + */ +struct IDirectSound3DListenerImpl +{ + /* IUnknown fields */ + const IDirectSound3DListenerVtbl *lpVtbl; + LONG ref; + /* IDirectSound3DListenerImpl fields */ + IDirectSoundImpl* dsound; +}; + +HRESULT WINAPI IDirectSound3DListenerImpl_Create( + PrimaryBufferImpl *pb, + IDirectSound3DListenerImpl **pdsl); + +/***************************************************************************** + * IKsBufferPropertySet implementation structure + */ +struct IKsBufferPropertySetImpl +{ + /* IUnknown fields */ + const IKsPropertySetVtbl *lpVtbl; + LONG ref; + /* IKsPropertySetImpl fields */ + IDirectSoundBufferImpl* dsb; +}; + +HRESULT WINAPI IKsBufferPropertySetImpl_Create( + IDirectSoundBufferImpl *dsb, + IKsBufferPropertySetImpl **piks); +HRESULT WINAPI IKsBufferPropertySetImpl_Destroy( + IKsBufferPropertySetImpl *piks); + +/***************************************************************************** + * IKsPrivatePropertySet implementation structure + */ +struct IKsPrivatePropertySetImpl +{ + /* IUnknown fields */ + const IKsPropertySetVtbl *lpVtbl; + LONG ref; +}; + +HRESULT WINAPI IKsPrivatePropertySetImpl_Create( + IKsPrivatePropertySetImpl **piks); + +/***************************************************************************** + * IDirectSound3DBuffer implementation structure + */ +struct IDirectSound3DBufferImpl +{ + /* IUnknown fields */ + const IDirectSound3DBufferVtbl *lpVtbl; + LONG ref; + /* IDirectSound3DBufferImpl fields */ + IDirectSoundBufferImpl* dsb; +}; + +HRESULT WINAPI IDirectSound3DBufferImpl_Create( + IDirectSoundBufferImpl *dsb, + IDirectSound3DBufferImpl **pds3db); +HRESULT WINAPI IDirectSound3DBufferImpl_Destroy( + IDirectSound3DBufferImpl *pds3db); + +/******************************************************************************* + * DirectSound ClassFactory implementation structure + */ +struct IClassFactoryImpl +{ + /* IUnknown fields */ + const IClassFactoryVtbl *lpVtbl; + LONG ref; +}; + +extern IClassFactoryImpl DSOUND_CAPTURE_CF; +extern IClassFactoryImpl DSOUND_FULLDUPLEX_CF; + +void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan); +void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan); +void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb); + +/* dsound.c */ + +HRESULT DSOUND_AddBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB); +HRESULT DSOUND_RemoveBuffer(IDirectSoundImpl * pDS, IDirectSoundBufferImpl * pDSB); + +/* primary.c */ + +HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device); +HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device); +HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device); +HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device); +HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos); + +/* buffer.c */ + +DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This, DWORD pplay, DWORD pwrite); + +/* mixer.c */ + +void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len); +void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb); +void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos); +void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq); +void DSOUND_PerformMix(DirectSoundDevice *device); +void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2); +void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2); + +/* sound3d.c */ + +void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb); + +#define STATE_STOPPED 0 +#define STATE_STARTING 1 +#define STATE_PLAYING 2 +#define STATE_CAPTURING 2 +#define STATE_STOPPING 3 + +#define DSOUND_FREQSHIFT (14) + +extern DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS]; +extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; + +extern DirectSoundCaptureDevice * DSOUND_capture[MAXWAVEDRIVERS]; +extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; + +extern HRESULT mmErr(UINT err); +extern void setup_dsound_options(void); +extern const char * get_device_id(LPCGUID pGuid); diff --git a/reactos/lib/dsound/duplex.c b/reactos/lib/dsound/duplex.c new file mode 100644 index 00000000000..044d764047e --- /dev/null +++ b/reactos/lib/dsound/duplex.c @@ -0,0 +1,283 @@ +/* DirectSoundFullDuplex + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Rob Riggs + * Copyright 2000-2001 TransGaming Technologies, Inc. + * Copyright 2005 Robert Reif + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * TODO: + * Implement DirectSoundFullDuplex support. + */ + +#include + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "mmddk.h" +#include "winreg.h" +#include "winternl.h" +#include "winnls.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +static HRESULT WINAPI IDirectSoundFullDuplexImpl_Initialize( + LPDIRECTSOUNDFULLDUPLEX iface, + LPCGUID pCaptureGuid, + LPCGUID pRendererGuid, + LPCDSCBUFFERDESC lpDscBufferDesc, + LPCDSBUFFERDESC lpDsBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, + LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 ); + +static const IDirectSoundFullDuplexVtbl dsfdvt; + +/*************************************************************************** + * DirectSoundFullDuplexCreate [DSOUND.10] + * + * Create and initialize a DirectSoundFullDuplex interface. + * + * PARAMS + * pcGuidCaptureDevice [I] Address of sound capture device GUID. + * pcGuidRenderDevice [I] Address of sound render device GUID. + * pcDSCBufferDesc [I] Address of capture buffer description. + * pcDSBufferDesc [I] Address of render buffer description. + * hWnd [I] Handle to application window. + * dwLevel [I] Cooperative level. + * ppDSFD [O] Address where full duplex interface returned. + * ppDSCBuffer8 [0] Address where capture buffer interface returned. + * ppDSBuffer8 [0] Address where render buffer interface returned. + * pUnkOuter [I] Must be NULL. + * + * RETURNS + * Success: DS_OK + * Failure: DSERR_NOAGGREGATION, DSERR_ALLOCATED, DSERR_INVALIDPARAM, + * DSERR_OUTOFMEMORY DSERR_INVALIDCALL DSERR_NODRIVER + */ +HRESULT WINAPI +DirectSoundFullDuplexCreate( + LPCGUID pcGuidCaptureDevice, + LPCGUID pcGuidRenderDevice, + LPCDSCBUFFERDESC pcDSCBufferDesc, + LPCDSBUFFERDESC pcDSBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPDIRECTSOUNDFULLDUPLEX *ppDSFD, + LPDIRECTSOUNDCAPTUREBUFFER8 *ppDSCBuffer8, + LPDIRECTSOUNDBUFFER8 *ppDSBuffer8, + LPUNKNOWN pUnkOuter) +{ + IDirectSoundFullDuplexImpl** ippDSFD=(IDirectSoundFullDuplexImpl**)ppDSFD; + TRACE("(%s,%s,%p,%p,%p,%lx,%p,%p,%p,%p)\n", debugstr_guid(pcGuidCaptureDevice), + debugstr_guid(pcGuidRenderDevice), pcDSCBufferDesc, pcDSBufferDesc, + hWnd, dwLevel, ppDSFD, ppDSCBuffer8, ppDSBuffer8, pUnkOuter); + + if ( pUnkOuter ) { + WARN("pUnkOuter != 0\n"); + return DSERR_NOAGGREGATION; + } + + *ippDSFD = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(IDirectSoundFullDuplexImpl)); + + if (*ippDSFD == NULL) { + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } else { + HRESULT hres; + IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)*ippDSFD; + + This->ref = 1; + This->lpVtbl = &dsfdvt; + + InitializeCriticalSection( &(This->lock) ); + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)"DSDUPLEX_lock"; + + hres = IDirectSoundFullDuplexImpl_Initialize( (LPDIRECTSOUNDFULLDUPLEX)This, + pcGuidCaptureDevice, pcGuidRenderDevice, + pcDSCBufferDesc, pcDSBufferDesc, + hWnd, dwLevel, ppDSCBuffer8, ppDSBuffer8); + if (hres != DS_OK) + WARN("IDirectSoundFullDuplexImpl_Initialize failed\n"); + return hres; + } +} + +static HRESULT WINAPI +IDirectSoundFullDuplexImpl_QueryInterface( + LPDIRECTSOUNDFULLDUPLEX iface, + REFIID riid, + LPVOID* ppobj ) +{ + IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; + TRACE( "(%p,%s,%p)\n", This, debugstr_guid(riid), ppobj ); + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI +IDirectSoundFullDuplexImpl_AddRef( LPDIRECTSOUNDFULLDUPLEX iface ) +{ + IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI +IDirectSoundFullDuplexImpl_Release( LPDIRECTSOUNDFULLDUPLEX iface ) +{ + IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + + if (!ref) { + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &(This->lock) ); + HeapFree( GetProcessHeap(), 0, This ); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI +IDirectSoundFullDuplexImpl_Initialize( + LPDIRECTSOUNDFULLDUPLEX iface, + LPCGUID pCaptureGuid, + LPCGUID pRendererGuid, + LPCDSCBUFFERDESC lpDscBufferDesc, + LPCDSBUFFERDESC lpDsBufferDesc, + HWND hWnd, + DWORD dwLevel, + LPLPDIRECTSOUNDCAPTUREBUFFER8 lplpDirectSoundCaptureBuffer8, + LPLPDIRECTSOUNDBUFFER8 lplpDirectSoundBuffer8 ) +{ + IDirectSoundFullDuplexImpl *This = (IDirectSoundFullDuplexImpl *)iface; + IDirectSoundCaptureBufferImpl** ippdscb=(IDirectSoundCaptureBufferImpl**)lplpDirectSoundCaptureBuffer8; + IDirectSoundBufferImpl** ippdsc=(IDirectSoundBufferImpl**)lplpDirectSoundBuffer8; + + FIXME( "(%p,%s,%s,%p,%p,%p,%lx,%p,%p) stub!\n", This, debugstr_guid(pCaptureGuid), + debugstr_guid(pRendererGuid), lpDscBufferDesc, lpDsBufferDesc, hWnd, dwLevel, + ippdscb, ippdsc); + + return E_FAIL; +} + +static const IDirectSoundFullDuplexVtbl dsfdvt = +{ + /* IUnknown methods */ + IDirectSoundFullDuplexImpl_QueryInterface, + IDirectSoundFullDuplexImpl_AddRef, + IDirectSoundFullDuplexImpl_Release, + + /* IDirectSoundFullDuplex methods */ + IDirectSoundFullDuplexImpl_Initialize +}; + +/******************************************************************************* + * DirectSoundFullDuplex ClassFactory + */ + +static HRESULT WINAPI +DSFDCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI +DSFDCF_AddRef(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + TRACE("(%p) ref was %ld\n", This, This->ref); + return InterlockedIncrement(&(This->ref)); +} + +static ULONG WINAPI +DSFDCF_Release(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class, won't be freed */ + TRACE("(%p) ref was %ld\n", This, This->ref); + return InterlockedDecrement(&(This->ref)); +} + +static HRESULT WINAPI +DSFDCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + if (pOuter) { + WARN("aggregation not supported\n"); + return CLASS_E_NOAGGREGATION; + } + + if (ppobj == NULL) { + WARN("invalid parameter\n"); + return E_INVALIDARG; + } + + *ppobj = NULL; + + if ( IsEqualGUID( &IID_IDirectSoundFullDuplex, riid ) ) { + /* FIXME: how do we do this one ? */ + FIXME("not implemented\n"); + return E_NOINTERFACE; + } + + WARN("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI +DSFDCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static const IClassFactoryVtbl DSFDCF_Vtbl = +{ + DSFDCF_QueryInterface, + DSFDCF_AddRef, + DSFDCF_Release, + DSFDCF_CreateInstance, + DSFDCF_LockServer +}; + +IClassFactoryImpl DSOUND_FULLDUPLEX_CF = { &DSFDCF_Vtbl, 1 }; diff --git a/reactos/lib/dsound/mixer.c b/reactos/lib/dsound/mixer.c index caf4e80c7ad..00695461ce3 100644 --- a/reactos/lib/dsound/mixer.c +++ b/reactos/lib/dsound/mixer.c @@ -1,1188 +1,1177 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include /* Insomnia - pow() function */ - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winreg.h" -#include "winternl.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - -void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan) -{ - double temp; - TRACE("(%p)\n",volpan); - - TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan); - /* the AmpFactors are expressed in 16.16 fixed point */ - volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 0xffff); - /* FIXME: dwPan{Left|Right}AmpFactor */ - - /* FIXME: use calculated vol and pan ampfactors */ - temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0)); - volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); - temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0)); - volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); - - TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor); -} - -void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan) -{ - double left,right; - TRACE("(%p)\n",volpan); - - TRACE("left=%lx, right=%lx\n",volpan->dwTotalLeftAmpFactor,volpan->dwTotalRightAmpFactor); - if (volpan->dwTotalLeftAmpFactor==0) - left=-10000; - else - left=600 * log(((double)volpan->dwTotalLeftAmpFactor) / 0xffff) / log(2); - if (volpan->dwTotalRightAmpFactor==0) - right=-10000; - else - right=600 * log(((double)volpan->dwTotalRightAmpFactor) / 0xffff) / log(2); - if (leftlVolume=right; - volpan->dwVolAmpFactor=volpan->dwTotalRightAmpFactor; - } - else - { - volpan->lVolume=left; - volpan->dwVolAmpFactor=volpan->dwTotalLeftAmpFactor; - } - if (volpan->lVolume < -10000) - volpan->lVolume=-10000; - volpan->lPan=right-left; - if (volpan->lPan < -10000) - volpan->lPan=-10000; - - TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan); -} - -void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) -{ - DWORD sw; - TRACE("(%p)\n",dsb); - - sw = dsb->pwfx->nChannels * (dsb->pwfx->wBitsPerSample / 8); - /* calculate the 10ms write lead */ - dsb->writelead = (dsb->freq / 100) * sw; -} - -void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len) -{ - int i; - DWORD offset; - LPDSBPOSITIONNOTIFY event; - TRACE("(%p,%d)\n",dsb,len); - - if (dsb->nrofnotifies == 0) - return; - - TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n", - dsb, dsb->buflen, dsb->playpos, len); - for (i = 0; i < dsb->nrofnotifies ; i++) { - event = dsb->notifies + i; - offset = event->dwOffset; - TRACE("checking %d, position %ld, event = %p\n", - i, offset, event->hEventNotify); - /* DSBPN_OFFSETSTOP has to be the last element. So this is */ - /* OK. [Inside DirectX, p274] */ - /* */ - /* This also means we can't sort the entries by offset, */ - /* because DSBPN_OFFSETSTOP == -1 */ - if (offset == DSBPN_OFFSETSTOP) { - if (dsb->state == STATE_STOPPED) { - SetEvent(event->hEventNotify); - TRACE("signalled event %p (%d)\n", event->hEventNotify, i); - return; - } else - return; - } - if ((dsb->playpos + len) >= dsb->buflen) { - if ((offset < ((dsb->playpos + len) % dsb->buflen)) || - (offset >= dsb->playpos)) { - TRACE("signalled event %p (%d)\n", event->hEventNotify, i); - SetEvent(event->hEventNotify); - } - } else { - if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) { - TRACE("signalled event %p (%d)\n", event->hEventNotify, i); - SetEvent(event->hEventNotify); - } - } - } -} - -/* WAV format info can be found at: - * - * http://www.cwi.nl/ftp/audio/AudioFormats.part2 - * ftp://ftp.cwi.nl/pub/audio/RIFF-format - * - * Import points to remember: - * 8-bit WAV is unsigned - * 16-bit WAV is signed - */ - /* Use the same formulas as pcmconverter.c */ -static inline INT16 cvtU8toS16(BYTE b) -{ - return (short)((b+(b << 8))-32768); -} - -static inline BYTE cvtS16toU8(INT16 s) -{ - return (s >> 8) ^ (unsigned char)0x80; -} - -static inline void cp_fields(const IDirectSoundBufferImpl *dsb, BYTE *ibuf, BYTE *obuf ) -{ - INT fl,fr; - - if (dsb->pwfx->wBitsPerSample == 8) { - if (dsb->dsound->pwfx->wBitsPerSample == 8 && - dsb->dsound->pwfx->nChannels == dsb->pwfx->nChannels) { - /* avoid needless 8->16->8 conversion */ - *obuf=*ibuf; - if (dsb->pwfx->nChannels==2) - *(obuf+1)=*(ibuf+1); - return; - } - fl = cvtU8toS16(*ibuf); - fr = (dsb->pwfx->nChannels==2 ? cvtU8toS16(*(ibuf + 1)) : fl); - } else { - fl = *((INT16 *)ibuf); - fr = (dsb->pwfx->nChannels==2 ? *(((INT16 *)ibuf) + 1) : fl); - } - - if (dsb->dsound->pwfx->nChannels == 2) { - if (dsb->dsound->pwfx->wBitsPerSample == 8) { - *obuf = cvtS16toU8(fl); - *(obuf + 1) = cvtS16toU8(fr); - return; - } - if (dsb->dsound->pwfx->wBitsPerSample == 16) { - *((INT16 *)obuf) = fl; - *(((INT16 *)obuf) + 1) = fr; - return; - } - } - if (dsb->dsound->pwfx->nChannels == 1) { - fl = (fl + fr) >> 1; - if (dsb->dsound->pwfx->wBitsPerSample == 8) { - *obuf = cvtS16toU8(fl); - return; - } - if (dsb->dsound->pwfx->wBitsPerSample == 16) { - *((INT16 *)obuf) = fl; - return; - } - } -} - -/* Now with PerfectPitch (tm) technology */ -static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) -{ - INT i, size, ipos, ilen; - BYTE *ibp, *obp; - INT iAdvance = dsb->pwfx->nBlockAlign; - INT oAdvance = dsb->dsound->pwfx->nBlockAlign; - - ibp = dsb->buffer->memory + dsb->buf_mixpos; - obp = buf; - - TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb, ibp, obp, dsb->buf_mixpos); - /* Check for the best case */ - if ((dsb->freq == dsb->dsound->pwfx->nSamplesPerSec) && - (dsb->pwfx->wBitsPerSample == dsb->dsound->pwfx->wBitsPerSample) && - (dsb->pwfx->nChannels == dsb->dsound->pwfx->nChannels)) { - DWORD bytesleft = dsb->buflen - dsb->buf_mixpos; - TRACE("(%p) Best case\n", dsb); - if (len <= bytesleft ) - memcpy(obp, ibp, len); - else { /* wrap */ - memcpy(obp, ibp, bytesleft ); - memcpy(obp + bytesleft, dsb->buffer->memory, len - bytesleft); - } - return len; - } - - /* Check for same sample rate */ - if (dsb->freq == dsb->dsound->pwfx->nSamplesPerSec) { - TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb, - dsb->freq, dsb->dsound->pwfx->nSamplesPerSec); - ilen = 0; - for (i = 0; i < len; i += oAdvance) { - cp_fields(dsb, ibp, obp ); - ibp += iAdvance; - ilen += iAdvance; - obp += oAdvance; - if (ibp >= (BYTE *)(dsb->buffer->memory + dsb->buflen)) - ibp = dsb->buffer->memory; /* wrap */ - } - return (ilen); - } - - /* Mix in different sample rates */ - /* */ - /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */ - /* Patent Pending :-] */ - - /* Patent enhancements (c) 2000 Ove Kåven, - * TransGaming Technologies Inc. */ - - /* FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n", - dsb, dsb->freq, dsb->dsound->pwfx->nSamplesPerSec); */ - - size = len / oAdvance; - ilen = 0; - ipos = dsb->buf_mixpos; - for (i = 0; i < size; i++) { - cp_fields(dsb, (dsb->buffer->memory + ipos), obp); - obp += oAdvance; - dsb->freqAcc += dsb->freqAdjust; - if (dsb->freqAcc >= (1<freqAcc>>DSOUND_FREQSHIFT) * iAdvance; - dsb->freqAcc &= (1<buflen; - } - } - return ilen; -} - -static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) -{ - INT i; - BYTE *bpc = buf; - INT16 *bps = (INT16 *) buf; - - TRACE("(%p,%p,%d)\n",dsb,buf,len); - TRACE("left = %lx, right = %lx\n", dsb->cvolpan.dwTotalLeftAmpFactor, - dsb->cvolpan.dwTotalRightAmpFactor); - - if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->cvolpan.lPan == 0)) && - (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->cvolpan.lVolume == 0)) && - !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) - return; /* Nothing to do */ - - /* If we end up with some bozo coder using panning or 3D sound */ - /* with a mono primary buffer, it could sound very weird using */ - /* this method. Oh well, tough patooties. */ - - switch (dsb->dsound->pwfx->wBitsPerSample) { - case 8: - /* 8-bit WAV is unsigned, but we need to operate */ - /* on signed data for this to work properly */ - switch (dsb->dsound->pwfx->nChannels) { - case 1: - for (i = 0; i < len; i++) { - INT val = *bpc - 128; - val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; - *bpc = val + 128; - bpc++; - } - break; - case 2: - for (i = 0; i < len; i+=2) { - INT val = *bpc - 128; - val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; - *bpc++ = val + 128; - val = *bpc - 128; - val = (val * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; - *bpc = val + 128; - bpc++; - } - break; - default: - FIXME("doesn't support %d channels\n", dsb->dsound->pwfx->nChannels); - break; - } - break; - case 16: - /* 16-bit WAV is signed -- much better */ - switch (dsb->dsound->pwfx->nChannels) { - case 1: - for (i = 0; i < len; i += 2) { - *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; - bps++; - } - break; - case 2: - for (i = 0; i < len; i += 4) { - *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; - bps++; - *bps = (*bps * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; - bps++; - } - break; - default: - FIXME("doesn't support %d channels\n", dsb->dsound->pwfx->nChannels); - break; - } - break; - default: - FIXME("doesn't support %d bit samples\n", dsb->dsound->pwfx->wBitsPerSample); - break; - } -} - -static void *tmp_buffer; -static size_t tmp_buffer_len = 0; - -static void *DSOUND_tmpbuffer(size_t len) -{ - if (len>tmp_buffer_len) { - void *new_buffer = realloc(tmp_buffer, len); - if (new_buffer) { - tmp_buffer = new_buffer; - tmp_buffer_len = len; - } - return new_buffer; - } - return tmp_buffer; -} - -static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen) -{ - INT i, len, ilen, temp, field, nBlockAlign, todo; - BYTE *buf, *ibuf; - - TRACE("(%p,%ld,%ld)\n",dsb,writepos,fraglen); - - len = fraglen; - if (!(dsb->playflags & DSBPLAY_LOOPING)) { - temp = MulDiv(dsb->dsound->pwfx->nAvgBytesPerSec, dsb->buflen, - dsb->nAvgBytesPerSec) - - MulDiv(dsb->dsound->pwfx->nAvgBytesPerSec, dsb->buf_mixpos, - dsb->nAvgBytesPerSec); - len = (len > temp) ? temp : len; - } - nBlockAlign = dsb->dsound->pwfx->nBlockAlign; - len = len / nBlockAlign * nBlockAlign; /* data alignment */ - - if (len == 0) { - /* This should only happen if we aren't looping and temp < nBlockAlign */ - return 0; - } - - /* Been seeing segfaults in malloc() for some reason... */ - TRACE("allocating buffer (size = %d)\n", len); - if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL) - return 0; - - TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos); - - ilen = DSOUND_MixerNorm(dsb, ibuf, len); - if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || - (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || - (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) - DSOUND_MixerVol(dsb, ibuf, len); - - if (dsb->dsound->pwfx->wBitsPerSample == 8) { - BYTE *obuf = dsb->dsound->buffer + writepos; - - if ((writepos + len) <= dsb->dsound->buflen) - todo = len; - else - todo = dsb->dsound->buflen - writepos; - - for (i = 0; i < todo; i++) { - /* 8-bit WAV is unsigned */ - field = (*ibuf++ - 128); - field += (*obuf - 128); - if (field > 127) field = 127; - else if (field < -128) field = -128; - *obuf++ = field + 128; - } - - if (todo < len) { - todo = len - todo; - obuf = dsb->dsound->buffer; - - for (i = 0; i < todo; i++) { - /* 8-bit WAV is unsigned */ - field = (*ibuf++ - 128); - field += (*obuf - 128); - if (field > 127) field = 127; - else if (field < -128) field = -128; - *obuf++ = field + 128; - } - } - } else { - INT16 *ibufs, *obufs; - - ibufs = (INT16 *) ibuf; - obufs = (INT16 *)(dsb->dsound->buffer + writepos); - - if ((writepos + len) <= dsb->dsound->buflen) - todo = len / 2; - else - todo = (dsb->dsound->buflen - writepos) / 2; - - for (i = 0; i < todo; i++) { - /* 16-bit WAV is signed */ - field = *ibufs++; - field += *obufs; - if (field > 32767) field = 32767; - else if (field < -32768) field = -32768; - *obufs++ = field; - } - - if (todo < (len / 2)) { - todo = (len / 2) - todo; - obufs = (INT16 *)dsb->dsound->buffer; - - for (i = 0; i < todo; i++) { - /* 16-bit WAV is signed */ - field = *ibufs++; - field += *obufs; - if (field > 32767) field = 32767; - else if (field < -32768) field = -32768; - *obufs++ = field; - } - } - } - - if (dsb->leadin && (dsb->startpos > dsb->buf_mixpos) && (dsb->startpos <= dsb->buf_mixpos + ilen)) { - /* HACK... leadin should be reset when the PLAY position reaches the startpos, - * not the MIX position... but if the sound buffer is bigger than our prebuffering - * (which must be the case for the streaming buffers that need this hack anyway) - * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */ - dsb->leadin = FALSE; - } - - dsb->buf_mixpos += ilen; - - if (dsb->buf_mixpos >= dsb->buflen) { - if (dsb->playflags & DSBPLAY_LOOPING) { - /* wrap */ - dsb->buf_mixpos %= dsb->buflen; - if (dsb->leadin && (dsb->startpos <= dsb->buf_mixpos)) - dsb->leadin = FALSE; /* HACK: see above */ - } - } - - return len; -} - -static void DSOUND_PhaseCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len) -{ - INT ilen, field, nBlockAlign; - UINT i, todo; - BYTE *buf, *ibuf; - - TRACE("(%p,%ld,%ld)\n",dsb,writepos,len); - - nBlockAlign = dsb->dsound->pwfx->nBlockAlign; - len = len / nBlockAlign * nBlockAlign; /* data alignment */ - - TRACE("allocating buffer (size = %ld)\n", len); - if ((buf = ibuf = (BYTE *) DSOUND_tmpbuffer(len)) == NULL) - return; - - TRACE("PhaseCancel (%p) len = %ld, dest = %ld\n", dsb, len, writepos); - - ilen = DSOUND_MixerNorm(dsb, ibuf, len); - if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || - (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || - (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) - DSOUND_MixerVol(dsb, ibuf, len); - - /* subtract instead of add, to phase out premixed data */ - if (dsb->dsound->pwfx->wBitsPerSample == 8) { - BYTE *obuf = dsb->dsound->buffer + writepos; - - if ((writepos + len) <= dsb->dsound->buflen) - todo = len; - else - todo = dsb->dsound->buflen - writepos; - - for (i = 0; i < todo; i++) { - /* 8-bit WAV is unsigned */ - field = (*ibuf++ - 128); - field -= (*obuf - 128); - if (field > 127) field = 127; - else if (field < -128) field = -128; - *obuf++ = field + 128; - } - - if (todo < len) { - todo = len - todo; - obuf = dsb->dsound->buffer; - - for (i = 0; i < todo; i++) { - /* 8-bit WAV is unsigned */ - field = (*ibuf++ - 128); - field -= (*obuf - 128); - if (field > 127) field = 127; - else if (field < -128) field = -128; - *obuf++ = field + 128; - } - } - } else { - INT16 *ibufs, *obufs; - - ibufs = (INT16 *) ibuf; - obufs = (INT16 *)(dsb->dsound->buffer + writepos); - - if ((writepos + len) <= dsb->dsound->buflen) - todo = len / 2; - else - todo = (dsb->dsound->buflen - writepos) / 2; - - for (i = 0; i < todo; i++) { - /* 16-bit WAV is signed */ - field = *ibufs++; - field -= *obufs; - if (field > 32767) field = 32767; - else if (field < -32768) field = -32768; - *obufs++ = field; - } - - if (todo < (len / 2)) { - todo = (len / 2) - todo; - obufs = (INT16 *)dsb->dsound->buffer; - - for (i = 0; i < todo; i++) { - /* 16-bit WAV is signed */ - field = *ibufs++; - field -= *obufs; - if (field > 32767) field = 32767; - else if (field < -32768) field = -32768; - *obufs++ = field; - } - } - } -} - -static void DSOUND_MixCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, BOOL cancel) -{ - DWORD size, flen, len, npos, nlen; - INT iAdvance = dsb->pwfx->nBlockAlign; - INT oAdvance = dsb->dsound->pwfx->nBlockAlign; - /* determine amount of premixed data to cancel */ - DWORD primary_done = - ((dsb->primary_mixpos < writepos) ? dsb->dsound->buflen : 0) + - dsb->primary_mixpos - writepos; - - TRACE("(%p, %ld), buf_mixpos=%ld\n", dsb, writepos, dsb->buf_mixpos); - - /* backtrack the mix position */ - size = primary_done / oAdvance; - flen = size * dsb->freqAdjust; - len = (flen >> DSOUND_FREQSHIFT) * iAdvance; - flen &= (1<freqAcc < flen) { - len += iAdvance; - dsb->freqAcc += 1<buflen; - npos = ((dsb->buf_mixpos < len) ? dsb->buflen : 0) + - dsb->buf_mixpos - len; - if (dsb->leadin && (dsb->startpos > npos) && (dsb->startpos <= npos + len)) { - /* stop backtracking at startpos */ - npos = dsb->startpos; - len = ((dsb->buf_mixpos < npos) ? dsb->buflen : 0) + - dsb->buf_mixpos - npos; - flen = dsb->freqAcc; - nlen = len / dsb->pwfx->nBlockAlign; - nlen = ((nlen << DSOUND_FREQSHIFT) + flen) / dsb->freqAdjust; - nlen *= dsb->dsound->pwfx->nBlockAlign; - writepos = - ((dsb->primary_mixpos < nlen) ? dsb->dsound->buflen : 0) + - dsb->primary_mixpos - nlen; - } - - dsb->freqAcc -= flen; - dsb->buf_mixpos = npos; - dsb->primary_mixpos = writepos; - - TRACE("new buf_mixpos=%ld, primary_mixpos=%ld (len=%ld)\n", - dsb->buf_mixpos, dsb->primary_mixpos, len); - - if (cancel) DSOUND_PhaseCancel(dsb, writepos, len); -} - -void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos) -{ -#if 0 - DWORD i, size, flen, len, npos, nlen; - INT iAdvance = dsb->pwfx->nBlockAlign; - INT oAdvance = dsb->dsound->pwfx->nBlockAlign; - /* determine amount of premixed data to cancel */ - DWORD buf_done = - ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) + - dsb->buf_mixpos - buf_writepos; -#endif - - WARN("(%p, %ld), buf_mixpos=%ld\n", dsb, buf_writepos, dsb->buf_mixpos); - /* since this is not implemented yet, just cancel *ALL* prebuffering for now - * (which is faster anyway when there's only a single secondary buffer) */ - dsb->dsound->need_remix = TRUE; -} - -void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb) -{ - TRACE("(%p)\n",dsb); - EnterCriticalSection(&dsb->lock); - if (dsb->state == STATE_PLAYING) { -#if 0 /* this may not be quite reliable yet */ - dsb->need_remix = TRUE; -#else - dsb->dsound->need_remix = TRUE; -#endif - } - LeaveCriticalSection(&dsb->lock); -} - -static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD writepos, DWORD mixlen) -{ - DWORD len, slen; - /* determine this buffer's write position */ - DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, dsb->state & dsb->dsound->state, writepos, - writepos, dsb->primary_mixpos, dsb->buf_mixpos); - /* determine how much already-mixed data exists */ - DWORD buf_done = - ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) + - dsb->buf_mixpos - buf_writepos; - DWORD primary_done = - ((dsb->primary_mixpos < writepos) ? dsb->dsound->buflen : 0) + - dsb->primary_mixpos - writepos; - DWORD adv_done = - ((dsb->dsound->mixpos < writepos) ? dsb->dsound->buflen : 0) + - dsb->dsound->mixpos - writepos; - DWORD played = - ((buf_writepos < dsb->playpos) ? dsb->buflen : 0) + - buf_writepos - dsb->playpos; - DWORD buf_left = dsb->buflen - buf_writepos; - int still_behind; - - TRACE("(%p,%ld,%ld,%ld)\n",dsb,playpos,writepos,mixlen); - TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos, writepos); - TRACE("buf_done=%ld, primary_done=%ld\n", buf_done, primary_done); - TRACE("buf_mixpos=%ld, primary_mixpos=%ld, mixlen=%ld\n", dsb->buf_mixpos, dsb->primary_mixpos, - mixlen); - TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb->playflags, dsb->startpos, dsb->leadin); - - /* check for notification positions */ - if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY && - dsb->state != STATE_STARTING) { - DSOUND_CheckEvent(dsb, played); - } - - /* save write position for non-GETCURRENTPOSITION2... */ - dsb->playpos = buf_writepos; - - /* check whether CalcPlayPosition detected a mixing underrun */ - if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) { - /* it did, but did we have more to play? */ - if ((dsb->playflags & DSBPLAY_LOOPING) || - (dsb->buf_mixpos < dsb->buflen)) { - /* yes, have to recover */ - ERR("underrun on sound buffer %p\n", dsb); - TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos); - } - dsb->primary_mixpos = writepos; - primary_done = 0; - } - /* determine how far ahead we should mix */ - if (((dsb->playflags & DSBPLAY_LOOPING) || - (dsb->leadin && (dsb->probably_valid_to != 0))) && - !(dsb->dsbd.dwFlags & DSBCAPS_STATIC)) { - /* if this is a streaming buffer, it typically means that - * we should defer mixing past probably_valid_to as long - * as we can, to avoid unnecessary remixing */ - /* the heavy-looking calculations shouldn't be that bad, - * as any game isn't likely to be have more than 1 or 2 - * streaming buffers in use at any time anyway... */ - DWORD probably_valid_left = - (dsb->probably_valid_to == (DWORD)-1) ? dsb->buflen : - ((dsb->probably_valid_to < buf_writepos) ? dsb->buflen : 0) + - dsb->probably_valid_to - buf_writepos; - /* check for leadin condition */ - if ((probably_valid_left == 0) && - (dsb->probably_valid_to == dsb->startpos) && - dsb->leadin) - probably_valid_left = dsb->buflen; - TRACE("streaming buffer probably_valid_to=%ld, probably_valid_left=%ld\n", - dsb->probably_valid_to, probably_valid_left); - /* check whether the app's time is already up */ - if (probably_valid_left < dsb->writelead) { - WARN("probably_valid_to now within writelead, possible streaming underrun\n"); - /* once we pass the point of no return, - * no reason to hold back anymore */ - dsb->probably_valid_to = (DWORD)-1; - /* we just have to go ahead and mix what we have, - * there's no telling what the app is thinking anyway */ - } else { - /* adjust for our frequency and our sample size */ - probably_valid_left = MulDiv(probably_valid_left, - 1 << DSOUND_FREQSHIFT, - dsb->pwfx->nBlockAlign * dsb->freqAdjust) * - dsb->dsound->pwfx->nBlockAlign; - /* check whether to clip mix_len */ - if (probably_valid_left < mixlen) { - TRACE("clipping to probably_valid_left=%ld\n", probably_valid_left); - mixlen = probably_valid_left; - } - } - } - /* cut mixlen with what's already been mixed */ - if (mixlen < primary_done) { - /* huh? and still CalcPlayPosition didn't - * detect an underrun? */ - FIXME("problem with underrun detection (mixlen=%ld < primary_done=%ld)\n", mixlen, primary_done); - return 0; - } - len = mixlen - primary_done; - TRACE("remaining mixlen=%ld\n", len); - - if (len < dsb->dsound->fraglen) { - /* smaller than a fragment, wait until it gets larger - * before we take the mixing overhead */ - TRACE("mixlen not worth it, deferring mixing\n"); - still_behind = 1; - goto post_mix; - } - - /* ok, we know how much to mix, let's go */ - still_behind = (adv_done > primary_done); - while (len) { - slen = dsb->dsound->buflen - dsb->primary_mixpos; - if (slen > len) slen = len; - slen = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, slen); - - if ((dsb->primary_mixpos < dsb->dsound->mixpos) && - (dsb->primary_mixpos + slen >= dsb->dsound->mixpos)) - still_behind = FALSE; - - dsb->primary_mixpos += slen; len -= slen; - dsb->primary_mixpos %= dsb->dsound->buflen; - - if ((dsb->state == STATE_STOPPED) || !slen) break; - } - TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb->primary_mixpos, dsb->dsound->mixpos); - TRACE("mixed data len=%ld, still_behind=%d\n", mixlen-len, still_behind); - -post_mix: - /* check if buffer should be considered complete */ - if (buf_left < dsb->writelead && - !(dsb->playflags & DSBPLAY_LOOPING)) { - dsb->state = STATE_STOPPED; - dsb->playpos = 0; - dsb->last_playpos = 0; - dsb->buf_mixpos = 0; - dsb->leadin = FALSE; - DSOUND_CheckEvent(dsb, buf_left); - } - - /* return how far we think the primary buffer can - * advance its underrun detector...*/ - if (still_behind) return 0; - if ((mixlen - len) < primary_done) return 0; - slen = ((dsb->primary_mixpos < dsb->dsound->mixpos) ? - dsb->dsound->buflen : 0) + dsb->primary_mixpos - - dsb->dsound->mixpos; - if (slen > mixlen) { - /* the primary_done and still_behind checks above should have worked */ - FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen, mixlen); - slen = 0; - } - return slen; -} - -static DWORD DSOUND_MixToPrimary(IDirectSoundImpl *dsound, DWORD playpos, DWORD writepos, DWORD mixlen, BOOL recover) -{ - INT i, len, maxlen = 0; - IDirectSoundBufferImpl *dsb; - - TRACE("(%ld,%ld,%ld,%d)\n", playpos, writepos, mixlen, recover); - for (i = 0; i < dsound->nrofbuffers; i++) { - dsb = dsound->buffers[i]; - - if (dsb->buflen && dsb->state && !dsb->hwbuf) { - TRACE("Checking %p, mixlen=%ld\n", dsb, mixlen); - EnterCriticalSection(&(dsb->lock)); - if (dsb->state == STATE_STOPPING) { - DSOUND_MixCancel(dsb, writepos, TRUE); - dsb->state = STATE_STOPPED; - DSOUND_CheckEvent(dsb, 0); - } else { - if ((dsb->state == STATE_STARTING) || recover) { - dsb->primary_mixpos = writepos; - dsb->cvolpan = dsb->volpan; - dsb->need_remix = FALSE; - } - else if (dsb->need_remix) { - DSOUND_MixCancel(dsb, writepos, TRUE); - dsb->cvolpan = dsb->volpan; - dsb->need_remix = FALSE; - } - len = DSOUND_MixOne(dsb, playpos, writepos, mixlen); - if (dsb->state == STATE_STARTING) - dsb->state = STATE_PLAYING; - maxlen = (len > maxlen) ? len : maxlen; - } - LeaveCriticalSection(&(dsb->lock)); - } - } - - return maxlen; -} - -static void DSOUND_MixReset(IDirectSoundImpl *dsound, DWORD writepos) -{ - INT i; - IDirectSoundBufferImpl *dsb; - int nfiller; - - TRACE("(%ld)\n", writepos); - - /* the sound of silence */ - nfiller = dsound->pwfx->wBitsPerSample == 8 ? 128 : 0; - - /* reset all buffer mix positions */ - for (i = 0; i < dsound->nrofbuffers; i++) { - dsb = dsound->buffers[i]; - - if (dsb->buflen && dsb->state && !dsb->hwbuf) { - TRACE("Resetting %p\n", dsb); - EnterCriticalSection(&(dsb->lock)); - if (dsb->state == STATE_STOPPING) { - dsb->state = STATE_STOPPED; - } - else if (dsb->state == STATE_STARTING) { - /* nothing */ - } else { - DSOUND_MixCancel(dsb, writepos, FALSE); - dsb->cvolpan = dsb->volpan; - dsb->need_remix = FALSE; - } - LeaveCriticalSection(&(dsb->lock)); - } - } - - /* wipe out premixed data */ - if (dsound->mixpos < writepos) { - memset(dsound->buffer + writepos, nfiller, dsound->buflen - writepos); - memset(dsound->buffer, nfiller, dsound->mixpos); - } else { - memset(dsound->buffer + writepos, nfiller, dsound->mixpos - writepos); - } - - /* reset primary mix position */ - dsound->mixpos = writepos; -} - -static void DSOUND_CheckReset(IDirectSoundImpl *dsound, DWORD writepos) -{ - TRACE("(%p,%ld)\n",dsound,writepos); - if (dsound->need_remix) { - DSOUND_MixReset(dsound, writepos); - dsound->need_remix = FALSE; - /* maximize Half-Life performance */ - dsound->prebuf = ds_snd_queue_min; - dsound->precount = 0; - } else { - dsound->precount++; - if (dsound->precount >= 4) { - if (dsound->prebuf < ds_snd_queue_max) - dsound->prebuf++; - dsound->precount = 0; - } - } - TRACE("premix adjust: %d\n", dsound->prebuf); -} - -void DSOUND_WaveQueue(IDirectSoundImpl *dsound, DWORD mixq) -{ - TRACE("(%p,%ld)\n",dsound,mixq); - if (mixq + dsound->pwqueue > ds_hel_queue) mixq = ds_hel_queue - dsound->pwqueue; - TRACE("queueing %ld buffers, starting at %d\n", mixq, dsound->pwwrite); - for (; mixq; mixq--) { - waveOutWrite(dsound->hwo, dsound->pwave[dsound->pwwrite], sizeof(WAVEHDR)); - dsound->pwwrite++; - if (dsound->pwwrite >= DS_HEL_FRAGS) dsound->pwwrite = 0; - dsound->pwqueue++; - } -} - -/* #define SYNC_CALLBACK */ - -void DSOUND_PerformMix(IDirectSoundImpl *dsound) -{ - int nfiller; - BOOL forced; - HRESULT hres; - - TRACE("(%p)\n", dsound); - - /* the sound of silence */ - nfiller = dsound->pwfx->wBitsPerSample == 8 ? 128 : 0; - - /* whether the primary is forced to play even without secondary buffers */ - forced = ((dsound->state == STATE_PLAYING) || (dsound->state == STATE_STARTING)); - - if (dsound->priolevel != DSSCL_WRITEPRIMARY) { - BOOL paused = ((dsound->state == STATE_STOPPED) || (dsound->state == STATE_STARTING)); - /* FIXME: document variables */ - DWORD playpos, writepos, inq, maxq, frag; - if (dsound->hwbuf) { - hres = IDsDriverBuffer_GetPosition(dsound->hwbuf, &playpos, &writepos); - if (hres) { - WARN("IDsDriverBuffer_GetPosition failed\n"); - return; - } - /* Well, we *could* do Just-In-Time mixing using the writepos, - * but that's a little bit ambitious and unnecessary... */ - /* rather add our safety margin to the writepos, if we're playing */ - if (!paused) { - writepos += dsound->writelead; - writepos %= dsound->buflen; - } else writepos = playpos; - } else { - playpos = dsound->pwplay * dsound->fraglen; - writepos = playpos; - if (!paused) { - writepos += ds_hel_margin * dsound->fraglen; - writepos %= dsound->buflen; - } - } - TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld, buflen=%ld\n", - playpos,writepos,dsound->playpos,dsound->mixpos,dsound->buflen); - assert(dsound->playpos < dsound->buflen); - /* wipe out just-played sound data */ - if (playpos < dsound->playpos) { - memset(dsound->buffer + dsound->playpos, nfiller, dsound->buflen - dsound->playpos); - memset(dsound->buffer, nfiller, playpos); - } else { - memset(dsound->buffer + dsound->playpos, nfiller, playpos - dsound->playpos); - } - dsound->playpos = playpos; - - EnterCriticalSection(&(dsound->mixlock)); - - /* reset mixing if necessary */ - DSOUND_CheckReset(dsound, writepos); - - /* check how much prebuffering is left */ - inq = dsound->mixpos; - if (inq < writepos) - inq += dsound->buflen; - inq -= writepos; - - /* find the maximum we can prebuffer */ - if (!paused) { - maxq = playpos; - if (maxq < writepos) - maxq += dsound->buflen; - maxq -= writepos; - } else maxq = dsound->buflen; - - /* clip maxq to dsound->prebuf */ - frag = dsound->prebuf * dsound->fraglen; - if (maxq > frag) maxq = frag; - - /* check for consistency */ - if (inq > maxq) { - /* the playback position must have passed our last - * mixed position, i.e. it's an underrun, or we have - * nothing more to play */ - TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq); - inq = 0; - /* stop the playback now, to allow buffers to refill */ - if (dsound->state == STATE_PLAYING) { - dsound->state = STATE_STARTING; - } - else if (dsound->state == STATE_STOPPING) { - dsound->state = STATE_STOPPED; - } - else { - /* how can we have an underrun if we aren't playing? */ - WARN("unexpected primary state (%ld)\n", dsound->state); - } -#ifdef SYNC_CALLBACK - /* DSOUND_callback may need this lock */ - LeaveCriticalSection(&(dsound->mixlock)); -#endif - if (DSOUND_PrimaryStop(dsound) != DS_OK) - WARN("DSOUND_PrimaryStop failed\n"); -#ifdef SYNC_CALLBACK - EnterCriticalSection(&(dsound->mixlock)); -#endif - if (dsound->hwbuf) { - /* the Stop is supposed to reset play position to beginning of buffer */ - /* unfortunately, OSS is not able to do so, so get current pointer */ - hres = IDsDriverBuffer_GetPosition(dsound->hwbuf, &playpos, NULL); - if (hres) { - LeaveCriticalSection(&(dsound->mixlock)); - WARN("IDsDriverBuffer_GetPosition failed\n"); - return; - } - } else { - playpos = dsound->pwplay * dsound->fraglen; - } - writepos = playpos; - dsound->playpos = playpos; - dsound->mixpos = writepos; - inq = 0; - maxq = dsound->buflen; - if (maxq > frag) maxq = frag; - memset(dsound->buffer, nfiller, dsound->buflen); - paused = TRUE; - } - - /* do the mixing */ - frag = DSOUND_MixToPrimary(dsound, playpos, writepos, maxq, paused); - if (forced) frag = maxq - inq; - dsound->mixpos += frag; - dsound->mixpos %= dsound->buflen; - - if (frag) { - /* buffers have been filled, restart playback */ - if (dsound->state == STATE_STARTING) { - dsound->state = STATE_PLAYING; - } - else if (dsound->state == STATE_STOPPED) { - /* the dsound is supposed to play if there's something to play - * even if it is reported as stopped, so don't let this confuse you */ - dsound->state = STATE_STOPPING; - } - LeaveCriticalSection(&(dsound->mixlock)); - if (paused) { - if (DSOUND_PrimaryPlay(dsound) != DS_OK) - WARN("DSOUND_PrimaryPlay failed\n"); - else - TRACE("starting playback\n"); - } - } - else - LeaveCriticalSection(&(dsound->mixlock)); - } else { - /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */ - if (dsound->state == STATE_STARTING) { - if (DSOUND_PrimaryPlay(dsound) != DS_OK) - WARN("DSOUND_PrimaryPlay failed\n"); - else - dsound->state = STATE_PLAYING; - } - else if (dsound->state == STATE_STOPPING) { - if (DSOUND_PrimaryStop(dsound) != DS_OK) - WARN("DSOUND_PrimaryStop failed\n"); - else - dsound->state = STATE_STOPPED; - } - } -} - -void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2) -{ - IDirectSoundImpl* This = (IDirectSoundImpl*)dwUser; - DWORD start_time = GetTickCount(); - DWORD end_time; - TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2); - TRACE("entering at %ld\n", start_time); - - if (dsound != This) { - ERR("dsound died without killing us?\n"); - timeKillEvent(timerID); - timeEndPeriod(DS_TIME_RES); - return; - } - - RtlAcquireResourceShared(&(This->buffer_list_lock), TRUE); - - if (This->ref) - DSOUND_PerformMix(This); - - RtlReleaseResource(&(This->buffer_list_lock)); - - end_time = GetTickCount(); - TRACE("completed processing at %ld, duration = %ld\n", end_time, end_time - start_time); -} - -void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2) -{ - IDirectSoundImpl* This = (IDirectSoundImpl*)dwUser; - TRACE("(%p,%x,%lx,%lx,%lx)\n",hwo,msg,dwUser,dw1,dw2); - TRACE("entering at %ld, msg=%08x(%s)\n", GetTickCount(), msg, - msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" : - msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN"); - if (msg == MM_WOM_DONE) { - DWORD inq, mixq, fraglen, buflen, pwplay, playpos, mixpos; - if (This->pwqueue == (DWORD)-1) { - TRACE("completed due to reset\n"); - return; - } -/* it could be a bad idea to enter critical section here... if there's lock contention, - * the resulting scheduling delays might obstruct the winmm player thread */ -#ifdef SYNC_CALLBACK - EnterCriticalSection(&(This->mixlock)); -#endif - /* retrieve current values */ - fraglen = This->fraglen; - buflen = This->buflen; - pwplay = This->pwplay; - playpos = pwplay * fraglen; - mixpos = This->mixpos; - /* check remaining mixed data */ - inq = ((mixpos < playpos) ? buflen : 0) + mixpos - playpos; - mixq = inq / fraglen; - if ((inq - (mixq * fraglen)) > 0) mixq++; - /* complete the playing buffer */ - TRACE("done playing primary pos=%ld\n", playpos); - pwplay++; - if (pwplay >= DS_HEL_FRAGS) pwplay = 0; - /* write new values */ - This->pwplay = pwplay; - This->pwqueue--; - /* queue new buffer if we have data for it */ - if (inq>1) DSOUND_WaveQueue(This, inq-1); -#ifdef SYNC_CALLBACK - LeaveCriticalSection(&(This->mixlock)); -#endif - } - TRACE("completed\n"); -} +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include /* Insomnia - pow() function */ + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +void DSOUND_RecalcVolPan(PDSVOLUMEPAN volpan) +{ + double temp; + TRACE("(%p)\n",volpan); + + TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan); + /* the AmpFactors are expressed in 16.16 fixed point */ + volpan->dwVolAmpFactor = (ULONG) (pow(2.0, volpan->lVolume / 600.0) * 0xffff); + /* FIXME: dwPan{Left|Right}AmpFactor */ + + /* FIXME: use calculated vol and pan ampfactors */ + temp = (double) (volpan->lVolume - (volpan->lPan > 0 ? volpan->lPan : 0)); + volpan->dwTotalLeftAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); + temp = (double) (volpan->lVolume + (volpan->lPan < 0 ? volpan->lPan : 0)); + volpan->dwTotalRightAmpFactor = (ULONG) (pow(2.0, temp / 600.0) * 0xffff); + + TRACE("left = %lx, right = %lx\n", volpan->dwTotalLeftAmpFactor, volpan->dwTotalRightAmpFactor); +} + +void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan) +{ + double left,right; + TRACE("(%p)\n",volpan); + + TRACE("left=%lx, right=%lx\n",volpan->dwTotalLeftAmpFactor,volpan->dwTotalRightAmpFactor); + if (volpan->dwTotalLeftAmpFactor==0) + left=-10000; + else + left=600 * log(((double)volpan->dwTotalLeftAmpFactor) / 0xffff) / log(2); + if (volpan->dwTotalRightAmpFactor==0) + right=-10000; + else + right=600 * log(((double)volpan->dwTotalRightAmpFactor) / 0xffff) / log(2); + if (leftlVolume=right; + volpan->dwVolAmpFactor=volpan->dwTotalRightAmpFactor; + } + else + { + volpan->lVolume=left; + volpan->dwVolAmpFactor=volpan->dwTotalLeftAmpFactor; + } + if (volpan->lVolume < -10000) + volpan->lVolume=-10000; + volpan->lPan=right-left; + if (volpan->lPan < -10000) + volpan->lPan=-10000; + + TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan); +} + +void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) +{ + TRACE("(%p)\n",dsb); + + /* calculate the 10ms write lead */ + dsb->writelead = (dsb->freq / 100) * dsb->pwfx->nBlockAlign; +} + +void DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len) +{ + int i; + DWORD offset; + LPDSBPOSITIONNOTIFY event; + TRACE("(%p,%d)\n",dsb,len); + + if (dsb->nrofnotifies == 0) + return; + + TRACE("(%p) buflen = %ld, playpos = %ld, len = %d\n", + dsb, dsb->buflen, dsb->playpos, len); + for (i = 0; i < dsb->nrofnotifies ; i++) { + event = dsb->notifies + i; + offset = event->dwOffset; + TRACE("checking %d, position %ld, event = %p\n", + i, offset, event->hEventNotify); + /* DSBPN_OFFSETSTOP has to be the last element. So this is */ + /* OK. [Inside DirectX, p274] */ + /* */ + /* This also means we can't sort the entries by offset, */ + /* because DSBPN_OFFSETSTOP == -1 */ + if (offset == DSBPN_OFFSETSTOP) { + if (dsb->state == STATE_STOPPED) { + SetEvent(event->hEventNotify); + TRACE("signalled event %p (%d)\n", event->hEventNotify, i); + return; + } else + return; + } + if ((dsb->playpos + len) >= dsb->buflen) { + if ((offset < ((dsb->playpos + len) % dsb->buflen)) || + (offset >= dsb->playpos)) { + TRACE("signalled event %p (%d)\n", event->hEventNotify, i); + SetEvent(event->hEventNotify); + } + } else { + if ((offset >= dsb->playpos) && (offset < (dsb->playpos + len))) { + TRACE("signalled event %p (%d)\n", event->hEventNotify, i); + SetEvent(event->hEventNotify); + } + } + } +} + +/* WAV format info can be found at: + * + * http://www.cwi.nl/ftp/audio/AudioFormats.part2 + * ftp://ftp.cwi.nl/pub/audio/RIFF-format + * + * Import points to remember: + * 8-bit WAV is unsigned + * 16-bit WAV is signed + */ + /* Use the same formulas as pcmconverter.c */ +static inline INT16 cvtU8toS16(BYTE b) +{ + return (short)((b+(b << 8))-32768); +} + +static inline BYTE cvtS16toU8(INT16 s) +{ + return (s >> 8) ^ (unsigned char)0x80; +} + +static inline void cp_fields(const IDirectSoundBufferImpl *dsb, BYTE *ibuf, BYTE *obuf ) +{ + DirectSoundDevice * device = dsb->dsound->device; + INT fl,fr; + + if (dsb->pwfx->wBitsPerSample == 8) { + if (device->pwfx->wBitsPerSample == 8 && + device->pwfx->nChannels == dsb->pwfx->nChannels) { + /* avoid needless 8->16->8 conversion */ + *obuf=*ibuf; + if (dsb->pwfx->nChannels==2) + *(obuf+1)=*(ibuf+1); + return; + } + fl = cvtU8toS16(*ibuf); + fr = (dsb->pwfx->nChannels==2 ? cvtU8toS16(*(ibuf + 1)) : fl); + } else { + fl = *((INT16 *)ibuf); + fr = (dsb->pwfx->nChannels==2 ? *(((INT16 *)ibuf) + 1) : fl); + } + + if (device->pwfx->nChannels == 2) { + if (device->pwfx->wBitsPerSample == 8) { + *obuf = cvtS16toU8(fl); + *(obuf + 1) = cvtS16toU8(fr); + return; + } + if (device->pwfx->wBitsPerSample == 16) { + *((INT16 *)obuf) = fl; + *(((INT16 *)obuf) + 1) = fr; + return; + } + } + if (device->pwfx->nChannels == 1) { + fl = (fl + fr) >> 1; + if (device->pwfx->wBitsPerSample == 8) { + *obuf = cvtS16toU8(fl); + return; + } + if (device->pwfx->wBitsPerSample == 16) { + *((INT16 *)obuf) = fl; + return; + } + } +} + +/* Now with PerfectPitch (tm) technology */ +static INT DSOUND_MixerNorm(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) +{ + INT i, size, ipos, ilen; + BYTE *ibp, *obp; + INT iAdvance = dsb->pwfx->nBlockAlign; + INT oAdvance = dsb->dsound->device->pwfx->nBlockAlign; + + ibp = dsb->buffer->memory + dsb->buf_mixpos; + obp = buf; + + TRACE("(%p, %p, %p), buf_mixpos=%ld\n", dsb, ibp, obp, dsb->buf_mixpos); + /* Check for the best case */ + if ((dsb->freq == dsb->dsound->device->pwfx->nSamplesPerSec) && + (dsb->pwfx->wBitsPerSample == dsb->dsound->device->pwfx->wBitsPerSample) && + (dsb->pwfx->nChannels == dsb->dsound->device->pwfx->nChannels)) { + INT bytesleft = dsb->buflen - dsb->buf_mixpos; + TRACE("(%p) Best case\n", dsb); + if (len <= bytesleft ) + CopyMemory(obp, ibp, len); + else { /* wrap */ + CopyMemory(obp, ibp, bytesleft); + CopyMemory(obp + bytesleft, dsb->buffer->memory, len - bytesleft); + } + return len; + } + + /* Check for same sample rate */ + if (dsb->freq == dsb->dsound->device->pwfx->nSamplesPerSec) { + TRACE("(%p) Same sample rate %ld = primary %ld\n", dsb, + dsb->freq, dsb->dsound->device->pwfx->nSamplesPerSec); + ilen = 0; + for (i = 0; i < len; i += oAdvance) { + cp_fields(dsb, ibp, obp ); + ibp += iAdvance; + ilen += iAdvance; + obp += oAdvance; + if (ibp >= (BYTE *)(dsb->buffer->memory + dsb->buflen)) + ibp = dsb->buffer->memory; /* wrap */ + } + return (ilen); + } + + /* Mix in different sample rates */ + /* */ + /* New PerfectPitch(tm) Technology (c) 1998 Rob Riggs */ + /* Patent Pending :-] */ + + /* Patent enhancements (c) 2000 Ove Kåven, + * TransGaming Technologies Inc. */ + + /* FIXME("(%p) Adjusting frequency: %ld -> %ld (need optimization)\n", + dsb, dsb->freq, dsb->dsound->device->pwfx->nSamplesPerSec); */ + + size = len / oAdvance; + ilen = 0; + ipos = dsb->buf_mixpos; + for (i = 0; i < size; i++) { + cp_fields(dsb, (dsb->buffer->memory + ipos), obp); + obp += oAdvance; + dsb->freqAcc += dsb->freqAdjust; + if (dsb->freqAcc >= (1<freqAcc>>DSOUND_FREQSHIFT) * iAdvance; + dsb->freqAcc &= (1<buflen; + } + } + return ilen; +} + +static void DSOUND_MixerVol(IDirectSoundBufferImpl *dsb, BYTE *buf, INT len) +{ + INT i; + BYTE *bpc = buf; + INT16 *bps = (INT16 *) buf; + + TRACE("(%p,%p,%d)\n",dsb,buf,len); + TRACE("left = %lx, right = %lx\n", dsb->cvolpan.dwTotalLeftAmpFactor, + dsb->cvolpan.dwTotalRightAmpFactor); + + if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->cvolpan.lPan == 0)) && + (!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->cvolpan.lVolume == 0)) && + !(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) + return; /* Nothing to do */ + + /* If we end up with some bozo coder using panning or 3D sound */ + /* with a mono primary buffer, it could sound very weird using */ + /* this method. Oh well, tough patooties. */ + + switch (dsb->dsound->device->pwfx->wBitsPerSample) { + case 8: + /* 8-bit WAV is unsigned, but we need to operate */ + /* on signed data for this to work properly */ + switch (dsb->dsound->device->pwfx->nChannels) { + case 1: + for (i = 0; i < len; i++) { + INT val = *bpc - 128; + val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; + *bpc = val + 128; + bpc++; + } + break; + case 2: + for (i = 0; i < len; i+=2) { + INT val = *bpc - 128; + val = (val * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; + *bpc++ = val + 128; + val = *bpc - 128; + val = (val * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; + *bpc = val + 128; + bpc++; + } + break; + default: + FIXME("doesn't support %d channels\n", dsb->dsound->device->pwfx->nChannels); + break; + } + break; + case 16: + /* 16-bit WAV is signed -- much better */ + switch (dsb->dsound->device->pwfx->nChannels) { + case 1: + for (i = 0; i < len; i += 2) { + *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; + bps++; + } + break; + case 2: + for (i = 0; i < len; i += 4) { + *bps = (*bps * dsb->cvolpan.dwTotalLeftAmpFactor) >> 16; + bps++; + *bps = (*bps * dsb->cvolpan.dwTotalRightAmpFactor) >> 16; + bps++; + } + break; + default: + FIXME("doesn't support %d channels\n", dsb->dsound->device->pwfx->nChannels); + break; + } + break; + default: + FIXME("doesn't support %d bit samples\n", dsb->dsound->device->pwfx->wBitsPerSample); + break; + } +} + +static LPBYTE DSOUND_tmpbuffer(DirectSoundDevice *device, DWORD len) +{ + TRACE("(%p,%ld)\n", device, len); + + if (len > device->tmp_buffer_len) { + if (device->tmp_buffer) + device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, device->tmp_buffer, len); + else + device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, len); + + device->tmp_buffer_len = len; + } + + return device->tmp_buffer; +} + +static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen) +{ + INT i, len, ilen, field, todo; + BYTE *buf, *ibuf; + + TRACE("(%p,%ld,%ld)\n",dsb,writepos,fraglen); + + len = fraglen; + if (!(dsb->playflags & DSBPLAY_LOOPING)) { + int secondary_remainder = dsb->buflen - dsb->buf_mixpos; + int adjusted_remainder = MulDiv(dsb->dsound->device->pwfx->nAvgBytesPerSec, secondary_remainder, dsb->nAvgBytesPerSec); + assert(adjusted_remainder >= 0); + TRACE("secondary_remainder = %d, adjusted_remainder = %d, len = %d\n", secondary_remainder, adjusted_remainder, len); + if (adjusted_remainder < len) { + TRACE("clipping len to remainder of secondary buffer\n"); + len = adjusted_remainder; + } + if (len == 0) + return 0; + } + + if (len % dsb->dsound->device->pwfx->nBlockAlign) { + INT nBlockAlign = dsb->dsound->device->pwfx->nBlockAlign; + ERR("length not a multiple of block size, len = %d, block size = %d\n", len, nBlockAlign); + len = (len / nBlockAlign) * nBlockAlign; /* data alignment */ + } + + if ((buf = ibuf = DSOUND_tmpbuffer(dsb->dsound->device, len)) == NULL) + return 0; + + TRACE("MixInBuffer (%p) len = %d, dest = %ld\n", dsb, len, writepos); + + ilen = DSOUND_MixerNorm(dsb, ibuf, len); + if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || + (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || + (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) + DSOUND_MixerVol(dsb, ibuf, len); + + if (dsb->dsound->device->pwfx->wBitsPerSample == 8) { + BYTE *obuf = dsb->dsound->device->buffer + writepos; + + if ((writepos + len) <= dsb->dsound->device->buflen) + todo = len; + else + todo = dsb->dsound->device->buflen - writepos; + + for (i = 0; i < todo; i++) { + /* 8-bit WAV is unsigned */ + field = (*ibuf++ - 128); + field += (*obuf - 128); + if (field > 127) field = 127; + else if (field < -128) field = -128; + *obuf++ = field + 128; + } + + if (todo < len) { + todo = len - todo; + obuf = dsb->dsound->device->buffer; + + for (i = 0; i < todo; i++) { + /* 8-bit WAV is unsigned */ + field = (*ibuf++ - 128); + field += (*obuf - 128); + if (field > 127) field = 127; + else if (field < -128) field = -128; + *obuf++ = field + 128; + } + } + } else { + INT16 *ibufs, *obufs; + + ibufs = (INT16 *) ibuf; + obufs = (INT16 *)(dsb->dsound->device->buffer + writepos); + + if ((writepos + len) <= dsb->dsound->device->buflen) + todo = len / 2; + else + todo = (dsb->dsound->device->buflen - writepos) / 2; + + for (i = 0; i < todo; i++) { + /* 16-bit WAV is signed */ + field = *ibufs++; + field += *obufs; + if (field > 32767) field = 32767; + else if (field < -32768) field = -32768; + *obufs++ = field; + } + + if (todo < (len / 2)) { + todo = (len / 2) - todo; + obufs = (INT16 *)dsb->dsound->device->buffer; + + for (i = 0; i < todo; i++) { + /* 16-bit WAV is signed */ + field = *ibufs++; + field += *obufs; + if (field > 32767) field = 32767; + else if (field < -32768) field = -32768; + *obufs++ = field; + } + } + } + + if (dsb->leadin && (dsb->startpos > dsb->buf_mixpos) && (dsb->startpos <= dsb->buf_mixpos + ilen)) { + /* HACK... leadin should be reset when the PLAY position reaches the startpos, + * not the MIX position... but if the sound buffer is bigger than our prebuffering + * (which must be the case for the streaming buffers that need this hack anyway) + * plus DS_HEL_MARGIN or equivalent, then this ought to work anyway. */ + dsb->leadin = FALSE; + } + + dsb->buf_mixpos += ilen; + + if (dsb->buf_mixpos >= dsb->buflen) { + if (dsb->playflags & DSBPLAY_LOOPING) { + /* wrap */ + dsb->buf_mixpos %= dsb->buflen; + if (dsb->leadin && (dsb->startpos <= dsb->buf_mixpos)) + dsb->leadin = FALSE; /* HACK: see above */ + } else if (dsb->buf_mixpos > dsb->buflen) { + ERR("Mixpos (%lu) past buflen (%lu), capping...\n", dsb->buf_mixpos, dsb->buflen); + dsb->buf_mixpos = dsb->buflen; + } + } + + return len; +} + +static void DSOUND_PhaseCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD len) +{ + INT ilen, field; + UINT i, todo; + BYTE *buf, *ibuf; + + TRACE("(%p,%ld,%ld)\n",dsb,writepos,len); + + if (len % dsb->dsound->device->pwfx->nBlockAlign) { + INT nBlockAlign = dsb->dsound->device->pwfx->nBlockAlign; + ERR("length not a multiple of block size, len = %ld, block size = %d\n", len, nBlockAlign); + len = (len / nBlockAlign) * nBlockAlign; /* data alignment */ + } + + if ((buf = ibuf = DSOUND_tmpbuffer(dsb->dsound->device, len)) == NULL) + return; + + TRACE("PhaseCancel (%p) len = %ld, dest = %ld\n", dsb, len, writepos); + + ilen = DSOUND_MixerNorm(dsb, ibuf, len); + if ((dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || + (dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || + (dsb->dsbd.dwFlags & DSBCAPS_CTRL3D)) + DSOUND_MixerVol(dsb, ibuf, len); + + /* subtract instead of add, to phase out premixed data */ + if (dsb->dsound->device->pwfx->wBitsPerSample == 8) { + BYTE *obuf = dsb->dsound->device->buffer + writepos; + + if ((writepos + len) <= dsb->dsound->device->buflen) + todo = len; + else + todo = dsb->dsound->device->buflen - writepos; + + for (i = 0; i < todo; i++) { + /* 8-bit WAV is unsigned */ + field = (*ibuf++ - 128); + field -= (*obuf - 128); + if (field > 127) field = 127; + else if (field < -128) field = -128; + *obuf++ = field + 128; + } + + if (todo < len) { + todo = len - todo; + obuf = dsb->dsound->device->buffer; + + for (i = 0; i < todo; i++) { + /* 8-bit WAV is unsigned */ + field = (*ibuf++ - 128); + field -= (*obuf - 128); + if (field > 127) field = 127; + else if (field < -128) field = -128; + *obuf++ = field + 128; + } + } + } else { + INT16 *ibufs, *obufs; + + ibufs = (INT16 *) ibuf; + obufs = (INT16 *)(dsb->dsound->device->buffer + writepos); + + if ((writepos + len) <= dsb->dsound->device->buflen) + todo = len / 2; + else + todo = (dsb->dsound->device->buflen - writepos) / 2; + + for (i = 0; i < todo; i++) { + /* 16-bit WAV is signed */ + field = *ibufs++; + field -= *obufs; + if (field > 32767) field = 32767; + else if (field < -32768) field = -32768; + *obufs++ = field; + } + + if (todo < (len / 2)) { + todo = (len / 2) - todo; + obufs = (INT16 *)dsb->dsound->device->buffer; + + for (i = 0; i < todo; i++) { + /* 16-bit WAV is signed */ + field = *ibufs++; + field -= *obufs; + if (field > 32767) field = 32767; + else if (field < -32768) field = -32768; + *obufs++ = field; + } + } + } +} + +static void DSOUND_MixCancel(IDirectSoundBufferImpl *dsb, DWORD writepos, BOOL cancel) +{ + DWORD size, flen, len, npos, nlen; + INT iAdvance = dsb->pwfx->nBlockAlign; + INT oAdvance = dsb->dsound->device->pwfx->nBlockAlign; + /* determine amount of premixed data to cancel */ + DWORD primary_done = + ((dsb->primary_mixpos < writepos) ? dsb->dsound->device->buflen : 0) + + dsb->primary_mixpos - writepos; + + TRACE("(%p, %ld), buf_mixpos=%ld\n", dsb, writepos, dsb->buf_mixpos); + + /* backtrack the mix position */ + size = primary_done / oAdvance; + flen = size * dsb->freqAdjust; + len = (flen >> DSOUND_FREQSHIFT) * iAdvance; + flen &= (1<freqAcc < flen) { + len += iAdvance; + dsb->freqAcc += 1<buflen; + npos = ((dsb->buf_mixpos < len) ? dsb->buflen : 0) + + dsb->buf_mixpos - len; + if (dsb->leadin && (dsb->startpos > npos) && (dsb->startpos <= npos + len)) { + /* stop backtracking at startpos */ + npos = dsb->startpos; + len = ((dsb->buf_mixpos < npos) ? dsb->buflen : 0) + + dsb->buf_mixpos - npos; + flen = dsb->freqAcc; + nlen = len / dsb->pwfx->nBlockAlign; + nlen = ((nlen << DSOUND_FREQSHIFT) + flen) / dsb->freqAdjust; + nlen *= dsb->dsound->device->pwfx->nBlockAlign; + writepos = + ((dsb->primary_mixpos < nlen) ? dsb->dsound->device->buflen : 0) + + dsb->primary_mixpos - nlen; + } + + dsb->freqAcc -= flen; + dsb->buf_mixpos = npos; + dsb->primary_mixpos = writepos; + + TRACE("new buf_mixpos=%ld, primary_mixpos=%ld (len=%ld)\n", + dsb->buf_mixpos, dsb->primary_mixpos, len); + + if (cancel) DSOUND_PhaseCancel(dsb, writepos, len); +} + +void DSOUND_MixCancelAt(IDirectSoundBufferImpl *dsb, DWORD buf_writepos) +{ +#if 0 + DWORD i, size, flen, len, npos, nlen; + INT iAdvance = dsb->pwfx->nBlockAlign; + INT oAdvance = dsb->dsound->device->pwfx->nBlockAlign; + /* determine amount of premixed data to cancel */ + DWORD buf_done = + ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) + + dsb->buf_mixpos - buf_writepos; +#endif + + WARN("(%p, %ld), buf_mixpos=%ld\n", dsb, buf_writepos, dsb->buf_mixpos); + /* since this is not implemented yet, just cancel *ALL* prebuffering for now + * (which is faster anyway when there's only a single secondary buffer) */ + dsb->dsound->device->need_remix = TRUE; +} + +void DSOUND_ForceRemix(IDirectSoundBufferImpl *dsb) +{ + TRACE("(%p)\n",dsb); + EnterCriticalSection(&dsb->lock); + if (dsb->state == STATE_PLAYING) + dsb->dsound->device->need_remix = TRUE; + LeaveCriticalSection(&dsb->lock); +} + +static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD writepos, DWORD mixlen) +{ + DWORD len, slen; + /* determine this buffer's write position */ + DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, writepos, writepos); + /* determine how much already-mixed data exists */ + DWORD buf_done = + ((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) + + dsb->buf_mixpos - buf_writepos; + DWORD primary_done = + ((dsb->primary_mixpos < writepos) ? dsb->dsound->device->buflen : 0) + + dsb->primary_mixpos - writepos; + DWORD adv_done = + ((dsb->dsound->device->mixpos < writepos) ? dsb->dsound->device->buflen : 0) + + dsb->dsound->device->mixpos - writepos; + DWORD played = + ((buf_writepos < dsb->playpos) ? dsb->buflen : 0) + + buf_writepos - dsb->playpos; + DWORD buf_left = dsb->buflen - buf_writepos; + int still_behind; + + TRACE("(%p,%ld,%ld,%ld)\n",dsb,playpos,writepos,mixlen); + TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos, writepos); + TRACE("buf_done=%ld, primary_done=%ld\n", buf_done, primary_done); + TRACE("buf_mixpos=%ld, primary_mixpos=%ld, mixlen=%ld\n", dsb->buf_mixpos, dsb->primary_mixpos, + mixlen); + TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb->playflags, dsb->startpos, dsb->leadin); + + /* check for notification positions */ + if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY && + dsb->state != STATE_STARTING) { + DSOUND_CheckEvent(dsb, played); + } + + /* save write position for non-GETCURRENTPOSITION2... */ + dsb->playpos = buf_writepos; + + /* check whether CalcPlayPosition detected a mixing underrun */ + if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) { + /* it did, but did we have more to play? */ + if ((dsb->playflags & DSBPLAY_LOOPING) || + (dsb->buf_mixpos < dsb->buflen)) { + /* yes, have to recover */ + ERR("underrun on sound buffer %p\n", dsb); + TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos); + } + dsb->primary_mixpos = writepos; + primary_done = 0; + } + /* determine how far ahead we should mix */ + if (((dsb->playflags & DSBPLAY_LOOPING) || + (dsb->leadin && (dsb->probably_valid_to != 0))) && + !(dsb->dsbd.dwFlags & DSBCAPS_STATIC)) { + /* if this is a streaming buffer, it typically means that + * we should defer mixing past probably_valid_to as long + * as we can, to avoid unnecessary remixing */ + /* the heavy-looking calculations shouldn't be that bad, + * as any game isn't likely to be have more than 1 or 2 + * streaming buffers in use at any time anyway... */ + DWORD probably_valid_left = + (dsb->probably_valid_to == (DWORD)-1) ? dsb->buflen : + ((dsb->probably_valid_to < buf_writepos) ? dsb->buflen : 0) + + dsb->probably_valid_to - buf_writepos; + /* check for leadin condition */ + if ((probably_valid_left == 0) && + (dsb->probably_valid_to == dsb->startpos) && + dsb->leadin) + probably_valid_left = dsb->buflen; + TRACE("streaming buffer probably_valid_to=%ld, probably_valid_left=%ld\n", + dsb->probably_valid_to, probably_valid_left); + /* check whether the app's time is already up */ + if (probably_valid_left < dsb->writelead) { + WARN("probably_valid_to now within writelead, possible streaming underrun\n"); + /* once we pass the point of no return, + * no reason to hold back anymore */ + dsb->probably_valid_to = (DWORD)-1; + /* we just have to go ahead and mix what we have, + * there's no telling what the app is thinking anyway */ + } else { + /* adjust for our frequency and our sample size */ + probably_valid_left = MulDiv(probably_valid_left, + 1 << DSOUND_FREQSHIFT, + dsb->pwfx->nBlockAlign * dsb->freqAdjust) * + dsb->dsound->device->pwfx->nBlockAlign; + /* check whether to clip mix_len */ + if (probably_valid_left < mixlen) { + TRACE("clipping to probably_valid_left=%ld\n", probably_valid_left); + mixlen = probably_valid_left; + } + } + } + /* cut mixlen with what's already been mixed */ + if (mixlen < primary_done) { + /* huh? and still CalcPlayPosition didn't + * detect an underrun? */ + FIXME("problem with underrun detection (mixlen=%ld < primary_done=%ld)\n", mixlen, primary_done); + return 0; + } + len = mixlen - primary_done; + TRACE("remaining mixlen=%ld\n", len); + + if (len < dsb->dsound->device->fraglen) { + /* smaller than a fragment, wait until it gets larger + * before we take the mixing overhead */ + TRACE("mixlen not worth it, deferring mixing\n"); + still_behind = 1; + goto post_mix; + } + + /* ok, we know how much to mix, let's go */ + still_behind = (adv_done > primary_done); + while (len) { + slen = dsb->dsound->device->buflen - dsb->primary_mixpos; + if (slen > len) slen = len; + slen = DSOUND_MixInBuffer(dsb, dsb->primary_mixpos, slen); + + if ((dsb->primary_mixpos < dsb->dsound->device->mixpos) && + (dsb->primary_mixpos + slen >= dsb->dsound->device->mixpos)) + still_behind = FALSE; + + dsb->primary_mixpos += slen; len -= slen; + dsb->primary_mixpos %= dsb->dsound->device->buflen; + + if ((dsb->state == STATE_STOPPED) || !slen) break; + } + TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb->primary_mixpos, dsb->dsound->device->mixpos); + TRACE("mixed data len=%ld, still_behind=%d\n", mixlen-len, still_behind); + +post_mix: + /* check if buffer should be considered complete */ + if (buf_left < dsb->writelead && + !(dsb->playflags & DSBPLAY_LOOPING)) { + dsb->state = STATE_STOPPED; + dsb->playpos = 0; + dsb->last_playpos = 0; + dsb->buf_mixpos = 0; + dsb->leadin = FALSE; + dsb->need_remix = FALSE; + DSOUND_CheckEvent(dsb, buf_left); + } + + /* return how far we think the primary buffer can + * advance its underrun detector...*/ + if (still_behind) return 0; + if ((mixlen - len) < primary_done) return 0; + slen = ((dsb->primary_mixpos < dsb->dsound->device->mixpos) ? + dsb->dsound->device->buflen : 0) + dsb->primary_mixpos - + dsb->dsound->device->mixpos; + if (slen > mixlen) { + /* the primary_done and still_behind checks above should have worked */ + FIXME("problem with advancement calculation (advlen=%ld > mixlen=%ld)\n", slen, mixlen); + slen = 0; + } + return slen; +} + +static DWORD DSOUND_MixToPrimary(DirectSoundDevice *device, DWORD playpos, DWORD writepos, DWORD mixlen, BOOL recover) +{ + INT i, len, maxlen = 0; + IDirectSoundBufferImpl *dsb; + + TRACE("(%ld,%ld,%ld,%d)\n", playpos, writepos, mixlen, recover); + for (i = 0; i < device->nrofbuffers; i++) { + dsb = device->buffers[i]; + + if (dsb->buflen && dsb->state && !dsb->hwbuf) { + TRACE("Checking %p, mixlen=%ld\n", dsb, mixlen); + EnterCriticalSection(&(dsb->lock)); + if (dsb->state == STATE_STOPPING) { + DSOUND_MixCancel(dsb, writepos, TRUE); + dsb->state = STATE_STOPPED; + DSOUND_CheckEvent(dsb, 0); + } else { + if ((dsb->state == STATE_STARTING) || recover) { + dsb->primary_mixpos = writepos; + dsb->cvolpan = dsb->volpan; + dsb->need_remix = FALSE; + } + else if (dsb->need_remix) { + DSOUND_MixCancel(dsb, writepos, TRUE); + dsb->cvolpan = dsb->volpan; + dsb->need_remix = FALSE; + } + len = DSOUND_MixOne(dsb, playpos, writepos, mixlen); + if (dsb->state == STATE_STARTING) + dsb->state = STATE_PLAYING; + maxlen = (len > maxlen) ? len : maxlen; + } + LeaveCriticalSection(&(dsb->lock)); + } + } + + return maxlen; +} + +static void DSOUND_MixReset(DirectSoundDevice *device, DWORD writepos) +{ + INT i; + IDirectSoundBufferImpl *dsb; + int nfiller; + + TRACE("(%p,%ld)\n", device, writepos); + + /* the sound of silence */ + nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0; + + /* reset all buffer mix positions */ + for (i = 0; i < device->nrofbuffers; i++) { + dsb = device->buffers[i]; + + if (dsb->buflen && dsb->state && !dsb->hwbuf) { + TRACE("Resetting %p\n", dsb); + EnterCriticalSection(&(dsb->lock)); + if (dsb->state == STATE_STOPPING) { + dsb->state = STATE_STOPPED; + } + else if (dsb->state == STATE_STARTING) { + /* nothing */ + } else { + DSOUND_MixCancel(dsb, writepos, FALSE); + dsb->cvolpan = dsb->volpan; + dsb->need_remix = FALSE; + } + LeaveCriticalSection(&(dsb->lock)); + } + } + + /* wipe out premixed data */ + if (device->mixpos < writepos) { + FillMemory(device->buffer + writepos, device->buflen - writepos, nfiller); + FillMemory(device->buffer, device->mixpos, nfiller); + } else { + FillMemory(device->buffer + writepos, device->mixpos - writepos, nfiller); + } + + /* reset primary mix position */ + device->mixpos = writepos; +} + +static void DSOUND_CheckReset(DirectSoundDevice *device, DWORD writepos) +{ + TRACE("(%p,%ld)\n",device,writepos); + if (device->need_remix) { + DSOUND_MixReset(device, writepos); + device->need_remix = FALSE; + /* maximize Half-Life performance */ + device->prebuf = ds_snd_queue_min; + device->precount = 0; + } else { + device->precount++; + if (device->precount >= 4) { + if (device->prebuf < ds_snd_queue_max) + device->prebuf++; + device->precount = 0; + } + } + TRACE("premix adjust: %d\n", device->prebuf); +} + +void DSOUND_WaveQueue(DirectSoundDevice *device, DWORD mixq) +{ + TRACE("(%p,%ld)\n", device, mixq); + if (mixq + device->pwqueue > ds_hel_queue) mixq = ds_hel_queue - device->pwqueue; + TRACE("queueing %ld buffers, starting at %d\n", mixq, device->pwwrite); + for (; mixq; mixq--) { + waveOutWrite(device->hwo, device->pwave[device->pwwrite], sizeof(WAVEHDR)); + device->pwwrite++; + if (device->pwwrite >= DS_HEL_FRAGS) device->pwwrite = 0; + device->pwqueue++; + } +} + +/* #define SYNC_CALLBACK */ + +void DSOUND_PerformMix(DirectSoundDevice *device) +{ + int nfiller; + BOOL forced; + HRESULT hres; + + TRACE("(%p)\n", device); + + /* the sound of silence */ + nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0; + + /* whether the primary is forced to play even without secondary buffers */ + forced = ((device->state == STATE_PLAYING) || (device->state == STATE_STARTING)); + + if (device->priolevel != DSSCL_WRITEPRIMARY) { + BOOL paused = ((device->state == STATE_STOPPED) || (device->state == STATE_STARTING)); + /* FIXME: document variables */ + DWORD playpos, writepos, inq, maxq, frag; + if (device->hwbuf) { + hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, &writepos); + if (hres) { + WARN("IDsDriverBuffer_GetPosition failed\n"); + return; + } + /* Well, we *could* do Just-In-Time mixing using the writepos, + * but that's a little bit ambitious and unnecessary... */ + /* rather add our safety margin to the writepos, if we're playing */ + if (!paused) { + writepos += device->writelead; + writepos %= device->buflen; + } else writepos = playpos; + } else { + playpos = device->pwplay * device->fraglen; + writepos = playpos; + if (!paused) { + writepos += ds_hel_margin * device->fraglen; + writepos %= device->buflen; + } + } + TRACE("primary playpos=%ld, writepos=%ld, clrpos=%ld, mixpos=%ld, buflen=%ld\n", + playpos,writepos,device->playpos,device->mixpos,device->buflen); + assert(device->playpos < device->buflen); + /* wipe out just-played sound data */ + if (playpos < device->playpos) { + FillMemory(device->buffer + device->playpos, device->buflen - device->playpos, nfiller); + FillMemory(device->buffer, playpos, nfiller); + } else { + FillMemory(device->buffer + device->playpos, playpos - device->playpos, nfiller); + } + device->playpos = playpos; + + EnterCriticalSection(&(device->mixlock)); + + /* reset mixing if necessary */ + DSOUND_CheckReset(device, writepos); + + /* check how much prebuffering is left */ + inq = device->mixpos; + if (inq < writepos) + inq += device->buflen; + inq -= writepos; + + /* find the maximum we can prebuffer */ + if (!paused) { + maxq = playpos; + if (maxq < writepos) + maxq += device->buflen; + maxq -= writepos; + } else maxq = device->buflen; + + /* clip maxq to device->prebuf */ + frag = device->prebuf * device->fraglen; + if (maxq > frag) maxq = frag; + + /* check for consistency */ + if (inq > maxq) { + /* the playback position must have passed our last + * mixed position, i.e. it's an underrun, or we have + * nothing more to play */ + TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq); + inq = 0; + /* stop the playback now, to allow buffers to refill */ + if (device->state == STATE_PLAYING) { + device->state = STATE_STARTING; + } + else if (device->state == STATE_STOPPING) { + device->state = STATE_STOPPED; + } + else { + /* how can we have an underrun if we aren't playing? */ + WARN("unexpected primary state (%ld)\n", device->state); + } +#ifdef SYNC_CALLBACK + /* DSOUND_callback may need this lock */ + LeaveCriticalSection(&(device->mixlock)); +#endif + if (DSOUND_PrimaryStop(device) != DS_OK) + WARN("DSOUND_PrimaryStop failed\n"); +#ifdef SYNC_CALLBACK + EnterCriticalSection(&(device->mixlock)); +#endif + if (device->hwbuf) { + /* the Stop is supposed to reset play position to beginning of buffer */ + /* unfortunately, OSS is not able to do so, so get current pointer */ + hres = IDsDriverBuffer_GetPosition(device->hwbuf, &playpos, NULL); + if (hres) { + LeaveCriticalSection(&(device->mixlock)); + WARN("IDsDriverBuffer_GetPosition failed\n"); + return; + } + } else { + playpos = device->pwplay * device->fraglen; + } + writepos = playpos; + device->playpos = playpos; + device->mixpos = writepos; + inq = 0; + maxq = device->buflen; + if (maxq > frag) maxq = frag; + FillMemory(device->buffer, device->buflen, nfiller); + paused = TRUE; + } + + /* do the mixing */ + frag = DSOUND_MixToPrimary(device, playpos, writepos, maxq, paused); + if (forced) frag = maxq - inq; + device->mixpos += frag; + device->mixpos %= device->buflen; + + if (frag) { + /* buffers have been filled, restart playback */ + if (device->state == STATE_STARTING) { + device->state = STATE_PLAYING; + } + else if (device->state == STATE_STOPPED) { + /* the dsound is supposed to play if there's something to play + * even if it is reported as stopped, so don't let this confuse you */ + device->state = STATE_STOPPING; + } + LeaveCriticalSection(&(device->mixlock)); + if (paused) { + if (DSOUND_PrimaryPlay(device) != DS_OK) + WARN("DSOUND_PrimaryPlay failed\n"); + else + TRACE("starting playback\n"); + } + } + else + LeaveCriticalSection(&(device->mixlock)); + } else { + /* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */ + if (device->state == STATE_STARTING) { + if (DSOUND_PrimaryPlay(device) != DS_OK) + WARN("DSOUND_PrimaryPlay failed\n"); + else + device->state = STATE_PLAYING; + } + else if (device->state == STATE_STOPPING) { + if (DSOUND_PrimaryStop(device) != DS_OK) + WARN("DSOUND_PrimaryStop failed\n"); + else + device->state = STATE_STOPPED; + } + } +} + +void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + DirectSoundDevice * device = (DirectSoundDevice*)dwUser; + DWORD start_time = GetTickCount(); + DWORD end_time; + TRACE("(%d,%d,0x%lx,0x%lx,0x%lx)\n",timerID,msg,dwUser,dw1,dw2); + TRACE("entering at %ld\n", start_time); + + if (DSOUND_renderer[device->drvdesc.dnDevNode] != device) { + ERR("dsound died without killing us?\n"); + timeKillEvent(timerID); + timeEndPeriod(DS_TIME_RES); + return; + } + + RtlAcquireResourceShared(&(device->buffer_list_lock), TRUE); + + if (device->ref) + DSOUND_PerformMix(device); + + RtlReleaseResource(&(device->buffer_list_lock)); + + end_time = GetTickCount(); + TRACE("completed processing at %ld, duration = %ld\n", end_time, end_time - start_time); +} + +void CALLBACK DSOUND_callback(HWAVEOUT hwo, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2) +{ + DirectSoundDevice * device = (DirectSoundDevice*)dwUser; + TRACE("(%p,%x,%lx,%lx,%lx)\n",hwo,msg,dwUser,dw1,dw2); + TRACE("entering at %ld, msg=%08x(%s)\n", GetTickCount(), msg, + msg==MM_WOM_DONE ? "MM_WOM_DONE" : msg==MM_WOM_CLOSE ? "MM_WOM_CLOSE" : + msg==MM_WOM_OPEN ? "MM_WOM_OPEN" : "UNKNOWN"); + if (msg == MM_WOM_DONE) { + DWORD inq, mixq, fraglen, buflen, pwplay, playpos, mixpos; + if (device->pwqueue == (DWORD)-1) { + TRACE("completed due to reset\n"); + return; + } +/* it could be a bad idea to enter critical section here... if there's lock contention, + * the resulting scheduling delays might obstruct the winmm player thread */ +#ifdef SYNC_CALLBACK + EnterCriticalSection(&(device->mixlock)); +#endif + /* retrieve current values */ + fraglen = device->fraglen; + buflen = device->buflen; + pwplay = device->pwplay; + playpos = pwplay * fraglen; + mixpos = device->mixpos; + /* check remaining mixed data */ + inq = ((mixpos < playpos) ? buflen : 0) + mixpos - playpos; + mixq = inq / fraglen; + if ((inq - (mixq * fraglen)) > 0) mixq++; + /* complete the playing buffer */ + TRACE("done playing primary pos=%ld\n", playpos); + pwplay++; + if (pwplay >= DS_HEL_FRAGS) pwplay = 0; + /* write new values */ + device->pwplay = pwplay; + device->pwqueue--; + /* queue new buffer if we have data for it */ + if (inq>1) DSOUND_WaveQueue(device, inq-1); +#ifdef SYNC_CALLBACK + LeaveCriticalSection(&(device->mixlock)); +#endif + } + TRACE("completed\n"); +} diff --git a/reactos/lib/dsound/primary.c b/reactos/lib/dsound/primary.c index 46fca563e8f..af2f2855bf4 100644 --- a/reactos/lib/dsound/primary.c +++ b/reactos/lib/dsound/primary.c @@ -1,1105 +1,1072 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include /* Insomnia - pow() function */ - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winreg.h" -#include "winternl.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - -void DSOUND_RecalcPrimary(IDirectSoundImpl *This) -{ - DWORD sw; - TRACE("(%p)\n",This); - - sw = This->pwfx->nChannels * (This->pwfx->wBitsPerSample / 8); - if (This->hwbuf) { - DWORD fraglen; - /* let fragment size approximate the timer delay */ - fraglen = (This->pwfx->nSamplesPerSec * DS_TIME_DEL / 1000) * sw; - /* reduce fragment size until an integer number of them fits in the buffer */ - /* (FIXME: this may or may not be a good idea) */ - while (This->buflen % fraglen) fraglen -= sw; - This->fraglen = fraglen; - TRACE("fraglen=%ld\n", This->fraglen); - } - /* calculate the 10ms write lead */ - This->writelead = (This->pwfx->nSamplesPerSec / 100) * sw; -} - -static HRESULT DSOUND_PrimaryOpen(IDirectSoundImpl *This) -{ - HRESULT err = DS_OK; - TRACE("(%p)\n",This); - - /* are we using waveOut stuff? */ - if (!This->driver) { - LPBYTE newbuf; - DWORD buflen; - HRESULT merr = DS_OK; - /* Start in pause mode, to allow buffers to get filled */ - waveOutPause(This->hwo); - if (This->state == STATE_PLAYING) This->state = STATE_STARTING; - else if (This->state == STATE_STOPPING) This->state = STATE_STOPPED; - /* use fragments of 10ms (1/100s) each (which should get us within - * the documented write cursor lead of 10-15ms) */ - buflen = ((This->pwfx->nAvgBytesPerSec / 100) & ~3) * DS_HEL_FRAGS; - TRACE("desired buflen=%ld, old buffer=%p\n", buflen, This->buffer); - /* reallocate emulated primary buffer */ - - if (This->buffer) - newbuf = HeapReAlloc(GetProcessHeap(),0,This->buffer,buflen); - else - newbuf = HeapAlloc(GetProcessHeap(),0,buflen); - - if (newbuf == NULL) { - ERR("failed to allocate primary buffer\n"); - merr = DSERR_OUTOFMEMORY; - /* but the old buffer might still exist and must be re-prepared */ - } else { - This->buffer = newbuf; - This->buflen = buflen; - } - if (This->buffer) { - unsigned c; - - This->fraglen = This->buflen / DS_HEL_FRAGS; - - /* prepare fragment headers */ - for (c=0; cpwave[c]->lpData = This->buffer + c*This->fraglen; - This->pwave[c]->dwBufferLength = This->fraglen; - This->pwave[c]->dwUser = (DWORD)This; - This->pwave[c]->dwFlags = 0; - This->pwave[c]->dwLoops = 0; - err = mmErr(waveOutPrepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR))); - if (err != DS_OK) { - while (c--) - waveOutUnprepareHeader(This->hwo,This->pwave[c],sizeof(WAVEHDR)); - break; - } - } - - This->pwplay = 0; - This->pwwrite = 0; - This->pwqueue = 0; - This->playpos = 0; - This->mixpos = 0; - memset(This->buffer, (This->pwfx->wBitsPerSample == 16) ? 0 : 128, This->buflen); - TRACE("fraglen=%ld\n", This->fraglen); - DSOUND_WaveQueue(This, (DWORD)-1); - } - if ((err == DS_OK) && (merr != DS_OK)) - err = merr; - } else if (!This->hwbuf) { - err = IDsDriver_CreateSoundBuffer(This->driver,This->pwfx, - DSBCAPS_PRIMARYBUFFER,0, - &(This->buflen),&(This->buffer), - (LPVOID*)&(This->hwbuf)); - if (err != DS_OK) { - WARN("IDsDriver_CreateSoundBuffer failed\n"); - return err; - } - - if (dsound->state == STATE_PLAYING) dsound->state = STATE_STARTING; - else if (dsound->state == STATE_STOPPING) dsound->state = STATE_STOPPED; - } - - return err; -} - - -static void DSOUND_PrimaryClose(IDirectSoundImpl *This) -{ - TRACE("(%p)\n",This); - - /* are we using waveOut stuff? */ - if (!This->hwbuf) { - unsigned c; - - This->pwqueue = (DWORD)-1; /* resetting queues */ - waveOutReset(This->hwo); - for (c=0; chwo, This->pwave[c], sizeof(WAVEHDR)); - This->pwqueue = 0; - } else { - if (IDsDriverBuffer_Release(This->hwbuf) == 0) - This->hwbuf = 0; - } -} - -HRESULT DSOUND_PrimaryCreate(IDirectSoundImpl *This) -{ - HRESULT err = DS_OK; - TRACE("(%p)\n",This); - - This->buflen = This->pwfx->nAvgBytesPerSec; - - /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */ - - if (This->driver) { - err = IDsDriver_CreateSoundBuffer(This->driver,This->pwfx, - DSBCAPS_PRIMARYBUFFER,0, - &(This->buflen),&(This->buffer), - (LPVOID*)&(This->hwbuf)); - if (err != DS_OK) { - WARN("IDsDriver_CreateSoundBuffer failed\n"); - return err; - } - } - if (!This->hwbuf) { - /* Allocate memory for HEL buffer headers */ - unsigned c; - for (c=0; cpwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR)); - if (!This->pwave[c]) { - /* Argh, out of memory */ - while (c--) { - HeapFree(GetProcessHeap(),0,This->pwave[c]); - } - WARN("out of memory\n"); - return DSERR_OUTOFMEMORY; - } - } - } - - err = DSOUND_PrimaryOpen(This); - - if (err != DS_OK) { - WARN("DSOUND_PrimaryOpen failed\n"); - return err; - } - - /* calculate fragment size and write lead */ - DSOUND_RecalcPrimary(This); - This->state = STATE_STOPPED; - return DS_OK; -} - -HRESULT DSOUND_PrimaryDestroy(IDirectSoundImpl *This) -{ - TRACE("(%p)\n",This); - - DSOUND_PrimaryClose(This); - if (This->driver) { - if (This->hwbuf) { - if (IDsDriverBuffer_Release(This->hwbuf) == 0) - This->hwbuf = 0; - } - } else { - unsigned c; - for (c=0; cpwave[c]); - } - } - if (This->pwfx) { - HeapFree(GetProcessHeap(),0,This->pwfx); - This->pwfx=NULL; - } - return DS_OK; -} - -HRESULT DSOUND_PrimaryPlay(IDirectSoundImpl *This) -{ - HRESULT err = DS_OK; - TRACE("(%p)\n",This); - - if (This->hwbuf) { - err = IDsDriverBuffer_Play(This->hwbuf, 0, 0, DSBPLAY_LOOPING); - if (err != DS_OK) - WARN("IDsDriverBuffer_Play failed\n"); - } else { - err = mmErr(waveOutRestart(This->hwo)); - if (err != DS_OK) - WARN("waveOutRestart failed\n"); - } - - return err; -} - -HRESULT DSOUND_PrimaryStop(IDirectSoundImpl *This) -{ - HRESULT err = DS_OK; - TRACE("(%p)\n",This); - - if (This->hwbuf) { - err = IDsDriverBuffer_Stop(This->hwbuf); - if (err == DSERR_BUFFERLOST) { - DWORD flags = CALLBACK_FUNCTION; - if (ds_hw_accel != DS_HW_ACCEL_EMULATION) - flags |= WAVE_DIRECTSOUND; - /* Wine-only: the driver wants us to reopen the device */ - /* FIXME: check for errors */ - IDsDriverBuffer_Release(This->hwbuf); - waveOutClose(This->hwo); - This->hwo = 0; - err = mmErr(waveOutOpen(&(This->hwo), This->drvdesc.dnDevNode, - This->pwfx, (DWORD)DSOUND_callback, (DWORD)This, - flags)); - if (err == DS_OK) { - err = IDsDriver_CreateSoundBuffer(This->driver,This->pwfx, - DSBCAPS_PRIMARYBUFFER,0, - &(This->buflen),&(This->buffer), - (LPVOID)&(This->hwbuf)); - if (err != DS_OK) - WARN("IDsDriver_CreateSoundBuffer failed\n"); - } else { - WARN("waveOutOpen failed\n"); - } - } else if (err != DS_OK) { - WARN("IDsDriverBuffer_Stop failed\n"); - } - } else { - err = mmErr(waveOutPause(This->hwo)); - if (err != DS_OK) - WARN("waveOutPause failed\n"); - } - return err; -} - -HRESULT DSOUND_PrimaryGetPosition(IDirectSoundImpl *This, LPDWORD playpos, LPDWORD writepos) -{ - TRACE("(%p,%p,%p)\n",This,playpos,writepos); - - if (This->hwbuf) { - HRESULT err=IDsDriverBuffer_GetPosition(This->hwbuf,playpos,writepos); - if (err) { - WARN("IDsDriverBuffer_GetPosition failed\n"); - return err; - } - } else { - if (playpos) { - MMTIME mtime; - mtime.wType = TIME_BYTES; - waveOutGetPosition(This->hwo, &mtime, sizeof(mtime)); - mtime.u.cb = mtime.u.cb % This->buflen; - *playpos = mtime.u.cb; - } - if (writepos) { - /* the writepos should only be used by apps with WRITEPRIMARY priority, - * in which case our software mixer is disabled anyway */ - *writepos = (This->pwplay + ds_hel_margin) * This->fraglen; - while (*writepos >= This->buflen) - *writepos -= This->buflen; - } - } - TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); - return DS_OK; -} - -/******************************************************************************* - * PrimaryBuffer - */ -/* This sets this format for the Primary Buffer Only */ -/* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */ -static HRESULT WINAPI PrimaryBufferImpl_SetFormat( - LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - HRESULT err = DS_OK; - int i, alloc_size, cp_size; - DWORD nSamplesPerSec; - TRACE("(%p,%p)\n",This,wfex); - - if (This->dsound->priolevel == DSSCL_NORMAL) { - WARN("failed priority check!\n"); - return DSERR_PRIOLEVELNEEDED; - } - - /* Let's be pedantic! */ - if (wfex == NULL) { - WARN("invalid parameter: wfex==NULL!\n"); - return DSERR_INVALIDPARAM; - } - TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," - "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", - wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, - wfex->nAvgBytesPerSec, wfex->nBlockAlign, - wfex->wBitsPerSample, wfex->cbSize); - - /* **** */ - RtlAcquireResourceExclusive(&(dsound->buffer_list_lock), TRUE); - - if (wfex->wFormatTag == WAVE_FORMAT_PCM) { - alloc_size = sizeof(WAVEFORMATEX); - cp_size = sizeof(PCMWAVEFORMAT); - } else - alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize; - - dsound->pwfx = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dsound->pwfx,alloc_size); - - nSamplesPerSec = dsound->pwfx->nSamplesPerSec; - - memcpy(dsound->pwfx, wfex, cp_size); - - if (dsound->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) { - DWORD flags = CALLBACK_FUNCTION; - if (ds_hw_accel != DS_HW_ACCEL_EMULATION) - flags |= WAVE_DIRECTSOUND; - /* FIXME: check for errors */ - DSOUND_PrimaryClose(dsound); - waveOutClose(dsound->hwo); - dsound->hwo = 0; - err = mmErr(waveOutOpen(&(dsound->hwo), dsound->drvdesc.dnDevNode, - dsound->pwfx, (DWORD)DSOUND_callback, (DWORD)dsound, - flags)); - if (err == DS_OK) { - err = DSOUND_PrimaryOpen(dsound); - if (err != DS_OK) { - WARN("DSOUND_PrimaryOpen failed\n"); - RtlReleaseResource(&(dsound->buffer_list_lock)); - return err; - } - } else { - WARN("waveOutOpen failed\n"); - RtlReleaseResource(&(dsound->buffer_list_lock)); - return err; - } - } else if (dsound->hwbuf) { - err = IDsDriverBuffer_SetFormat(dsound->hwbuf, dsound->pwfx); - if (err == DSERR_BUFFERLOST) { - /* Wine-only: the driver wants us to recreate the HW buffer */ - IDsDriverBuffer_Release(dsound->hwbuf); - err = IDsDriver_CreateSoundBuffer(dsound->driver,dsound->pwfx, - DSBCAPS_PRIMARYBUFFER,0, - &(dsound->buflen),&(dsound->buffer), - (LPVOID)&(dsound->hwbuf)); - if (err != DS_OK) { - WARN("IDsDriver_CreateSoundBuffer failed\n"); - RtlReleaseResource(&(dsound->buffer_list_lock)); - return err; - } - if (dsound->state == STATE_PLAYING) dsound->state = STATE_STARTING; - else if (dsound->state == STATE_STOPPING) dsound->state = STATE_STOPPED; - } else { - WARN("IDsDriverBuffer_SetFormat failed\n"); - RtlReleaseResource(&(dsound->buffer_list_lock)); - return err; - } - /* FIXME: should we set err back to DS_OK in all cases ? */ - } - DSOUND_RecalcPrimary(dsound); - - if (nSamplesPerSec != dsound->pwfx->nSamplesPerSec) { - IDirectSoundBufferImpl** dsb = dsound->buffers; - for (i = 0; i < dsound->nrofbuffers; i++, dsb++) { - /* **** */ - EnterCriticalSection(&((*dsb)->lock)); - - (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) / - wfex->nSamplesPerSec; - - LeaveCriticalSection(&((*dsb)->lock)); - /* **** */ - } - } - - RtlReleaseResource(&(dsound->buffer_list_lock)); - /* **** */ - - return err; -} - -static HRESULT WINAPI PrimaryBufferImpl_SetVolume( - LPDIRECTSOUNDBUFFER8 iface,LONG vol -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - DWORD ampfactors; - DSVOLUMEPAN volpan; - HRESULT hres = DS_OK; - - TRACE("(%p,%ld)\n",This,vol); - - if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { - WARN("invalid parameter: vol = %ld\n", vol); - return DSERR_INVALIDPARAM; - } - - /* **** */ - EnterCriticalSection(&(dsound->mixlock)); - - waveOutGetVolume(dsound->hwo, &factors); - volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; - volpan.dwTotalRightAmpFactor=ampfactors >> 16; - DSOUND_AmpFactorToVolPan(&volpan); - if (vol != volpan.lVolume) { - volpan.lVolume=vol; - DSOUND_RecalcVolPan(&volpan); - if (dsound->hwbuf) { - hres = IDsDriverBuffer_SetVolumePan(dsound->hwbuf, &volpan); - if (hres != DS_OK) - WARN("IDsDriverBuffer_SetVolumePan failed\n"); - } else { - ampfactors = (volpan.dwTotalLeftAmpFactor & 0xffff) | (volpan.dwTotalRightAmpFactor << 16); - waveOutSetVolume(dsound->hwo, ampfactors); - } - } - - LeaveCriticalSection(&(dsound->mixlock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI PrimaryBufferImpl_GetVolume( - LPDIRECTSOUNDBUFFER8 iface,LPLONG vol -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - DWORD ampfactors; - DSVOLUMEPAN volpan; - TRACE("(%p,%p)\n",This,vol); - - if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - if (vol == NULL) { - WARN("invalid parameter: vol = NULL\n"); - return DSERR_INVALIDPARAM; - } - - waveOutGetVolume(dsound->hwo, &factors); - volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; - volpan.dwTotalRightAmpFactor=ampfactors >> 16; - DSOUND_AmpFactorToVolPan(&volpan); - *vol = volpan.lVolume; - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_SetFrequency( - LPDIRECTSOUNDBUFFER8 iface,DWORD freq -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - - TRACE("(%p,%ld)\n",This,freq); - - /* You cannot set the frequency of the primary buffer */ - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; -} - -static HRESULT WINAPI PrimaryBufferImpl_Play( - LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - - TRACE("(%p,%08lx,%08lx,%08lx)\n", - This,reserved1,reserved2,flags - ); - - if (!(flags & DSBPLAY_LOOPING)) { - WARN("invalid parameter: flags = %08lx\n", flags); - return DSERR_INVALIDPARAM; - } - - /* **** */ - EnterCriticalSection(&(dsound->mixlock)); - - if (dsound->state == STATE_STOPPED) - dsound->state = STATE_STARTING; - else if (dsound->state == STATE_STOPPING) - dsound->state = STATE_PLAYING; - - LeaveCriticalSection(&(dsound->mixlock)); - /* **** */ - - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) -{ - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - - TRACE("(%p)\n",This); - - /* **** */ - EnterCriticalSection(&(dsound->mixlock)); - - if (dsound->state == STATE_PLAYING) - dsound->state = STATE_STOPPING; - else if (dsound->state == STATE_STARTING) - dsound->state = STATE_STOPPED; - - LeaveCriticalSection(&(dsound->mixlock)); - /* **** */ - - return DS_OK; -} - -static ULONG WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - DWORD ref; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - ref = InterlockedDecrement(&(This->ref)); - - if (ref == 0) { - This->dsound->primary = NULL; - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - - return ref; -} - -static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos -) { - HRESULT hres; - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - - TRACE("(%p,%p,%p)\n",This,playpos,writepos); - hres = DSOUND_PrimaryGetPosition(dsound, playpos, writepos); - if (hres != DS_OK) { - WARN("DSOUND_PrimaryGetPosition failed\n"); - return hres; - } - if (writepos) { - if (dsound->state != STATE_STOPPED) - /* apply the documented 10ms lead to writepos */ - *writepos += dsound->writelead; - while (*writepos >= dsound->buflen) *writepos -= dsound->buflen; - } - TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, This, GetTickCount()); - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_GetStatus( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD status -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - TRACE("(%p,%p), thread is %04lx\n",This,status,GetCurrentThreadId()); - - if (status == NULL) { - WARN("invalid parameter: status == NULL\n"); - return DSERR_INVALIDPARAM; - } - - *status = 0; - if ((This->dsound->state == STATE_STARTING) || - (This->dsound->state == STATE_PLAYING)) - *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING; - - TRACE("status=%lx\n", *status); - return DS_OK; -} - - -static HRESULT WINAPI PrimaryBufferImpl_GetFormat( - LPDIRECTSOUNDBUFFER8 iface, - LPWAVEFORMATEX lpwf, - DWORD wfsize, - LPDWORD wfwritten) -{ - DWORD size; - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - TRACE("(%p,%p,%ld,%p)\n",This,lpwf,wfsize,wfwritten); - - size = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; - - if (lpwf) { /* NULL is valid */ - if (wfsize >= size) { - memcpy(lpwf,This->dsound->pwfx,size); - if (wfwritten) - *wfwritten = size; - } else { - WARN("invalid parameter: wfsize to small\n"); - if (wfwritten) - *wfwritten = 0; - return DSERR_INVALIDPARAM; - } - } else { - if (wfwritten) - *wfwritten = sizeof(WAVEFORMATEX) + This->dsound->pwfx->cbSize; - else { - WARN("invalid parameter: wfwritten == NULL\n"); - return DSERR_INVALIDPARAM; - } - } - - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_Lock( - LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - - TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", - This, - writecursor, - writebytes, - lplpaudioptr1, - audiobytes1, - lplpaudioptr2, - audiobytes2, - flags, - GetTickCount() - ); - - if (dsound->priolevel != DSSCL_WRITEPRIMARY) { - WARN("failed priority check!\n"); - return DSERR_PRIOLEVELNEEDED; - } - - if (flags & DSBLOCK_FROMWRITECURSOR) { - DWORD writepos; - HRESULT hres; - /* GetCurrentPosition does too much magic to duplicate here */ - hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writepos); - if (hres != DS_OK) { - WARN("IDirectSoundBuffer_GetCurrentPosition failed\n"); - return hres; - } - writecursor += writepos; - } - while (writecursor >= dsound->buflen) - writecursor -= dsound->buflen; - if (flags & DSBLOCK_ENTIREBUFFER) - writebytes = dsound->buflen; - if (writebytes > dsound->buflen) - writebytes = dsound->buflen; - - if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) { - HRESULT hres; - hres = IDsDriverBuffer_Lock(dsound->hwbuf, - lplpaudioptr1, audiobytes1, - lplpaudioptr2, audiobytes2, - writecursor, writebytes, - 0); - if (hres != DS_OK) { - WARN("IDsDriverBuffer_Lock failed\n"); - return hres; - } - } else { - if (writecursor+writebytes <= dsound->buflen) { - *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor; - *audiobytes1 = writebytes; - if (lplpaudioptr2) - *(LPBYTE*)lplpaudioptr2 = NULL; - if (audiobytes2) - *audiobytes2 = 0; - TRACE("->%ld.0\n",writebytes); - } else { - *(LPBYTE*)lplpaudioptr1 = dsound->buffer+writecursor; - *audiobytes1 = dsound->buflen-writecursor; - if (lplpaudioptr2) - *(LPBYTE*)lplpaudioptr2 = dsound->buffer; - if (audiobytes2) - *audiobytes2 = writebytes-(dsound->buflen-writecursor); - TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); - } - } - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition( - LPDIRECTSOUNDBUFFER8 iface,DWORD newpos -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - TRACE("(%p,%ld)\n",This,newpos); - - /* You cannot set the position of the primary buffer */ - WARN("invalid call\n"); - return DSERR_INVALIDCALL; -} - -static HRESULT WINAPI PrimaryBufferImpl_SetPan( - LPDIRECTSOUNDBUFFER8 iface,LONG pan -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - DWORD ampfactors; - DSVOLUMEPAN volpan; - HRESULT hres = DS_OK; - - TRACE("(%p,%ld)\n",This,pan); - - if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { - WARN("invalid parameter: pan = %ld\n", pan); - return DSERR_INVALIDPARAM; - } - - /* **** */ - EnterCriticalSection(&(dsound->mixlock)); - - waveOutGetVolume(dsound->hwo, &factors); - volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; - volpan.dwTotalRightAmpFactor=ampfactors >> 16; - DSOUND_AmpFactorToVolPan(&volpan); - if (pan != volpan.lPan) { - volpan.lPan=pan; - DSOUND_RecalcVolPan(&volpan); - if (dsound->hwbuf) { - hres = IDsDriverBuffer_SetVolumePan(dsound->hwbuf, &volpan); - if (hres != DS_OK) - WARN("IDsDriverBuffer_SetVolumePan failed\n"); - } else { - ampfactors = (volpan.dwTotalLeftAmpFactor & 0xffff) | (volpan.dwTotalRightAmpFactor << 16); - waveOutSetVolume(dsound->hwo, ampfactors); - } - } - - LeaveCriticalSection(&(dsound->mixlock)); - /* **** */ - - return hres; -} - -static HRESULT WINAPI PrimaryBufferImpl_GetPan( - LPDIRECTSOUNDBUFFER8 iface,LPLONG pan -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - DWORD ampfactors; - DSVOLUMEPAN volpan; - TRACE("(%p,%p)\n",This,pan); - - if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - if (pan == NULL) { - WARN("invalid parameter: pan == NULL\n"); - return DSERR_INVALIDPARAM; - } - - waveOutGetVolume(dsound->hwo, &factors); - volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; - volpan.dwTotalRightAmpFactor=ampfactors >> 16; - DSOUND_AmpFactorToVolPan(&volpan); - *pan = volpan.lPan; - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_Unlock( - LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - IDirectSoundImpl* dsound = This->dsound; - - TRACE("(%p,%p,%ld,%p,%ld)\n", This,p1,x1,p2,x2); - - if (dsound->priolevel != DSSCL_WRITEPRIMARY) { - WARN("failed priority check!\n"); - return DSERR_PRIOLEVELNEEDED; - } - - if (!(dsound->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && dsound->hwbuf) { - HRESULT hres; - - hres = IDsDriverBuffer_Unlock(dsound->hwbuf, p1, x1, p2, x2); - if (hres != DS_OK) { - WARN("IDsDriverBuffer_Unlock failed\n"); - return hres; - } - } - - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_Restore( - LPDIRECTSOUNDBUFFER8 iface -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - FIXME("(%p):stub\n",This); - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_GetFrequency( - LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - TRACE("(%p,%p)\n",This,freq); - - if (freq == NULL) { - WARN("invalid parameter: freq == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (!(This->dsound->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) { - WARN("control unavailable\n"); - return DSERR_CONTROLUNAVAIL; - } - - *freq = This->dsound->pwfx->nSamplesPerSec; - TRACE("-> %ld\n", *freq); - - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_SetFX( - LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; - DWORD u; - - FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); - - if (pdwResultCodes) - for (u=0; u(%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 = %ld: < %d\n", caps->dwSize, sizeof(*caps)); - return DSERR_INVALIDPARAM; - } - - caps->dwFlags = This->dsound->dsbd.dwFlags; - if (This->dsound->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; - else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; - - caps->dwBufferBytes = This->dsound->buflen; - - /* This value represents the speed of the "unlock" command. - As unlock is quite fast (it does not do anything), I put - 4096 ko/s = 4 Mo / s */ - /* FIXME: hwbuf speed */ - caps->dwUnlockTransferRate = 4096; - caps->dwPlayCpuOverhead = 0; - - return DS_OK; -} - -static HRESULT WINAPI PrimaryBufferImpl_QueryInterface( - LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj -) { - PrimaryBufferImpl *This = (PrimaryBufferImpl *)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) ) { - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This); - *ppobj = This; - return S_OK; - } - - /* DirectSoundBuffer and DirectSoundBuffer8 are different and */ - /* a primary buffer can't have a DirectSoundBuffer8 interface */ - if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) { - WARN("app requested DirectSoundBuffer8 on primary buffer\n"); - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { - ERR("app requested IDirectSoundNotify on primary buffer\n"); - /* FIXME: should we support this? */ - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { - ERR("app requested IDirectSound3DBuffer on primary buffer\n"); - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) { - if (!This->dsound->listener) - IDirectSound3DListenerImpl_Create(This, &This->dsound->listener); - if (This->dsound->listener) { - *ppobj = This->dsound->listener; - IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj); - return S_OK; - } - - WARN("IID_IDirectSound3DListener failed\n"); - return E_NOINTERFACE; - } - - if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { - FIXME("app requested IKsPropertySet on primary buffer\n"); - return E_NOINTERFACE; - } - - FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); - return E_NOINTERFACE; -} - -static IDirectSoundBuffer8Vtbl dspbvt = -{ - PrimaryBufferImpl_QueryInterface, - PrimaryBufferImpl_AddRef, - PrimaryBufferImpl_Release, - PrimaryBufferImpl_GetCaps, - PrimaryBufferImpl_GetCurrentPosition, - PrimaryBufferImpl_GetFormat, - PrimaryBufferImpl_GetVolume, - PrimaryBufferImpl_GetPan, - PrimaryBufferImpl_GetFrequency, - PrimaryBufferImpl_GetStatus, - PrimaryBufferImpl_Initialize, - PrimaryBufferImpl_Lock, - PrimaryBufferImpl_Play, - PrimaryBufferImpl_SetCurrentPosition, - PrimaryBufferImpl_SetFormat, - PrimaryBufferImpl_SetVolume, - PrimaryBufferImpl_SetPan, - PrimaryBufferImpl_SetFrequency, - PrimaryBufferImpl_Stop, - PrimaryBufferImpl_Unlock, - PrimaryBufferImpl_Restore, - PrimaryBufferImpl_SetFX, - PrimaryBufferImpl_AcquireResources, - PrimaryBufferImpl_GetObjectInPath -}; - -HRESULT WINAPI PrimaryBufferImpl_Create( - IDirectSoundImpl *ds, - PrimaryBufferImpl **pdsb, - LPCDSBUFFERDESC dsbd) -{ - PrimaryBufferImpl *dsb; - - TRACE("%p,%p,%p)\n",ds,pdsb,dsbd); - - if (dsbd->lpwfxFormat) { - WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n"); - *pdsb = NULL; - return DSERR_INVALIDPARAM; - } - - dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); - - if (dsb == NULL) { - WARN("out of memory\n"); - *pdsb = NULL; - return DSERR_OUTOFMEMORY; - } - - dsb->ref = 0; - dsb->dsound = ds; - dsb->lpVtbl = &dspbvt; - - memcpy(&ds->dsbd, dsbd, sizeof(*dsbd)); - - TRACE("Created primary buffer at %p\n", dsb); - TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," - "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", - ds->pwfx->wFormatTag, ds->pwfx->nChannels, ds->pwfx->nSamplesPerSec, - ds->pwfx->nAvgBytesPerSec, ds->pwfx->nBlockAlign, - ds->pwfx->wBitsPerSample, ds->pwfx->cbSize); - - *pdsb = dsb; - return S_OK; -} +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "winternl.h" +#include "mmddk.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + +void DSOUND_RecalcPrimary(DirectSoundDevice *device) +{ + DWORD nBlockAlign; + TRACE("(%p)\n", device); + + nBlockAlign = device->pwfx->nBlockAlign; + if (device->hwbuf) { + DWORD fraglen; + /* let fragment size approximate the timer delay */ + fraglen = (device->pwfx->nSamplesPerSec * DS_TIME_DEL / 1000) * nBlockAlign; + /* reduce fragment size until an integer number of them fits in the buffer */ + /* (FIXME: this may or may not be a good idea) */ + while (device->buflen % fraglen) fraglen -= nBlockAlign; + device->fraglen = fraglen; + TRACE("fraglen=%ld\n", device->fraglen); + } + /* calculate the 10ms write lead */ + device->writelead = (device->pwfx->nSamplesPerSec / 100) * nBlockAlign; +} + +static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) +{ + HRESULT err = DS_OK; + TRACE("(%p)\n", device); + + /* are we using waveOut stuff? */ + if (!device->driver) { + LPBYTE newbuf; + DWORD buflen; + HRESULT merr = DS_OK; + /* Start in pause mode, to allow buffers to get filled */ + waveOutPause(device->hwo); + if (device->state == STATE_PLAYING) device->state = STATE_STARTING; + else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; + /* use fragments of 10ms (1/100s) each (which should get us within + * the documented write cursor lead of 10-15ms) */ + buflen = ((device->pwfx->nSamplesPerSec / 100) * device->pwfx->nBlockAlign) * DS_HEL_FRAGS; + TRACE("desired buflen=%ld, old buffer=%p\n", buflen, device->buffer); + /* reallocate emulated primary buffer */ + + if (device->buffer) + newbuf = HeapReAlloc(GetProcessHeap(),0,device->buffer,buflen); + else + newbuf = HeapAlloc(GetProcessHeap(),0,buflen); + + if (newbuf == NULL) { + ERR("failed to allocate primary buffer\n"); + merr = DSERR_OUTOFMEMORY; + /* but the old buffer might still exist and must be re-prepared */ + } else { + device->buffer = newbuf; + device->buflen = buflen; + } + if (device->buffer) { + unsigned c; + + device->fraglen = device->buflen / DS_HEL_FRAGS; + + /* prepare fragment headers */ + for (c=0; cpwave[c]->lpData = (char*)device->buffer + c*device->fraglen; + device->pwave[c]->dwBufferLength = device->fraglen; + device->pwave[c]->dwUser = (DWORD)device; + device->pwave[c]->dwFlags = 0; + device->pwave[c]->dwLoops = 0; + err = mmErr(waveOutPrepareHeader(device->hwo,device->pwave[c],sizeof(WAVEHDR))); + if (err != DS_OK) { + while (c--) + waveOutUnprepareHeader(device->hwo,device->pwave[c],sizeof(WAVEHDR)); + break; + } + } + + device->pwplay = 0; + device->pwwrite = 0; + device->pwqueue = 0; + device->playpos = 0; + device->mixpos = 0; + FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); + TRACE("fraglen=%ld\n", device->fraglen); + DSOUND_WaveQueue(device, (DWORD)-1); + } + if ((err == DS_OK) && (merr != DS_OK)) + err = merr; + } else if (!device->hwbuf) { + err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx, + DSBCAPS_PRIMARYBUFFER,0, + &(device->buflen),&(device->buffer), + (LPVOID*)&(device->hwbuf)); + if (err != DS_OK) { + WARN("IDsDriver_CreateSoundBuffer failed\n"); + return err; + } + + if (device->state == STATE_PLAYING) device->state = STATE_STARTING; + else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; + device->playpos = 0; + device->mixpos = 0; + FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0); + } + + return err; +} + + +static void DSOUND_PrimaryClose(DirectSoundDevice *device) +{ + TRACE("(%p)\n", device); + + /* are we using waveOut stuff? */ + if (!device->hwbuf) { + unsigned c; + + device->pwqueue = (DWORD)-1; /* resetting queues */ + waveOutReset(device->hwo); + for (c=0; chwo, device->pwave[c], sizeof(WAVEHDR)); + device->pwqueue = 0; + } else { + if (IDsDriverBuffer_Release(device->hwbuf) == 0) + device->hwbuf = 0; + } +} + +HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device) +{ + HRESULT err = DS_OK; + TRACE("(%p)\n", device); + + device->buflen = device->pwfx->nAvgBytesPerSec; + + /* FIXME: verify that hardware capabilities (DSCAPS_PRIMARY flags) match */ + + if (device->driver) { + err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx, + DSBCAPS_PRIMARYBUFFER,0, + &(device->buflen),&(device->buffer), + (LPVOID*)&(device->hwbuf)); + if (err != DS_OK) { + WARN("IDsDriver_CreateSoundBuffer failed\n"); + return err; + } + } + if (!device->hwbuf) { + /* Allocate memory for HEL buffer headers */ + unsigned c; + for (c=0; cpwave[c] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(WAVEHDR)); + if (!device->pwave[c]) { + /* Argh, out of memory */ + while (c--) { + HeapFree(GetProcessHeap(),0,device->pwave[c]); + } + WARN("out of memory\n"); + return DSERR_OUTOFMEMORY; + } + } + } + + err = DSOUND_PrimaryOpen(device); + + if (err != DS_OK) { + WARN("DSOUND_PrimaryOpen failed\n"); + return err; + } + + /* calculate fragment size and write lead */ + DSOUND_RecalcPrimary(device); + device->state = STATE_STOPPED; + return DS_OK; +} + +HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) +{ + TRACE("(%p)\n", device); + + DSOUND_PrimaryClose(device); + if (device->driver) { + if (device->hwbuf) { + if (IDsDriverBuffer_Release(device->hwbuf) == 0) + device->hwbuf = 0; + } + } else { + unsigned c; + for (c=0; cpwave[c]); + } + } + HeapFree(GetProcessHeap(),0,device->pwfx); + device->pwfx=NULL; + return DS_OK; +} + +HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) +{ + HRESULT err = DS_OK; + TRACE("(%p)\n", device); + + if (device->hwbuf) { + err = IDsDriverBuffer_Play(device->hwbuf, 0, 0, DSBPLAY_LOOPING); + if (err != DS_OK) + WARN("IDsDriverBuffer_Play failed\n"); + } else { + err = mmErr(waveOutRestart(device->hwo)); + if (err != DS_OK) + WARN("waveOutRestart failed\n"); + } + + return err; +} + +HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) +{ + HRESULT err = DS_OK; + TRACE("(%p)\n", device); + + if (device->hwbuf) { + err = IDsDriverBuffer_Stop(device->hwbuf); + if (err == DSERR_BUFFERLOST) { + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; + /* Wine-only: the driver wants us to reopen the device */ + /* FIXME: check for errors */ + IDsDriverBuffer_Release(device->hwbuf); + waveOutClose(device->hwo); + device->hwo = 0; + err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, + device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device, + flags)); + if (err == DS_OK) { + err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx, + DSBCAPS_PRIMARYBUFFER,0, + &(device->buflen),&(device->buffer), + (LPVOID)&(device->hwbuf)); + if (err != DS_OK) + WARN("IDsDriver_CreateSoundBuffer failed\n"); + } else { + WARN("waveOutOpen failed\n"); + } + } else if (err != DS_OK) { + WARN("IDsDriverBuffer_Stop failed\n"); + } + } else { + err = mmErr(waveOutPause(device->hwo)); + if (err != DS_OK) + WARN("waveOutPause failed\n"); + } + return err; +} + +HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos) +{ + TRACE("(%p,%p,%p)\n", device, playpos, writepos); + + if (device->hwbuf) { + HRESULT err=IDsDriverBuffer_GetPosition(device->hwbuf,playpos,writepos); + if (err) { + WARN("IDsDriverBuffer_GetPosition failed\n"); + return err; + } + } else { + if (playpos) { + MMTIME mtime; + mtime.wType = TIME_BYTES; + waveOutGetPosition(device->hwo, &mtime, sizeof(mtime)); + mtime.u.cb = mtime.u.cb % device->buflen; + *playpos = mtime.u.cb; + } + if (writepos) { + /* the writepos should only be used by apps with WRITEPRIMARY priority, + * in which case our software mixer is disabled anyway */ + *writepos = (device->pwplay + ds_hel_margin) * device->fraglen; + while (*writepos >= device->buflen) + *writepos -= device->buflen; + } + } + TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount()); + return DS_OK; +} + +/******************************************************************************* + * PrimaryBuffer + */ +/* This sets this format for the Primary Buffer Only */ +/* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */ +static HRESULT WINAPI PrimaryBufferImpl_SetFormat( + LPDIRECTSOUNDBUFFER8 iface,LPCWAVEFORMATEX wfex +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + HRESULT err = DS_OK; + int i, alloc_size, cp_size; + DWORD nSamplesPerSec; + TRACE("(%p,%p)\n", iface, wfex); + + if (device->priolevel == DSSCL_NORMAL) { + WARN("failed priority check!\n"); + return DSERR_PRIOLEVELNEEDED; + } + + /* Let's be pedantic! */ + if (wfex == NULL) { + WARN("invalid parameter: wfex==NULL!\n"); + return DSERR_INVALIDPARAM; + } + TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," + "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", + wfex->wFormatTag, wfex->nChannels, wfex->nSamplesPerSec, + wfex->nAvgBytesPerSec, wfex->nBlockAlign, + wfex->wBitsPerSample, wfex->cbSize); + + /* **** */ + RtlAcquireResourceExclusive(&(device->buffer_list_lock), TRUE); + EnterCriticalSection(&(device->mixlock)); + + if (wfex->wFormatTag == WAVE_FORMAT_PCM) { + alloc_size = sizeof(WAVEFORMATEX); + cp_size = sizeof(PCMWAVEFORMAT); + } else + alloc_size = cp_size = sizeof(WAVEFORMATEX) + wfex->cbSize; + + device->pwfx = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,device->pwfx,alloc_size); + + nSamplesPerSec = device->pwfx->nSamplesPerSec; + + CopyMemory(device->pwfx, wfex, cp_size); + + if (device->drvdesc.dwFlags & DSDDESC_DOMMSYSTEMSETFORMAT) { + DWORD flags = CALLBACK_FUNCTION; + if (ds_hw_accel != DS_HW_ACCEL_EMULATION) + flags |= WAVE_DIRECTSOUND; + /* FIXME: check for errors */ + DSOUND_PrimaryClose(device); + waveOutClose(device->hwo); + device->hwo = 0; + err = mmErr(waveOutOpen(&(device->hwo), device->drvdesc.dnDevNode, + device->pwfx, (DWORD_PTR)DSOUND_callback, (DWORD)device, + flags)); + if (err == DS_OK) { + err = DSOUND_PrimaryOpen(device); + if (err != DS_OK) { + WARN("DSOUND_PrimaryOpen failed\n"); + goto done; + } + } else { + WARN("waveOutOpen failed\n"); + goto done; + } + } else if (device->hwbuf) { + err = IDsDriverBuffer_SetFormat(device->hwbuf, device->pwfx); + if (err == DSERR_BUFFERLOST) { + /* Wine-only: the driver wants us to recreate the HW buffer */ + IDsDriverBuffer_Release(device->hwbuf); + err = IDsDriver_CreateSoundBuffer(device->driver,device->pwfx, + DSBCAPS_PRIMARYBUFFER,0, + &(device->buflen),&(device->buffer), + (LPVOID)&(device->hwbuf)); + if (err != DS_OK) { + WARN("IDsDriver_CreateSoundBuffer failed\n"); + goto done; + } + if (device->state == STATE_PLAYING) device->state = STATE_STARTING; + else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED; + } else { + WARN("IDsDriverBuffer_SetFormat failed\n"); + goto done; + } + /* FIXME: should we set err back to DS_OK in all cases ? */ + } + DSOUND_RecalcPrimary(device); + + if (nSamplesPerSec != device->pwfx->nSamplesPerSec) { + IDirectSoundBufferImpl** dsb = device->buffers; + for (i = 0; i < device->nrofbuffers; i++, dsb++) { + /* **** */ + EnterCriticalSection(&((*dsb)->lock)); + + (*dsb)->freqAdjust = ((*dsb)->freq << DSOUND_FREQSHIFT) / + wfex->nSamplesPerSec; + + LeaveCriticalSection(&((*dsb)->lock)); + /* **** */ + } + } + +done: + LeaveCriticalSection(&(device->mixlock)); + RtlReleaseResource(&(device->buffer_list_lock)); + /* **** */ + + return err; +} + +static HRESULT WINAPI PrimaryBufferImpl_SetVolume( + LPDIRECTSOUNDBUFFER8 iface,LONG vol +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + DWORD ampfactors; + DSVOLUMEPAN volpan; + HRESULT hres = DS_OK; + TRACE("(%p,%ld)\n", iface, vol); + + if (!(device->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + if ((vol > DSBVOLUME_MAX) || (vol < DSBVOLUME_MIN)) { + WARN("invalid parameter: vol = %ld\n", vol); + return DSERR_INVALIDPARAM; + } + + /* **** */ + EnterCriticalSection(&(device->mixlock)); + + waveOutGetVolume(device->hwo, &factors); + volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; + volpan.dwTotalRightAmpFactor=ampfactors >> 16; + DSOUND_AmpFactorToVolPan(&volpan); + if (vol != volpan.lVolume) { + volpan.lVolume=vol; + DSOUND_RecalcVolPan(&volpan); + if (device->hwbuf) { + hres = IDsDriverBuffer_SetVolumePan(device->hwbuf, &volpan); + if (hres != DS_OK) + WARN("IDsDriverBuffer_SetVolumePan failed\n"); + } else { + ampfactors = (volpan.dwTotalLeftAmpFactor & 0xffff) | (volpan.dwTotalRightAmpFactor << 16); + waveOutSetVolume(device->hwo, ampfactors); + } + } + + LeaveCriticalSection(&(device->mixlock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI PrimaryBufferImpl_GetVolume( + LPDIRECTSOUNDBUFFER8 iface,LPLONG vol +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + DWORD ampfactors; + DSVOLUMEPAN volpan; + TRACE("(%p,%p)\n", iface, vol); + + if (!(device->dsbd.dwFlags & DSBCAPS_CTRLVOLUME)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + if (vol == NULL) { + WARN("invalid parameter: vol = NULL\n"); + return DSERR_INVALIDPARAM; + } + + waveOutGetVolume(device->hwo, &factors); + volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; + volpan.dwTotalRightAmpFactor=ampfactors >> 16; + DSOUND_AmpFactorToVolPan(&volpan); + *vol = volpan.lVolume; + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_SetFrequency( + LPDIRECTSOUNDBUFFER8 iface,DWORD freq +) { + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,freq); + + /* You cannot set the frequency of the primary buffer */ + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; +} + +static HRESULT WINAPI PrimaryBufferImpl_Play( + LPDIRECTSOUNDBUFFER8 iface,DWORD reserved1,DWORD reserved2,DWORD flags +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%08lx,%08lx,%08lx)\n", iface, reserved1, reserved2, flags); + + if (!(flags & DSBPLAY_LOOPING)) { + WARN("invalid parameter: flags = %08lx\n", flags); + return DSERR_INVALIDPARAM; + } + + /* **** */ + EnterCriticalSection(&(device->mixlock)); + + if (device->state == STATE_STOPPED) + device->state = STATE_STARTING; + else if (device->state == STATE_STOPPING) + device->state = STATE_PLAYING; + + LeaveCriticalSection(&(device->mixlock)); + /* **** */ + + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_Stop(LPDIRECTSOUNDBUFFER8 iface) +{ + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p)\n", iface); + + /* **** */ + EnterCriticalSection(&(device->mixlock)); + + if (device->state == STATE_PLAYING) + device->state = STATE_STOPPING; + else if (device->state == STATE_STARTING) + device->state = STATE_STOPPED; + + LeaveCriticalSection(&(device->mixlock)); + /* **** */ + + return DS_OK; +} + +static ULONG WINAPI PrimaryBufferImpl_AddRef(LPDIRECTSOUNDBUFFER8 iface) +{ + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI PrimaryBufferImpl_Release(LPDIRECTSOUNDBUFFER8 iface) +{ + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + DWORD ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + This->dsound->device->primary = NULL; + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI PrimaryBufferImpl_GetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD playpos,LPDWORD writepos +) { + HRESULT hres; + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%p,%p)\n", iface, playpos, writepos); + + hres = DSOUND_PrimaryGetPosition(device, playpos, writepos); + if (hres != DS_OK) { + WARN("DSOUND_PrimaryGetPosition failed\n"); + return hres; + } + if (writepos) { + if (device->state != STATE_STOPPED) + /* apply the documented 10ms lead to writepos */ + *writepos += device->writelead; + while (*writepos >= device->buflen) *writepos -= device->buflen; + } + TRACE("playpos = %ld, writepos = %ld (%p, time=%ld)\n", playpos?*playpos:0, writepos?*writepos:0, device, GetTickCount()); + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_GetStatus( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD status +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%p)\n", iface, status); + + if (status == NULL) { + WARN("invalid parameter: status == NULL\n"); + return DSERR_INVALIDPARAM; + } + + *status = 0; + if ((device->state == STATE_STARTING) || + (device->state == STATE_PLAYING)) + *status |= DSBSTATUS_PLAYING | DSBSTATUS_LOOPING; + + TRACE("status=%lx\n", *status); + return DS_OK; +} + + +static HRESULT WINAPI PrimaryBufferImpl_GetFormat( + LPDIRECTSOUNDBUFFER8 iface, + LPWAVEFORMATEX lpwf, + DWORD wfsize, + LPDWORD wfwritten) +{ + DWORD size; + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%p,%ld,%p)\n", iface, lpwf, wfsize, wfwritten); + + size = sizeof(WAVEFORMATEX) + device->pwfx->cbSize; + + if (lpwf) { /* NULL is valid */ + if (wfsize >= size) { + CopyMemory(lpwf,device->pwfx,size); + if (wfwritten) + *wfwritten = size; + } else { + WARN("invalid parameter: wfsize too small\n"); + if (wfwritten) + *wfwritten = 0; + return DSERR_INVALIDPARAM; + } + } else { + if (wfwritten) + *wfwritten = sizeof(WAVEFORMATEX) + device->pwfx->cbSize; + else { + WARN("invalid parameter: wfwritten == NULL\n"); + return DSERR_INVALIDPARAM; + } + } + + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_Lock( + LPDIRECTSOUNDBUFFER8 iface,DWORD writecursor,DWORD writebytes,LPVOID lplpaudioptr1,LPDWORD audiobytes1,LPVOID lplpaudioptr2,LPDWORD audiobytes2,DWORD flags +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%ld,%ld,%p,%p,%p,%p,0x%08lx) at %ld\n", + iface, + writecursor, + writebytes, + lplpaudioptr1, + audiobytes1, + lplpaudioptr2, + audiobytes2, + flags, + GetTickCount() + ); + + if (device->priolevel != DSSCL_WRITEPRIMARY) { + WARN("failed priority check!\n"); + return DSERR_PRIOLEVELNEEDED; + } + + if (flags & DSBLOCK_FROMWRITECURSOR) { + DWORD writepos; + HRESULT hres; + /* GetCurrentPosition does too much magic to duplicate here */ + hres = IDirectSoundBuffer_GetCurrentPosition(iface, NULL, &writepos); + if (hres != DS_OK) { + WARN("IDirectSoundBuffer_GetCurrentPosition failed\n"); + return hres; + } + writecursor += writepos; + } + while (writecursor >= device->buflen) + writecursor -= device->buflen; + if (flags & DSBLOCK_ENTIREBUFFER) + writebytes = device->buflen; + if (writebytes > device->buflen) + writebytes = device->buflen; + + if (!(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && device->hwbuf) { + HRESULT hres; + hres = IDsDriverBuffer_Lock(device->hwbuf, + lplpaudioptr1, audiobytes1, + lplpaudioptr2, audiobytes2, + writecursor, writebytes, + 0); + if (hres != DS_OK) { + WARN("IDsDriverBuffer_Lock failed\n"); + return hres; + } + } else { + if (writecursor+writebytes <= device->buflen) { + *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor; + *audiobytes1 = writebytes; + if (lplpaudioptr2) + *(LPBYTE*)lplpaudioptr2 = NULL; + if (audiobytes2) + *audiobytes2 = 0; + TRACE("->%ld.0\n",writebytes); + } else { + *(LPBYTE*)lplpaudioptr1 = device->buffer+writecursor; + *audiobytes1 = device->buflen-writecursor; + if (lplpaudioptr2) + *(LPBYTE*)lplpaudioptr2 = device->buffer; + if (audiobytes2) + *audiobytes2 = writebytes-(device->buflen-writecursor); + TRACE("->%ld.%ld\n",*audiobytes1,audiobytes2?*audiobytes2:0); + } + } + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_SetCurrentPosition( + LPDIRECTSOUNDBUFFER8 iface,DWORD newpos +) { + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + TRACE("(%p,%ld)\n",This,newpos); + + /* You cannot set the position of the primary buffer */ + WARN("invalid call\n"); + return DSERR_INVALIDCALL; +} + +static HRESULT WINAPI PrimaryBufferImpl_SetPan( + LPDIRECTSOUNDBUFFER8 iface,LONG pan +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + DWORD ampfactors; + DSVOLUMEPAN volpan; + HRESULT hres = DS_OK; + TRACE("(%p,%ld)\n", iface, pan); + + if (!(device->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT)) { + WARN("invalid parameter: pan = %ld\n", pan); + return DSERR_INVALIDPARAM; + } + + /* **** */ + EnterCriticalSection(&(device->mixlock)); + + waveOutGetVolume(device->hwo, &factors); + volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; + volpan.dwTotalRightAmpFactor=ampfactors >> 16; + DSOUND_AmpFactorToVolPan(&volpan); + if (pan != volpan.lPan) { + volpan.lPan=pan; + DSOUND_RecalcVolPan(&volpan); + if (device->hwbuf) { + hres = IDsDriverBuffer_SetVolumePan(device->hwbuf, &volpan); + if (hres != DS_OK) + WARN("IDsDriverBuffer_SetVolumePan failed\n"); + } else { + ampfactors = (volpan.dwTotalLeftAmpFactor & 0xffff) | (volpan.dwTotalRightAmpFactor << 16); + waveOutSetVolume(device->hwo, ampfactors); + } + } + + LeaveCriticalSection(&(device->mixlock)); + /* **** */ + + return hres; +} + +static HRESULT WINAPI PrimaryBufferImpl_GetPan( + LPDIRECTSOUNDBUFFER8 iface,LPLONG pan +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + DWORD ampfactors; + DSVOLUMEPAN volpan; + TRACE("(%p,%p)\n", iface, pan); + + if (!(device->dsbd.dwFlags & DSBCAPS_CTRLPAN)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + if (pan == NULL) { + WARN("invalid parameter: pan == NULL\n"); + return DSERR_INVALIDPARAM; + } + + waveOutGetVolume(device->hwo, &factors); + volpan.dwTotalLeftAmpFactor=ampfactors & 0xffff; + volpan.dwTotalRightAmpFactor=ampfactors >> 16; + DSOUND_AmpFactorToVolPan(&volpan); + *pan = volpan.lPan; + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_Unlock( + LPDIRECTSOUNDBUFFER8 iface,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2 +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%p,%ld,%p,%ld)\n", iface, p1, x1, p2, x2); + + if (device->priolevel != DSSCL_WRITEPRIMARY) { + WARN("failed priority check!\n"); + return DSERR_PRIOLEVELNEEDED; + } + + if (!(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK) && device->hwbuf) { + HRESULT hres; + + hres = IDsDriverBuffer_Unlock(device->hwbuf, p1, x1, p2, x2); + if (hres != DS_OK) { + WARN("IDsDriverBuffer_Unlock failed\n"); + return hres; + } + } + + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_Restore( + LPDIRECTSOUNDBUFFER8 iface +) { + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + FIXME("(%p):stub\n",This); + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_GetFrequency( + LPDIRECTSOUNDBUFFER8 iface,LPDWORD freq +) { + DirectSoundDevice *device = ((PrimaryBufferImpl *)iface)->dsound->device; + TRACE("(%p,%p)\n", iface, freq); + + if (freq == NULL) { + WARN("invalid parameter: freq == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (!(device->dsbd.dwFlags & DSBCAPS_CTRLFREQUENCY)) { + WARN("control unavailable\n"); + return DSERR_CONTROLUNAVAIL; + } + + *freq = device->pwfx->nSamplesPerSec; + TRACE("-> %ld\n", *freq); + + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_SetFX( + LPDIRECTSOUNDBUFFER8 iface,DWORD dwEffectsCount,LPDSEFFECTDESC pDSFXDesc,LPDWORD pdwResultCodes +) { + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + DWORD u; + FIXME("(%p,%lu,%p,%p): stub\n",This,dwEffectsCount,pDSFXDesc,pdwResultCodes); + + if (pdwResultCodes) + for (u=0; udsound->device; + TRACE("(%p,%p)\n", iface, caps); + + if (caps == NULL) { + WARN("invalid parameter: caps == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (caps->dwSize < sizeof(*caps)) { + WARN("invalid parameter: caps->dwSize = %ld: < %d\n", caps->dwSize, sizeof(*caps)); + return DSERR_INVALIDPARAM; + } + + caps->dwFlags = device->dsbd.dwFlags; + if (device->hwbuf) caps->dwFlags |= DSBCAPS_LOCHARDWARE; + else caps->dwFlags |= DSBCAPS_LOCSOFTWARE; + + caps->dwBufferBytes = device->buflen; + + /* This value represents the speed of the "unlock" command. + As unlock is quite fast (it does not do anything), I put + 4096 ko/s = 4 Mo / s */ + /* FIXME: hwbuf speed */ + caps->dwUnlockTransferRate = 4096; + caps->dwPlayCpuOverhead = 0; + + return DS_OK; +} + +static HRESULT WINAPI PrimaryBufferImpl_QueryInterface( + LPDIRECTSOUNDBUFFER8 iface,REFIID riid,LPVOID *ppobj +) { + PrimaryBufferImpl *This = (PrimaryBufferImpl *)iface; + DirectSoundDevice *device = This->dsound->device; + TRACE("(%p,%s,%p)\n", iface, 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) ) { + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)This); + *ppobj = This; + return S_OK; + } + + /* DirectSoundBuffer and DirectSoundBuffer8 are different and */ + /* a primary buffer can't have a DirectSoundBuffer8 interface */ + if ( IsEqualGUID( &IID_IDirectSoundBuffer8, riid ) ) { + WARN("app requested DirectSoundBuffer8 on primary buffer\n"); + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IDirectSoundNotify, riid ) ) { + ERR("app requested IDirectSoundNotify on primary buffer\n"); + /* FIXME: should we support this? */ + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IDirectSound3DBuffer, riid ) ) { + ERR("app requested IDirectSound3DBuffer on primary buffer\n"); + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IDirectSound3DListener, riid ) ) { + if (!device->listener) + IDirectSound3DListenerImpl_Create(This, &device->listener); + if (device->listener) { + *ppobj = device->listener; + IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)*ppobj); + return S_OK; + } + + WARN("IID_IDirectSound3DListener failed\n"); + return E_NOINTERFACE; + } + + if ( IsEqualGUID( &IID_IKsPropertySet, riid ) ) { + FIXME("app requested IKsPropertySet on primary buffer\n"); + return E_NOINTERFACE; + } + + FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); + return E_NOINTERFACE; +} + +static const IDirectSoundBuffer8Vtbl dspbvt = +{ + PrimaryBufferImpl_QueryInterface, + PrimaryBufferImpl_AddRef, + PrimaryBufferImpl_Release, + PrimaryBufferImpl_GetCaps, + PrimaryBufferImpl_GetCurrentPosition, + PrimaryBufferImpl_GetFormat, + PrimaryBufferImpl_GetVolume, + PrimaryBufferImpl_GetPan, + PrimaryBufferImpl_GetFrequency, + PrimaryBufferImpl_GetStatus, + PrimaryBufferImpl_Initialize, + PrimaryBufferImpl_Lock, + PrimaryBufferImpl_Play, + PrimaryBufferImpl_SetCurrentPosition, + PrimaryBufferImpl_SetFormat, + PrimaryBufferImpl_SetVolume, + PrimaryBufferImpl_SetPan, + PrimaryBufferImpl_SetFrequency, + PrimaryBufferImpl_Stop, + PrimaryBufferImpl_Unlock, + PrimaryBufferImpl_Restore, + PrimaryBufferImpl_SetFX, + PrimaryBufferImpl_AcquireResources, + PrimaryBufferImpl_GetObjectInPath +}; + +HRESULT WINAPI PrimaryBufferImpl_Create( + IDirectSoundImpl *ds, + PrimaryBufferImpl **pdsb, + LPCDSBUFFERDESC dsbd) +{ + PrimaryBufferImpl *dsb; + TRACE("%p,%p,%p)\n",ds,pdsb,dsbd); + + if (dsbd->lpwfxFormat) { + WARN("invalid parameter: dsbd->lpwfxFormat != NULL\n"); + *pdsb = NULL; + return DSERR_INVALIDPARAM; + } + + dsb = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsb)); + + if (dsb == NULL) { + WARN("out of memory\n"); + *pdsb = NULL; + return DSERR_OUTOFMEMORY; + } + + dsb->ref = 0; + dsb->dsound = ds; + dsb->lpVtbl = &dspbvt; + + CopyMemory(&ds->device->dsbd, dsbd, sizeof(*dsbd)); + + TRACE("Created primary buffer at %p\n", dsb); + TRACE("(formattag=0x%04x,chans=%d,samplerate=%ld," + "bytespersec=%ld,blockalign=%d,bitspersamp=%d,cbSize=%d)\n", + ds->device->pwfx->wFormatTag, ds->device->pwfx->nChannels, ds->device->pwfx->nSamplesPerSec, + ds->device->pwfx->nAvgBytesPerSec, ds->device->pwfx->nBlockAlign, + ds->device->pwfx->wBitsPerSample, ds->device->pwfx->cbSize); + + *pdsb = dsb; + return S_OK; +} diff --git a/reactos/lib/dsound/propset.c b/reactos/lib/dsound/propset.c index 16a89aa5e95..0309b81ebcc 100644 --- a/reactos/lib/dsound/propset.c +++ b/reactos/lib/dsound/propset.c @@ -1,1163 +1,1516 @@ -/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#include /* Insomnia - pow() function */ - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winreg.h" -#include "winternl.h" -#include "winnls.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" -#include "initguid.h" -#include "dsconf.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dsound); - - -/******************************************************************************* - * IKsBufferPropertySet - */ - -/* IUnknown methods */ -static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface( - LPKSPROPERTYSET iface, - REFIID riid, - LPVOID *ppobj ) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - - return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj); -} - -static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - ULONG ulReturn; - - TRACE("(%p) ref was %ld\n", This, This->ref); - ulReturn = InterlockedDecrement(&(This->ref)); - if (!ulReturn) { - This->dsb->iks = 0; - IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - return ulReturn; -} - -static HRESULT WINAPI IKsBufferPropertySetImpl_Get( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - LPVOID pInstanceData, - ULONG cbInstanceData, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - PIDSDRIVERPROPERTYSET ps; - TRACE("(iface=%p,guidPropSet=%s,dwPropID=%ld,pInstanceData=%p,cbInstanceData=%ld,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned); - - if (This->dsb->hwbuf) { - IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); - - if (ps) { - DSPROPERTY prop; - HRESULT hres; - - prop.s.Set = *guidPropSet; - prop.s.Id = dwPropID; - prop.s.Flags = 0; /* unused */ - prop.s.InstanceId = (ULONG)This->dsb->dsound; - - hres = IDsDriverPropertySet_Get(ps, &prop, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned); - - IDsDriverPropertySet_Release(ps); - - return hres; - } - } - - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI IKsBufferPropertySetImpl_Set( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - LPVOID pInstanceData, - ULONG cbInstanceData, - LPVOID pPropData, - ULONG cbPropData ) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - PIDSDRIVERPROPERTYSET ps; - TRACE("(%p,%s,%ld,%p,%ld,%p,%ld)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData); - - if (This->dsb->hwbuf) { - IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); - - if (ps) { - DSPROPERTY prop; - HRESULT hres; - - prop.s.Set = *guidPropSet; - prop.s.Id = dwPropID; - prop.s.Flags = 0; /* unused */ - prop.s.InstanceId = (ULONG)This->dsb->dsound; - hres = IDsDriverPropertySet_Set(ps,&prop,pInstanceData,cbInstanceData,pPropData,cbPropData); - - IDsDriverPropertySet_Release(ps); - - return hres; - } - } - - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - PULONG pTypeSupport ) -{ - IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; - PIDSDRIVERPROPERTYSET ps; - TRACE("(%p,%s,%ld,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport); - - if (This->dsb->hwbuf) { - IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); - - if (ps) { - HRESULT hres; - - hres = IDsDriverPropertySet_QuerySupport(ps,guidPropSet, dwPropID,pTypeSupport); - - IDsDriverPropertySet_Release(ps); - - return hres; - } - } - - return E_PROP_ID_UNSUPPORTED; -} - -static IKsPropertySetVtbl iksbvt = { - IKsBufferPropertySetImpl_QueryInterface, - IKsBufferPropertySetImpl_AddRef, - IKsBufferPropertySetImpl_Release, - IKsBufferPropertySetImpl_Get, - IKsBufferPropertySetImpl_Set, - IKsBufferPropertySetImpl_QuerySupport -}; - -HRESULT WINAPI IKsBufferPropertySetImpl_Create( - IDirectSoundBufferImpl *dsb, - IKsBufferPropertySetImpl **piks) -{ - IKsBufferPropertySetImpl *iks; - TRACE("(%p,%p)\n",dsb,piks); - - iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks)); - if (iks == 0) { - WARN("out of memory\n"); - *piks = NULL; - return DSERR_OUTOFMEMORY; - } - - iks->ref = 0; - iks->dsb = dsb; - dsb->iks = iks; - iks->lpVtbl = &iksbvt; - - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); - - *piks = iks; - return S_OK; -} - -HRESULT WINAPI IKsBufferPropertySetImpl_Destroy( - IKsBufferPropertySetImpl *piks) -{ - TRACE("(%p)\n",piks); - - while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0); - - return S_OK; -} - -/******************************************************************************* - * IKsPrivatePropertySet - */ - -/* IUnknown methods */ -static HRESULT WINAPI IKsPrivatePropertySetImpl_QueryInterface( - LPKSPROPERTYSET iface, - REFIID riid, - LPVOID *ppobj ) -{ - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - - *ppobj = NULL; - return DSERR_INVALIDPARAM; -} - -static ULONG WINAPI IKsPrivatePropertySetImpl_AddRef(LPKSPROPERTYSET iface) -{ - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - TRACE("(%p) ref was %ld\n", This, This->ref); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IKsPrivatePropertySetImpl_Release(LPKSPROPERTYSET iface) -{ - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - ULONG ulReturn; - - TRACE("(%p) ref was %ld\n", This, This->ref); - ulReturn = InterlockedDecrement(&(This->ref)); - if (ulReturn == 0) { - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - return ulReturn; -} - -static HRESULT WINAPI DSPROPERTY_WaveDeviceMappingA( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A_DATA ppd; - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) not implemented!\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A_DATA) pPropData; - - if (!ppd) { - WARN("invalid parameter: pPropData\n"); - return DSERR_INVALIDPARAM; - } - - FIXME("DeviceName=%s\n",ppd->DeviceName); - FIXME("DataFlow=%s\n", - ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "DIRECTSOUNDDEVICE_DATAFLOW_RENDER" : - ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? "DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE" : "UNKNOWN"); - - /* FIXME: match the name to a wave device somehow. */ - ppd->DeviceId = GUID_NULL; - - if (pcbReturned) { - *pcbReturned = cbPropData; - FIXME("*pcbReturned=%ld\n", *pcbReturned); - } - - return S_OK; -} - -static HRESULT WINAPI DSPROPERTY_WaveDeviceMappingW( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W_DATA ppd; - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) not implemented!\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W_DATA) pPropData; - - if (!ppd) { - WARN("invalid parameter: pPropData\n"); - return DSERR_INVALIDPARAM; - } - - FIXME("DeviceName=%s\n",debugstr_w(ppd->DeviceName)); - FIXME("DataFlow=%s\n", - ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "DIRECTSOUNDDEVICE_DATAFLOW_RENDER" : - ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? "DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE" : "UNKNOWN"); - - /* FIXME: match the name to a wave device somehow. */ - ppd->DeviceId = GUID_NULL; - - if (pcbReturned) { - *pcbReturned = cbPropData; - FIXME("*pcbReturned=%ld\n", *pcbReturned); - } - - return S_OK; -} - -static HRESULT WINAPI DSPROPERTY_Description1( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - HRESULT err; - GUID guid, dev_guid; - PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA ppd; - TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA) pPropData; - - if (!ppd) { - WARN("invalid parameter: pPropData\n"); - return DSERR_INVALIDPARAM; - } - - TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); - if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { - /* default device of type specified by ppd->DataFlow */ - if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - } else { - TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); - } - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - return E_PROP_ID_UNSUPPORTED; - } - - ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; - GetDeviceID(&ppd->DeviceId, &dev_guid); - - if ( IsEqualGUID( &ppd->DeviceId, &DSDEVID_DefaultPlayback) || - IsEqualGUID( &ppd->DeviceId, &DSDEVID_DefaultVoicePlayback) ) { - ULONG wod; - unsigned int wodn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &dev_guid, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wod; - ppd->Devnode = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - strncpy(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA) - 1); - strncpy(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA) - 1); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - } else if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || - IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { - ULONG wid; - unsigned int widn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - widn = waveInGetNumDevs(); - for (wid = 0; wid < widn; wid++) { - if (IsEqualGUID( &dev_guid, &guid) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wid; - ppd->Devnode = wid; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSCDRIVER drv; - strncpy(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA) - 1); - strncpy(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA) - 1); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&drv,0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveInMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - } else { - BOOL found = FALSE; - ULONG wod; - unsigned int wodn; - /* given specific device so try the render devices first */ - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &ppd->DeviceId, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - ppd->WaveDeviceId = wod; - ppd->Devnode = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - strncpy(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA) - 1); - strncpy(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA) - 1); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - found = TRUE; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - - if (found == FALSE) { - ULONG wid; - unsigned int widn; - /* given specific device so try the capture devices next */ - widn = waveInGetNumDevs(); - for (wid = 0; wid < widn; wid++) { - if (IsEqualGUID( &ppd->DeviceId, &capture_guids[wid] ) ) { - DSDRIVERDESC desc; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - ppd->WaveDeviceId = wid; - ppd->Devnode = wid; - err = mmErr(WineWaveInMessage((HWAVEIN)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - strncpy(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA) - 1); - strncpy(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA) - 1); - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); - err = mmErr(WineWaveInMessage((HWAVEIN)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - found = TRUE; - break; - } else { - WARN("WineWaveInMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - - if (found == FALSE) { - WARN("device not found\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - - if (pcbReturned) { - *pcbReturned = cbPropData; - TRACE("*pcbReturned=%ld\n", *pcbReturned); - } - - return S_OK; -} - -static HRESULT WINAPI DSPROPERTY_DescriptionA( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA) pPropData; - HRESULT err; - GUID dev_guid; - TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); - if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { - /* default device of type specified by ppd->DataFlow */ - if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - } else { - TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); - } - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - return E_PROP_ID_UNSUPPORTED; - } - - ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; - GetDeviceID(&ppd->DeviceId, &dev_guid); - - if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) || - IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoicePlayback) ) { - ULONG wod; - unsigned int wodn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &dev_guid, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - /* FIXME: this is a memory leak */ - CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); - CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); - CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); - - strcpy(szDescription, desc.szDesc); - strcpy(szModule, desc.szDrvname); - strcpy(szInterface, "Interface"); - - ppd->Description = szDescription; - ppd->Module = szModule; - ppd->Interface = szInterface; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - } else if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || - IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { - ULONG wid; - unsigned int widn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - widn = waveInGetNumDevs(); - for (wid = 0; wid < widn; wid++) { - if (IsEqualGUID( &dev_guid, &capture_guids[wid] ) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wid; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSCDRIVER drv; - /* FIXME: this is a memory leak */ - CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); - CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); - CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); - - strcpy(szDescription, desc.szDesc); - strcpy(szModule, desc.szDrvname); - strcpy(szInterface, "Interface"); - - ppd->Description = szDescription; - ppd->Module = szModule; - ppd->Interface = szInterface; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&drv,0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveInMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - break; - } - } - } else { - BOOL found = FALSE; - ULONG wod; - unsigned int wodn; - /* given specific device so try the render devices first */ - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &ppd->DeviceId, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - ppd->WaveDeviceId = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - /* FIXME: this is a memory leak */ - CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); - CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); - CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); - - strcpy(szDescription, desc.szDesc); - strcpy(szModule, desc.szDrvname); - strcpy(szInterface, "Interface"); - - ppd->Description = szDescription; - ppd->Module = szModule; - ppd->Interface = szInterface; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - found = TRUE; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - - if (found == FALSE) { - WARN("device not found\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - - if (pcbReturned) { - *pcbReturned = cbPropData; - TRACE("*pcbReturned=%ld\n", *pcbReturned); - } - - return S_OK; -} - -static HRESULT WINAPI DSPROPERTY_DescriptionW( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA) pPropData; - HRESULT err; - GUID dev_guid; - TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); - if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { - /* default device of type specified by ppd->DataFlow */ - if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - } else { - TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); - } - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - return E_PROP_ID_UNSUPPORTED; - } - - ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; - GetDeviceID(&ppd->DeviceId, &dev_guid); - - if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) || - IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoicePlayback) ) { - ULONG wod; - unsigned int wodn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &dev_guid, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - /* FIXME: this is a memory leak */ - WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); - - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); - - ppd->Description = wDescription; - ppd->Module = wModule; - ppd->Interface = wInterface; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - } else if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || - IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { - ULONG wid; - unsigned int widn; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - widn = waveInGetNumDevs(); - for (wid = 0; wid < widn; wid++) { - if (IsEqualGUID( &dev_guid, &capture_guids[wid] ) ) { - DSDRIVERDESC desc; - ppd->WaveDeviceId = wid; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSCDRIVER drv; - /* FIXME: this is a memory leak */ - WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); - - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); - - ppd->Description = wDescription; - ppd->Module = wModule; - ppd->Interface = wInterface; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD)&drv,0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - break; - } else { - WARN("WineWaveInMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - break; - } - } - } else { - BOOL found = FALSE; - ULONG wod; - unsigned int wodn; - /* given specific device so try the render devices first */ - wodn = waveOutGetNumDevs(); - for (wod = 0; wod < wodn; wod++) { - if (IsEqualGUID( &ppd->DeviceId, &renderer_guids[wod] ) ) { - DSDRIVERDESC desc; - TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); - ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - ppd->WaveDeviceId = wod; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&(desc),0)); - if (err == DS_OK) { - PIDSDRIVER drv = NULL; - /* FIXME: this is a memory leak */ - WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); - - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); - - ppd->Description = wDescription; - ppd->Module = wModule; - ppd->Interface = wInterface; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD)&drv, 0)); - if (err == DS_OK && drv) - ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; - found = TRUE; - break; - } else { - WARN("WineWaveOutMessage failed\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - } - - if (found == FALSE) { - WARN("device not found\n"); - return E_PROP_ID_UNSUPPORTED; - } - } - - if (pcbReturned) { - *pcbReturned = cbPropData; - TRACE("*pcbReturned=%ld\n", *pcbReturned); - } - - return S_OK; -} - -static HRESULT WINAPI DSPROPERTY_Enumerate1( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI DSPROPERTY_EnumerateA( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA) pPropData; - HRESULT err; - TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { - if (ppd) { - if (ppd->Callback) { - unsigned devs, wod, wid; - DSDRIVERDESC desc; - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data; - - devs = waveOutGetNumDevs(); - for (wod = 0; wod < devs; ++wod) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - DWORD size; - memset(&data, 0, sizeof(data)); - data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - data.WaveDeviceId = wod; - data.DeviceId = renderer_guids[wod]; - data.Description = desc.szDesc; - data.Module = desc.szDrvname; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACESIZE,(DWORD_PTR)&size,0)); - if (err == DS_OK) { - WCHAR * nameW = HeapAlloc(GetProcessHeap(),0,size); - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACE,(DWORD_PTR)nameW,size)); - if (err == DS_OK) { - CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,size/sizeof(WCHAR)); - WideCharToMultiByte( CP_ACP, 0, nameW, size/sizeof(WCHAR), szInterface, size/sizeof(WCHAR), NULL, NULL ); - data.Interface = szInterface; - - TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); - (ppd->Callback)(&data, ppd->Context); - - HeapFree(GetProcessHeap(),0,szInterface); - } - HeapFree(GetProcessHeap(),0,nameW); - } - } - } - - devs = waveInGetNumDevs(); - for (wid = 0; wid < devs; ++wid) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - DWORD size; - memset(&data, 0, sizeof(data)); - data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - data.WaveDeviceId = wid; - data.DeviceId = capture_guids[wid]; - data.Description = desc.szDesc; - data.Module = desc.szDrvname; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACESIZE,(DWORD_PTR)&size,0)); - if (err == DS_OK) { - WCHAR * nameW = HeapAlloc(GetProcessHeap(),0,size); - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACE,(DWORD_PTR)nameW,size)); - if (err == DS_OK) { - CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,size/sizeof(WCHAR)); - WideCharToMultiByte( CP_ACP, 0, nameW, size/sizeof(WCHAR), szInterface, size/sizeof(WCHAR), NULL, NULL ); - data.Interface = szInterface; - - TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); - (ppd->Callback)(&data, ppd->Context); - - HeapFree(GetProcessHeap(),0,szInterface); - } - HeapFree(GetProcessHeap(),0,nameW); - } - } - } - - return S_OK; - } - } - } else { - FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); - } - - if (pcbReturned) { - *pcbReturned = 0; - FIXME("*pcbReturned=%ld\n", *pcbReturned); - } - - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI DSPROPERTY_EnumerateW( - REFGUID guidPropSet, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned ) -{ - PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA) pPropData; - HRESULT err; - TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); - - if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { - if (ppd) { - if (ppd->Callback) { - unsigned devs, wod, wid; - DSDRIVERDESC desc; - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data; - - devs = waveOutGetNumDevs(); - for (wod = 0; wod < devs; ++wod) { - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); - DWORD size; - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&size, 0)); - if (err == DS_OK) { - WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,size); - err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)wInterface, size)); - if (err == DS_OK) { - memset(&data, 0, sizeof(data)); - data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; - data.WaveDeviceId = wod; - data.DeviceId = renderer_guids[wod]; - - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); - - data.Description = wDescription; - data.Module = wModule; - data.Interface = wInterface; - - TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); - (ppd->Callback)(&data, ppd->Context); - } - HeapFree(GetProcessHeap(),0,wInterface); - } - HeapFree(GetProcessHeap(),0,wDescription); - HeapFree(GetProcessHeap(),0,wModule); - } - } - - devs = waveInGetNumDevs(); - for (wid = 0; wid < devs; ++wid) { - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD)&desc,0)); - if (err == DS_OK) { - WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); - WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); - DWORD size; - err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&size, 0)); - if (err == DS_OK) { - WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,size); - err = mmErr(WineWaveInMessage((HWAVEIN)wod, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)wInterface, size)); - if (err == DS_OK) { - memset(&data, 0, sizeof(data)); - data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; - data.WaveDeviceId = wid; - data.DeviceId = capture_guids[wid]; - - MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); - MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); - - data.Description = wDescription; - data.Module = wModule; - data.Interface = wInterface; - TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); - (ppd->Callback)(&data, ppd->Context); - } - HeapFree(GetProcessHeap(),0,wInterface); - } - HeapFree(GetProcessHeap(),0,wDescription); - HeapFree(GetProcessHeap(),0,wModule); - } - } - - return S_OK; - } - } - } else { - FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); - } - - if (pcbReturned) { - *pcbReturned = 0; - FIXME("*pcbReturned=%ld\n", *pcbReturned); - } - - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI IKsPrivatePropertySetImpl_Get( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - LPVOID pInstanceData, - ULONG cbInstanceData, - LPVOID pPropData, - ULONG cbPropData, - PULONG pcbReturned -) { - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - TRACE("(iface=%p,guidPropSet=%s,dwPropID=%ld,pInstanceData=%p,cbInstanceData=%ld,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", - This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned); - - if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { - switch (dwPropID) { - case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: - return DSPROPERTY_WaveDeviceMappingA(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: - return DSPROPERTY_Description1(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: - return DSPROPERTY_Enumerate1(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: - return DSPROPERTY_WaveDeviceMappingW(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: - return DSPROPERTY_DescriptionA(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: - return DSPROPERTY_DescriptionW(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: - return DSPROPERTY_EnumerateA(guidPropSet,pPropData,cbPropData,pcbReturned); - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: - return DSPROPERTY_EnumerateW(guidPropSet,pPropData,cbPropData,pcbReturned); - default: - FIXME("unsupported ID: %ld\n",dwPropID); - break; - } - } else { - FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); - } - - if (pcbReturned) { - *pcbReturned = 0; - FIXME("*pcbReturned=%ld\n", *pcbReturned); - } - - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI IKsPrivatePropertySetImpl_Set( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - LPVOID pInstanceData, - ULONG cbInstanceData, - LPVOID pPropData, - ULONG cbPropData ) -{ - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - - FIXME("(%p,%s,%ld,%p,%ld,%p,%ld), stub!\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData); - return E_PROP_ID_UNSUPPORTED; -} - -static HRESULT WINAPI IKsPrivatePropertySetImpl_QuerySupport( - LPKSPROPERTYSET iface, - REFGUID guidPropSet, - ULONG dwPropID, - PULONG pTypeSupport ) -{ - IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; - TRACE("(%p,%s,%ld,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport); - - if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { - switch (dwPropID) { - case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: - *pTypeSupport = KSPROPERTY_SUPPORT_GET; - return S_OK; - default: - FIXME("unsupported ID: %ld\n",dwPropID); - break; - } - } else { - FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); - } - - return E_PROP_ID_UNSUPPORTED; -} - -static IKsPropertySetVtbl ikspvt = { - IKsPrivatePropertySetImpl_QueryInterface, - IKsPrivatePropertySetImpl_AddRef, - IKsPrivatePropertySetImpl_Release, - IKsPrivatePropertySetImpl_Get, - IKsPrivatePropertySetImpl_Set, - IKsPrivatePropertySetImpl_QuerySupport -}; - -HRESULT WINAPI IKsPrivatePropertySetImpl_Create( - IKsPrivatePropertySetImpl **piks) -{ - IKsPrivatePropertySetImpl *iks; - - iks = HeapAlloc(GetProcessHeap(),0,sizeof(*iks)); - iks->ref = 0; - iks->lpVtbl = &ikspvt; - - *piks = iks; - return S_OK; -} +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "winternl.h" +#include "winnls.h" +#include "vfwmsgs.h" +#include "mmddk.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" +#include "initguid.h" +#include "dsconf.h" + +#ifdef NONAMELESSSTRUCT +# define S(x) (x).s +#else +# define S(x) (x) +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(dsound); + + +/******************************************************************************* + * IKsBufferPropertySet + */ + +/* IUnknown methods */ +static HRESULT WINAPI IKsBufferPropertySetImpl_QueryInterface( + LPKSPROPERTYSET iface, + REFIID riid, + LPVOID *ppobj ) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + + return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj); +} + +static ULONG WINAPI IKsBufferPropertySetImpl_AddRef(LPKSPROPERTYSET iface) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IKsBufferPropertySetImpl_Release(LPKSPROPERTYSET iface) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + This->dsb->iks = 0; + IDirectSoundBuffer_Release((LPDIRECTSOUND3DBUFFER)This->dsb); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI IKsBufferPropertySetImpl_Get( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + LPVOID pInstanceData, + ULONG cbInstanceData, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + PIDSDRIVERPROPERTYSET ps; + TRACE("(iface=%p,guidPropSet=%s,dwPropID=%ld,pInstanceData=%p,cbInstanceData=%ld,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned); + + if (This->dsb->hwbuf) { + IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); + + if (ps) { + DSPROPERTY prop; + HRESULT hres; + + S(prop).Set = *guidPropSet; + S(prop).Id = dwPropID; + S(prop).Flags = 0; /* unused */ + S(prop).InstanceId = (ULONG)This->dsb->dsound; + + hres = IDsDriverPropertySet_Get(ps, &prop, pInstanceData, cbInstanceData, pPropData, cbPropData, pcbReturned); + + IDsDriverPropertySet_Release(ps); + + return hres; + } + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI IKsBufferPropertySetImpl_Set( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + LPVOID pInstanceData, + ULONG cbInstanceData, + LPVOID pPropData, + ULONG cbPropData ) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + PIDSDRIVERPROPERTYSET ps; + TRACE("(%p,%s,%ld,%p,%ld,%p,%ld)\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData); + + if (This->dsb->hwbuf) { + IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); + + if (ps) { + DSPROPERTY prop; + HRESULT hres; + + S(prop).Set = *guidPropSet; + S(prop).Id = dwPropID; + S(prop).Flags = 0; /* unused */ + S(prop).InstanceId = (ULONG)This->dsb->dsound; + hres = IDsDriverPropertySet_Set(ps,&prop,pInstanceData,cbInstanceData,pPropData,cbPropData); + + IDsDriverPropertySet_Release(ps); + + return hres; + } + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI IKsBufferPropertySetImpl_QuerySupport( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + PULONG pTypeSupport ) +{ + IKsBufferPropertySetImpl *This = (IKsBufferPropertySetImpl *)iface; + PIDSDRIVERPROPERTYSET ps; + TRACE("(%p,%s,%ld,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport); + + if (This->dsb->hwbuf) { + IDsDriver_QueryInterface(This->dsb->hwbuf, &IID_IDsDriverPropertySet, (void **)&ps); + + if (ps) { + HRESULT hres; + + hres = IDsDriverPropertySet_QuerySupport(ps,guidPropSet, dwPropID,pTypeSupport); + + IDsDriverPropertySet_Release(ps); + + return hres; + } + } + + return E_PROP_ID_UNSUPPORTED; +} + +static const IKsPropertySetVtbl iksbvt = { + IKsBufferPropertySetImpl_QueryInterface, + IKsBufferPropertySetImpl_AddRef, + IKsBufferPropertySetImpl_Release, + IKsBufferPropertySetImpl_Get, + IKsBufferPropertySetImpl_Set, + IKsBufferPropertySetImpl_QuerySupport +}; + +HRESULT WINAPI IKsBufferPropertySetImpl_Create( + IDirectSoundBufferImpl *dsb, + IKsBufferPropertySetImpl **piks) +{ + IKsBufferPropertySetImpl *iks; + TRACE("(%p,%p)\n",dsb,piks); + + iks = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*iks)); + if (iks == 0) { + WARN("out of memory\n"); + *piks = NULL; + return DSERR_OUTOFMEMORY; + } + + iks->ref = 0; + iks->dsb = dsb; + dsb->iks = iks; + iks->lpVtbl = &iksbvt; + + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)dsb); + + *piks = iks; + return S_OK; +} + +HRESULT WINAPI IKsBufferPropertySetImpl_Destroy( + IKsBufferPropertySetImpl *piks) +{ + TRACE("(%p)\n",piks); + + while (IKsBufferPropertySetImpl_Release((LPKSPROPERTYSET)piks) > 0); + + return S_OK; +} + +/******************************************************************************* + * IKsPrivatePropertySet + */ + +/* IUnknown methods */ +static HRESULT WINAPI IKsPrivatePropertySetImpl_QueryInterface( + LPKSPROPERTYSET iface, + REFIID riid, + LPVOID *ppobj ) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + + *ppobj = NULL; + return DSERR_INVALIDPARAM; +} + +static ULONG WINAPI IKsPrivatePropertySetImpl_AddRef(LPKSPROPERTYSET iface) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IKsPrivatePropertySetImpl_Release(LPKSPROPERTYSET iface) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +static HRESULT WINAPI DSPROPERTY_WaveDeviceMappingA( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + HRESULT hr = DSERR_INVALIDPARAM; + PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A_DATA ppd; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) not implemented!\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A_DATA) pPropData; + + if (!ppd) { + WARN("invalid parameter: pPropData\n"); + return DSERR_INVALIDPARAM; + } + + if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { + ULONG wod; + unsigned int wodn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + WAVEOUTCAPSA capsA; + MMRESULT res; + res = waveOutGetDevCapsA(wod, &capsA, sizeof(capsA)); + if (res == MMSYSERR_NOERROR) { + if (lstrcmpA(capsA.szPname, ppd->DeviceName) == 0) { + ppd->DeviceId = DSOUND_renderer_guids[wod]; + hr = DS_OK; + TRACE("found %s for %s\n", debugstr_guid(&ppd->DeviceId), + ppd->DeviceName); + break; + } + } + } + } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { + ULONG wid; + unsigned int widn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + WAVEINCAPSA capsA; + MMRESULT res; + res = waveInGetDevCapsA(wid, &capsA, sizeof(capsA)); + if (res == MMSYSERR_NOERROR) { + if (lstrcmpA(capsA.szPname, ppd->DeviceName) == 0) { + ppd->DeviceId = DSOUND_capture_guids[wid]; + TRACE("found %s for %s\n", debugstr_guid(&ppd->DeviceId), + ppd->DeviceName); + hr = DS_OK; + break; + } + } + } + } + + if (pcbReturned) + *pcbReturned = cbPropData; + + return hr; +} + +static HRESULT WINAPI DSPROPERTY_WaveDeviceMappingW( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + HRESULT hr = DSERR_INVALIDPARAM; + PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W_DATA ppd; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W_DATA) pPropData; + + if (!ppd) { + WARN("invalid parameter: pPropData\n"); + return DSERR_INVALIDPARAM; + } + + if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { + ULONG wod; + unsigned int wodn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + WAVEOUTCAPSW capsW; + MMRESULT res; + res = waveOutGetDevCapsW(wod, &capsW, sizeof(capsW)); + if (res == MMSYSERR_NOERROR) { + if (lstrcmpW(capsW.szPname, ppd->DeviceName) == 0) { + ppd->DeviceId = DSOUND_renderer_guids[wod]; + hr = DS_OK; + TRACE("found %s for %s\n", debugstr_guid(&ppd->DeviceId), + debugstr_w(ppd->DeviceName)); + break; + } + } + } + } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { + ULONG wid; + unsigned int widn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + WAVEINCAPSW capsW; + MMRESULT res; + res = waveInGetDevCapsW(wid, &capsW, sizeof(capsW)); + if (res == MMSYSERR_NOERROR) { + if (lstrcmpW(capsW.szPname, ppd->DeviceName) == 0) { + ppd->DeviceId = DSOUND_capture_guids[wid]; + hr = DS_OK; + TRACE("found %s for %s\n", debugstr_guid(&ppd->DeviceId), + debugstr_w(ppd->DeviceName)); + break; + } + } + } + } + + if (pcbReturned) + *pcbReturned = cbPropData; + + return hr; +} + +static HRESULT WINAPI DSPROPERTY_Description1( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + HRESULT err; + GUID guid, dev_guid; + PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA ppd; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA) pPropData; + + if (!ppd) { + WARN("invalid parameter: pPropData\n"); + return DSERR_INVALIDPARAM; + } + + TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); + if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { + /* default device of type specified by ppd->DataFlow */ + if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + } else { + TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); + } + FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + return E_PROP_ID_UNSUPPORTED; + } + + ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + GetDeviceID(&ppd->DeviceId, &dev_guid); + + if ( IsEqualGUID( &ppd->DeviceId, &DSDEVID_DefaultPlayback) || + IsEqualGUID( &ppd->DeviceId, &DSDEVID_DefaultVoicePlayback) ) { + ULONG wod; + unsigned int wodn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &dev_guid, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + ppd->WaveDeviceId = wod; + ppd->Devnode = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + lstrcpynA(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA)); + lstrcpynA(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA)); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || + IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { + ULONG wid; + unsigned int widn; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &dev_guid, &guid) ) { + DSDRIVERDESC desc; + ppd->WaveDeviceId = wid; + ppd->Devnode = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + lstrcpynA(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA)); + lstrcpynA(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA)); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&drv,0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else { + BOOL found = FALSE; + ULONG wod; + unsigned int wodn; + /* given specific device so try the render devices first */ + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &ppd->DeviceId, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + ppd->WaveDeviceId = wod; + ppd->Devnode = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + lstrcpynA(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA)); + lstrcpynA(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA)); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + + if (found == FALSE) { + ULONG wid; + unsigned int widn; + /* given specific device so try the capture devices next */ + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &ppd->DeviceId, &DSOUND_capture_guids[wid] ) ) { + DSDRIVERDESC desc; + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + ppd->WaveDeviceId = wid; + ppd->Devnode = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + lstrcpynA(ppd->DescriptionA, desc.szDesc, sizeof(ppd->DescriptionA)); + lstrcpynA(ppd->ModuleA, desc.szDrvname, sizeof(ppd->ModuleA)); + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, ppd->DescriptionW, sizeof(ppd->DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, ppd->ModuleW, sizeof(ppd->ModuleW)/sizeof(WCHAR) ); + err = mmErr(WineWaveInMessage((HWAVEIN)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + + if (found == FALSE) { + WARN("device not found\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + + if (pcbReturned) { + *pcbReturned = cbPropData; + TRACE("*pcbReturned=%ld\n", *pcbReturned); + } + + return S_OK; +} + +static HRESULT WINAPI DSPROPERTY_DescriptionA( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA) pPropData; + HRESULT err; + GUID dev_guid; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); + if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { + /* default device of type specified by ppd->DataFlow */ + if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + } else { + TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); + } + FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + return E_PROP_ID_UNSUPPORTED; + } + + ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + GetDeviceID(&ppd->DeviceId, &dev_guid); + + if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) || + IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoicePlayback) ) { + ULONG wod; + unsigned int wodn; + if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) ) + TRACE("DSDEVID_DefaultPlayback\n"); + else + TRACE("DSDEVID_DefaultVoicePlayback\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &dev_guid, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + ppd->WaveDeviceId = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); + CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); + + if (szDescription && szModule && szInterface) { + strcpy(szDescription, desc.szDesc); + strcpy(szModule, desc.szDrvname); + strcpy(szInterface, "Interface"); + + ppd->Description = szDescription; + ppd->Module = szModule; + ppd->Interface = szInterface; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, szDescription); + HeapFree(GetProcessHeap(), 0, szModule); + HeapFree(GetProcessHeap(), 0, szInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || + IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { + ULONG wid; + unsigned int widn; + if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) ) + TRACE("DSDEVID_DefaultCapture\n"); + else + TRACE("DSDEVID_DefaultVoiceCapture\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &dev_guid, &DSOUND_capture_guids[wid] ) ) { + DSDRIVERDESC desc; + ppd->WaveDeviceId = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + /* FIXME: this is a memory leak */ + CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); + CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); + + if (szDescription && szModule && szInterface) { + strcpy(szDescription, desc.szDesc); + strcpy(szModule, desc.szDrvname); + strcpy(szInterface, "Interface"); + + ppd->Description = szDescription; + ppd->Module = szModule; + ppd->Interface = szInterface; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&drv,0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, szDescription); + HeapFree(GetProcessHeap(), 0, szModule); + HeapFree(GetProcessHeap(), 0, szInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else { + BOOL found = FALSE; + ULONG wod; + unsigned int wodn; + /* given specific device so try the render devices first */ + TRACE("Checking renderer devices\n"); + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &ppd->DeviceId, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + TRACE("DSOUND_renderer_guids[%ld]\n", wod); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + ppd->WaveDeviceId = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); + CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); + + if (szDescription && szModule && szInterface) { + strcpy(szDescription, desc.szDesc); + strcpy(szModule, desc.szDrvname); + strcpy(szInterface, "Interface"); + + ppd->Description = szDescription; + ppd->Module = szModule; + ppd->Interface = szInterface; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, szDescription); + HeapFree(GetProcessHeap(), 0, szModule); + HeapFree(GetProcessHeap(), 0, szInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + + if (found == FALSE) { + ULONG wid; + unsigned int widn; + TRACE("Checking capture devices\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &ppd->DeviceId, &DSOUND_capture_guids[wid] ) ) { + DSDRIVERDESC desc; + TRACE("DSOUND_capture_guids[%ld]\n", wid); + ppd->WaveDeviceId = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + /* FIXME: this is a memory leak */ + CHAR * szDescription = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDesc) + 1); + CHAR * szModule = HeapAlloc(GetProcessHeap(),0,strlen(desc.szDrvname) + 1); + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,strlen("Interface") + 1); + + if (szDescription && szModule && szInterface) { + strcpy(szDescription, desc.szDesc); + strcpy(szModule, desc.szDrvname); + strcpy(szInterface, "Interface"); + + ppd->Description = szDescription; + ppd->Module = szModule; + ppd->Interface = szInterface; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&drv,0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, szDescription); + HeapFree(GetProcessHeap(), 0, szModule); + HeapFree(GetProcessHeap(), 0, szInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } + + if (found == FALSE) { + WARN("device not found\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + + if (pcbReturned) { + *pcbReturned = cbPropData; + TRACE("*pcbReturned=%ld\n", *pcbReturned); + } + + return S_OK; +} + +static HRESULT WINAPI DSPROPERTY_DescriptionW( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA) pPropData; + HRESULT err; + GUID dev_guid; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + TRACE("DeviceId=%s\n",debugstr_guid(&ppd->DeviceId)); + if ( IsEqualGUID( &ppd->DeviceId , &GUID_NULL) ) { + /* default device of type specified by ppd->DataFlow */ + if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE\n"); + } else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) { + TRACE("DataFlow=DIRECTSOUNDDEVICE_DATAFLOW_RENDER\n"); + } else { + TRACE("DataFlow=Unknown(%d)\n", ppd->DataFlow); + } + FIXME("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p) GUID_NULL not implemented!\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + return E_PROP_ID_UNSUPPORTED; + } + + ppd->Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + GetDeviceID(&ppd->DeviceId, &dev_guid); + + if ( IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) || + IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoicePlayback) ) { + ULONG wod; + unsigned int wodn; + if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultPlayback) ) + TRACE("DSDEVID_DefaultPlayback\n"); + else + TRACE("DSDEVID_DefaultVoicePlayback\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &dev_guid, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + TRACE("DSOUND_renderer_guids[%ld]\n", wod); + ppd->WaveDeviceId = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); + + if (wDescription && wModule && wInterface) { + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); + + ppd->Description = wDescription; + ppd->Module = wModule; + ppd->Interface = wInterface; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, wDescription); + HeapFree(GetProcessHeap(), 0, wModule); + HeapFree(GetProcessHeap(), 0, wInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture) || + IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultVoiceCapture) ) { + ULONG wid; + unsigned int widn; + if (IsEqualGUID( &ppd->DeviceId , &DSDEVID_DefaultCapture)) + TRACE("DSDEVID_DefaultCapture\n"); + else + TRACE("DSDEVID_DefaultVoiceCapture\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &dev_guid, &DSOUND_capture_guids[wid] ) ) { + DSDRIVERDESC desc; + ppd->WaveDeviceId = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + /* FIXME: this is a memory leak */ + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); + + if (wDescription && wModule && wInterface) { + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); + + ppd->Description = wDescription; + ppd->Module = wModule; + ppd->Interface = wInterface; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&drv,0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, wDescription); + HeapFree(GetProcessHeap(), 0, wModule); + HeapFree(GetProcessHeap(), 0, wInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } else { + BOOL found = FALSE; + ULONG wod; + unsigned int wodn; + TRACE("Checking renderer devices\n"); + /* given specific device so try the render devices first */ + wodn = waveOutGetNumDevs(); + for (wod = 0; wod < wodn; wod++) { + if (IsEqualGUID( &ppd->DeviceId, &DSOUND_renderer_guids[wod] ) ) { + DSDRIVERDESC desc; + TRACE("DSOUND_renderer_guids[%ld]\n", wod); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + ppd->WaveDeviceId = wod; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSDRIVER drv = NULL; + /* FIXME: this is a memory leak */ + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); + + if (wDescription && wModule && wInterface) { + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); + + ppd->Description = wDescription; + ppd->Module = wModule; + ppd->Interface = wInterface; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, wDescription); + HeapFree(GetProcessHeap(), 0, wModule); + HeapFree(GetProcessHeap(), 0, wInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + + if (found == FALSE) { + ULONG wid; + unsigned int widn; + TRACE("Checking capture devices\n"); + ppd->DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + widn = waveInGetNumDevs(); + for (wid = 0; wid < widn; wid++) { + if (IsEqualGUID( &dev_guid, &DSOUND_capture_guids[wid] ) ) { + DSDRIVERDESC desc; + TRACE("DSOUND_capture_guids[%ld]\n", wid); + ppd->WaveDeviceId = wid; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&(desc),0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + /* FIXME: this is a memory leak */ + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,0x200); + + if (wDescription && wModule && wInterface) { + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, "Interface", -1, wInterface, 0x100 ); + + ppd->Description = wDescription; + ppd->Module = wModule; + ppd->Interface = wInterface; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDIFACE,(DWORD_PTR)&drv,0)); + if (err == DS_OK && drv) + ppd->Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + found = TRUE; + break; + } else { + WARN("no memory\n"); + HeapFree(GetProcessHeap(), 0, wDescription); + HeapFree(GetProcessHeap(), 0, wModule); + HeapFree(GetProcessHeap(), 0, wInterface); + return E_OUTOFMEMORY; + } + } else { + WARN("WineWaveInMessage(DRV_QUERYDSOUNDDESC) failed\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + } + } + + if (found == FALSE) { + WARN("device not found\n"); + return E_PROP_ID_UNSUPPORTED; + } + } + + if (pcbReturned) { + *pcbReturned = cbPropData; + TRACE("*pcbReturned=%ld\n", *pcbReturned); + } + + return S_OK; +} + +static HRESULT WINAPI DSPROPERTY_Enumerate1( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA) pPropData; + HRESULT err; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { + if (ppd) { + if (ppd->Callback) { + unsigned devs, wod, wid; + DSDRIVERDESC desc; + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA data; + + devs = waveOutGetNumDevs(); + for (wod = 0; wod < devs; ++wod) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + data.WaveDeviceId = wod; + data.DeviceId = DSOUND_renderer_guids[wod]; + lstrcpynA(data.DescriptionA, desc.szDesc, sizeof(data.DescriptionA)); + lstrcpynA(data.ModuleA, desc.szDrvname, sizeof(data.ModuleA)); + + MultiByteToWideChar( CP_ACP, 0, data.DescriptionA, -1, data.DescriptionW, sizeof(data.DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, data.ModuleA, -1, data.ModuleW, sizeof(data.ModuleW)/sizeof(WCHAR) ); + + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + } + + devs = waveInGetNumDevs(); + for (wid = 0; wid < devs; ++wid) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + data.WaveDeviceId = wid; + data.DeviceId = DSOUND_capture_guids[wid]; + lstrcpynA(data.DescriptionA, desc.szDesc, sizeof(data.DescriptionA)); + lstrcpynA(data.ModuleA, desc.szDrvname, sizeof(data.ModuleA)); + + MultiByteToWideChar( CP_ACP, 0, data.DescriptionA, -1, data.DescriptionW, sizeof(data.DescriptionW)/sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, data.ModuleA, -1, data.ModuleW, sizeof(data.ModuleW)/sizeof(WCHAR) ); + + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveInMessage((HWAVEIN)wid, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + } + + return S_OK; + } + } + } else { + FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); + } + + if (pcbReturned) { + *pcbReturned = 0; + FIXME("*pcbReturned=%ld\n", *pcbReturned); + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI DSPROPERTY_EnumerateA( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA) pPropData; + HRESULT err; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { + if (ppd) { + if (ppd->Callback) { + unsigned devs, wod, wid; + DSDRIVERDESC desc; + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data; + + devs = waveOutGetNumDevs(); + for (wod = 0; wod < devs; ++wod) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + DWORD size; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACESIZE,(DWORD_PTR)&size,0)); + if (err == DS_OK) { + WCHAR * nameW = HeapAlloc(GetProcessHeap(),0,size); + if (nameW) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACE,(DWORD_PTR)nameW,size)); + if (err == DS_OK) { + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,size/sizeof(WCHAR)); + if (szInterface) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + data.WaveDeviceId = wod; + data.DeviceId = DSOUND_renderer_guids[wod]; + data.Description = desc.szDesc; + data.Module = desc.szDrvname; + WideCharToMultiByte( CP_ACP, 0, nameW, size/sizeof(WCHAR), szInterface, size/sizeof(WCHAR), NULL, NULL ); + data.Interface = szInterface; + + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + HeapFree(GetProcessHeap(),0,szInterface); + } + } + HeapFree(GetProcessHeap(),0,nameW); + } + } + } + + devs = waveInGetNumDevs(); + for (wid = 0; wid < devs; ++wid) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + DWORD size; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACESIZE,(DWORD_PTR)&size,0)); + if (err == DS_OK) { + WCHAR * nameW = HeapAlloc(GetProcessHeap(),0,size); + if (nameW) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACE,(DWORD_PTR)nameW,size)); + if (err == DS_OK) { + CHAR * szInterface = HeapAlloc(GetProcessHeap(),0,size/sizeof(WCHAR)); + if (szInterface) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + data.WaveDeviceId = wid; + data.DeviceId = DSOUND_capture_guids[wid]; + data.Description = desc.szDesc; + data.Module = desc.szDrvname; + WideCharToMultiByte( CP_ACP, 0, nameW, size/sizeof(WCHAR), szInterface, size/sizeof(WCHAR), NULL, NULL ); + data.Interface = szInterface; + + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveInMessage((HWAVEIN)wid, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + HeapFree(GetProcessHeap(),0,szInterface); + } + } + HeapFree(GetProcessHeap(),0,nameW); + } + } + } + + return S_OK; + } + } + } else { + FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); + } + + if (pcbReturned) { + *pcbReturned = 0; + FIXME("*pcbReturned=%ld\n", *pcbReturned); + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI DSPROPERTY_EnumerateW( + REFGUID guidPropSet, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA ppd = (PDSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA) pPropData; + HRESULT err; + TRACE("(guidPropSet=%s,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + debugstr_guid(guidPropSet),pPropData,cbPropData,pcbReturned); + + if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { + if (ppd) { + if (ppd->Callback) { + unsigned devs, wod, wid; + DSDRIVERDESC desc; + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data; + + devs = waveOutGetNumDevs(); + for (wod = 0; wod < devs; ++wod) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + if (wDescription && wModule) { + DWORD size; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod,DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&size, 0)); + if (err == DS_OK) { + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,size); + if (wInterface) { + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)wInterface, size)); + if (err == DS_OK) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_RENDER; + data.WaveDeviceId = wod; + data.DeviceId = DSOUND_renderer_guids[wod]; + + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + + data.Description = wDescription; + data.Module = wModule; + data.Interface = wInterface; + + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveOutMessage((HWAVEOUT)wod, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveOutMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + } + HeapFree(GetProcessHeap(),0,wInterface); + } + } + HeapFree(GetProcessHeap(),0,wDescription); + HeapFree(GetProcessHeap(),0,wModule); + } + } + + devs = waveInGetNumDevs(); + for (wid = 0; wid < devs; ++wid) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDSOUNDDESC,(DWORD_PTR)&desc,0)); + if (err == DS_OK) { + WCHAR * wDescription = HeapAlloc(GetProcessHeap(),0,0x200); + WCHAR * wModule = HeapAlloc(GetProcessHeap(),0,0x200); + if (wDescription && wModule) { + DWORD size; + err = mmErr(WineWaveInMessage((HWAVEIN)wid,DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&size, 0)); + if (err == DS_OK) { + WCHAR * wInterface = HeapAlloc(GetProcessHeap(),0,size); + if (wInterface) { + err = mmErr(WineWaveInMessage((HWAVEIN)wid, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)wInterface, size)); + if (err == DS_OK) { + PIDSCDRIVER drv; + ZeroMemory(&data, sizeof(data)); + data.DataFlow = DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE; + data.WaveDeviceId = wid; + data.DeviceId = DSOUND_capture_guids[wid]; + + MultiByteToWideChar( CP_ACP, 0, desc.szDesc, -1, wDescription, 0x100 ); + MultiByteToWideChar( CP_ACP, 0, desc.szDrvname, -1, wModule, 0x100 ); + + data.Description = wDescription; + data.Module = wModule; + data.Interface = wInterface; + data.Type = DIRECTSOUNDDEVICE_TYPE_EMULATED; + err = mmErr(WineWaveInMessage((HWAVEIN)wid, DRV_QUERYDSOUNDIFACE, (DWORD_PTR)&drv, 0)); + if (err == DS_OK && drv) + data.Type = DIRECTSOUNDDEVICE_TYPE_VXD; + else + WARN("WineWaveInMessage(DRV_QUERYDSOUNDIFACE) failed\n"); + + TRACE("calling Callback(%p,%p)\n", &data, ppd->Context); + (ppd->Callback)(&data, ppd->Context); + } + } + HeapFree(GetProcessHeap(),0,wInterface); + } + } + HeapFree(GetProcessHeap(),0,wDescription); + HeapFree(GetProcessHeap(),0,wModule); + } + } + + return S_OK; + } + } + } else { + FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); + } + + if (pcbReturned) { + *pcbReturned = 0; + FIXME("*pcbReturned=%ld\n", *pcbReturned); + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI IKsPrivatePropertySetImpl_Get( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + LPVOID pInstanceData, + ULONG cbInstanceData, + LPVOID pPropData, + ULONG cbPropData, + PULONG pcbReturned ) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + TRACE("(iface=%p,guidPropSet=%s,dwPropID=%ld,pInstanceData=%p,cbInstanceData=%ld,pPropData=%p,cbPropData=%ld,pcbReturned=%p)\n", + This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData,pcbReturned); + + if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { + switch (dwPropID) { + case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: + return DSPROPERTY_WaveDeviceMappingA(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: + return DSPROPERTY_Description1(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: + return DSPROPERTY_Enumerate1(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: + return DSPROPERTY_WaveDeviceMappingW(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: + return DSPROPERTY_DescriptionA(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: + return DSPROPERTY_DescriptionW(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: + return DSPROPERTY_EnumerateA(guidPropSet,pPropData,cbPropData,pcbReturned); + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: + return DSPROPERTY_EnumerateW(guidPropSet,pPropData,cbPropData,pcbReturned); + default: + FIXME("unsupported ID: %ld\n",dwPropID); + break; + } + } else { + FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); + } + + if (pcbReturned) { + *pcbReturned = 0; + FIXME("*pcbReturned=%ld\n", *pcbReturned); + } + + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI IKsPrivatePropertySetImpl_Set( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + LPVOID pInstanceData, + ULONG cbInstanceData, + LPVOID pPropData, + ULONG cbPropData ) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + + FIXME("(%p,%s,%ld,%p,%ld,%p,%ld), stub!\n",This,debugstr_guid(guidPropSet),dwPropID,pInstanceData,cbInstanceData,pPropData,cbPropData); + return E_PROP_ID_UNSUPPORTED; +} + +static HRESULT WINAPI IKsPrivatePropertySetImpl_QuerySupport( + LPKSPROPERTYSET iface, + REFGUID guidPropSet, + ULONG dwPropID, + PULONG pTypeSupport ) +{ + IKsPrivatePropertySetImpl *This = (IKsPrivatePropertySetImpl *)iface; + TRACE("(%p,%s,%ld,%p)\n",This,debugstr_guid(guidPropSet),dwPropID,pTypeSupport); + + if ( IsEqualGUID( &DSPROPSETID_DirectSoundDevice, guidPropSet) ) { + switch (dwPropID) { + case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + case DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: + *pTypeSupport = KSPROPERTY_SUPPORT_GET; + return S_OK; + default: + FIXME("unsupported ID: %ld\n",dwPropID); + break; + } + } else { + FIXME("unsupported property: %s\n",debugstr_guid(guidPropSet)); + } + + return E_PROP_ID_UNSUPPORTED; +} + +static const IKsPropertySetVtbl ikspvt = { + IKsPrivatePropertySetImpl_QueryInterface, + IKsPrivatePropertySetImpl_AddRef, + IKsPrivatePropertySetImpl_Release, + IKsPrivatePropertySetImpl_Get, + IKsPrivatePropertySetImpl_Set, + IKsPrivatePropertySetImpl_QuerySupport +}; + +HRESULT WINAPI IKsPrivatePropertySetImpl_Create( + IKsPrivatePropertySetImpl **piks) +{ + IKsPrivatePropertySetImpl *iks; + + iks = HeapAlloc(GetProcessHeap(),0,sizeof(*iks)); + iks->ref = 1; + iks->lpVtbl = &ikspvt; + + *piks = iks; + return S_OK; +} diff --git a/reactos/lib/dsound/sound3d.c b/reactos/lib/dsound/sound3d.c index 958a6c59a61..3505b0664c4 100644 --- a/reactos/lib/dsound/sound3d.c +++ b/reactos/lib/dsound/sound3d.c @@ -1,1132 +1,1114 @@ -/* DirectSound - * - * Copyright 1998 Marcus Meissner - * Copyright 1998 Rob Riggs - * Copyright 2000-2001 TransGaming Technologies, Inc. - * Copyright 2002-2003 Rok Mandeljc - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * Most thread locking is complete. There may be a few race - * conditions still lurking. - * - * Tested with a Soundblaster clone, a Gravis UltraSound Classic, - * and a Turtle Beach Tropez+. - * - * TODO: - * Implement SetCooperativeLevel properly (need to address focus issues) - * Implement DirectSound3DBuffers (stubs in place) - * Use hardware 3D support if available - * Add critical section locking inside Release and AddRef methods - * Handle static buffers - put those in hardware, non-static not in hardware - * Hardware DuplicateSoundBuffer - * Proper volume calculation, and setting volume in HEL primary buffer - * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN - */ - -#include "config.h" -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include -#include -#include /* Insomnia - pow() function */ - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "mmsystem.h" -#include "winreg.h" -#include "winternl.h" -#include "mmddk.h" -#include "wine/windef16.h" -#include "wine/debug.h" -#include "dsound.h" -#include "dsdriver.h" -#include "dsound_private.h" - -/* default intensity level for human ears */ -#define DEFAULT_INTENSITY 0.000000000001f -/* default velocity of sound in the air */ -#define DEFAULT_VELOCITY 340 - -WINE_DEFAULT_DEBUG_CHANNEL(dsound3d); - -/******************************************************************************* - * Auxiliary functions - */ - -/* scalar product (i believe it's called dot product in english) */ -static inline D3DVALUE ScalarProduct (LPD3DVECTOR a, LPD3DVECTOR b) -{ - D3DVALUE c; - c = (a->x*b->x) + (a->y*b->y) + (a->z*b->z); - TRACE("(%f,%f,%f) * (%f,%f,%f) = %f)\n", a->x, a->y, a->z, b->x, b->y, \ - b->z, c); - return c; -} - -/* vector product (i believe it's called cross product in english */ -static inline D3DVECTOR VectorProduct (LPD3DVECTOR a, LPD3DVECTOR b) -{ - D3DVECTOR c; - c.x = (a->y*b->z) - (a->z*b->y); - c.y = (a->z*b->x) - (a->x*b->z); - c.z = (a->x*b->y) - (a->y*b->x); - TRACE("(%f,%f,%f) x (%f,%f,%f) = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y, \ - b->z, c.x, c.y, c.z); - return c; -} - -/* magnitude (length) of vector */ -static inline D3DVALUE VectorMagnitude (LPD3DVECTOR a) -{ - D3DVALUE l; - l = sqrt (ScalarProduct (a, a)); - TRACE("|(%f,%f,%f)| = %f\n", a->x, a->y, a->z, l); - return l; -} - -/* conversion between radians and degrees */ -static inline D3DVALUE RadToDeg (D3DVALUE angle) -{ - D3DVALUE newangle; - newangle = angle * (360/(2*M_PI)); - TRACE("%f rad = %f deg\n", angle, newangle); - return newangle; -} - -/* conversion between degrees and radians */ -static inline D3DVALUE DegToRad (D3DVALUE angle) -{ - D3DVALUE newangle; - newangle = angle * (2*M_PI/360); - TRACE("%f deg = %f rad\n", angle, newangle); - return newangle; -} - -/* angle between vectors - deg version */ -static inline D3DVALUE AngleBetweenVectorsDeg (LPD3DVECTOR a, LPD3DVECTOR b) -{ - D3DVALUE la, lb, product, angle, cos; - /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */ - product = ScalarProduct (a,b); - la = VectorMagnitude (a); - lb = VectorMagnitude (b); - cos = product/(la*lb); - angle = acos(cos); - /* we now have angle in radians */ - angle = RadToDeg(angle); - TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f degrees\n", a->x, a->y, a->z, b->x, - b->y, b->z, angle); - return angle; -} - -/* angle between vectors - rad version */ -static inline D3DVALUE AngleBetweenVectorsRad (LPD3DVECTOR a, LPD3DVECTOR b) -{ - D3DVALUE la, lb, product, angle, cos; - /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */ - product = ScalarProduct (a,b); - la = VectorMagnitude (a); - lb = VectorMagnitude (b); - cos = product/(la*lb); - angle = acos(cos); - TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f radians\n", a->x, a->y, a->z, b->x, - b->y, b->z, angle); - return angle; -} - -/* calculates vector between two points */ -static inline D3DVECTOR VectorBetweenTwoPoints (LPD3DVECTOR a, LPD3DVECTOR b) -{ - D3DVECTOR c; - c.x = b->x - a->x; - c.y = b->y - a->y; - c.z = b->z - a->z; - TRACE("A (%f,%f,%f), B (%f,%f,%f), AB = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y, - b->z, c.x, c.y, c.z); - return c; -} - -/* calculates the length of vector's projection on another vector */ -static inline D3DVALUE ProjectVector (LPD3DVECTOR a, LPD3DVECTOR p) -{ - D3DVALUE prod, result; - prod = ScalarProduct(a, p); - result = prod/VectorMagnitude(p); - TRACE("length projection of (%f,%f,%f) on (%f,%f,%f) = %f\n", a->x, a->y, a->z, p->x, - p->y, p->z, result); - return result; -} - -/******************************************************************************* - * 3D Buffer and Listener mixing - */ - -void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) -{ - /* volume, at which the sound will be played after all calcs. */ - D3DVALUE lVolume = 0; - /* intensity (used for distance related stuff) */ - double flIntensity; - double flTemp; - /* stuff for distance related stuff calc. */ - D3DVECTOR vDistance; - D3DVALUE flDistance = 0; - /* panning related stuff */ - D3DVALUE flAngle; - D3DVECTOR vLeft; - /* doppler shift related stuff */ -#if 0 - D3DVALUE flFreq, flBufferVel, flListenerVel; -#endif - - TRACE("(%p)\n",dsb); - - /* initial buffer volume */ - lVolume = dsb->ds3db_lVolume; - - switch (dsb->ds3db_ds3db.dwMode) - { - case DS3DMODE_DISABLE: - TRACE("3D processing disabled\n"); - /* this one is here only to eliminate annoying warning message */ - DSOUND_RecalcVolPan (&dsb->volpan); - DSOUND_ForceRemix (dsb); - break; - case DS3DMODE_NORMAL: - TRACE("Normal 3D processing mode\n"); - /* we need to calculate distance between buffer and listener*/ - vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->dsound->ds3dl.vPosition); - flDistance = VectorMagnitude (&vDistance); - break; - case DS3DMODE_HEADRELATIVE: - TRACE("Head-relative 3D processing mode\n"); - /* distance between buffer and listener is same as buffer's position */ - flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition); - break; - } - - if (flDistance > dsb->ds3db_ds3db.flMaxDistance) - { - /* some apps don't want you to hear too distant sounds... */ - if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE) - { - dsb->volpan.lVolume = DSBVOLUME_MIN; - DSOUND_RecalcVolPan (&dsb->volpan); - /* i guess mixing here would be a waste of power */ - return; - } - else - flDistance = dsb->ds3db_ds3db.flMaxDistance; - } - - if (flDistance < dsb->ds3db_ds3db.flMinDistance) - flDistance = dsb->ds3db_ds3db.flMinDistance; - - /* the following formula is taken from my physics book. I think it's ok for the *real* world...i hope m$ does it that way */ - lVolume += 10000; /* ms likes working with negative volume...i don't */ - lVolume /= 1000; /* convert hundreths of dB into B */ - /* intensity level (loudness) = log10(Intensity/DefaultIntensity)...therefore */ - flIntensity = pow(10,lVolume)*DEFAULT_INTENSITY; - flTemp = (flDistance/dsb->ds3db_ds3db.flMinDistance)*(flDistance/dsb->ds3db_ds3db.flMinDistance); - flIntensity /= flTemp; - lVolume = log10(flIntensity/DEFAULT_INTENSITY); - lVolume *= 1000; /* convert back to hundreths of dB */ - lVolume -= 10000; /* we need to do it in ms way */ - TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %ld to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume); - - /* conning */ - /* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/ - if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0) - { - TRACE("conning: cones not set\n"); - } - else - { - /* calculate angle */ - flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance); - /* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */ - if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle) - { - /* my test show that for my way of calc., we need only half of angles */ - DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2; - DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2; - /* full volume */ - if (flAngle < dwInsideConeAngle) - flAngle = dwInsideConeAngle; - /* min (app defined) volume */ - if (flAngle > dwOutsideConeAngle) - flAngle = dwOutsideConeAngle; - /* this probably isn't the right thing, but it's ok for the time being */ - lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle; - } - TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %ld deg; OutsideConeAngle(/2) = %ld deg; ConeOutsideVolume = %ld => adjusting volume to %f\n", - flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume); - } - dsb->volpan.lVolume = lVolume; - - /* panning */ - if (dsb->dsound->ds3dl.vPosition.x == dsb->ds3db_ds3db.vPosition.x && - dsb->dsound->ds3dl.vPosition.y == dsb->ds3db_ds3db.vPosition.y && - dsb->dsound->ds3dl.vPosition.z == dsb->ds3db_ds3db.vPosition.z) { - dsb->volpan.lPan = 0; - flAngle = 0.0; - } - else - { - vDistance = VectorBetweenTwoPoints(&dsb->dsound->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition); - vLeft = VectorProduct(&dsb->dsound->ds3dl.vOrientFront, &dsb->dsound->ds3dl.vOrientTop); - flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance); - /* for now, we'll use "linear formula" (which is probably incorrect); if someone has it in book, correct it */ - dsb->volpan.lPan = 10000*2*flAngle/M_PI - 10000; - } - TRACE("panning: Angle = %f rad, lPan = %ld\n", flAngle, dsb->volpan.lPan); - - /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */ -#if 0 - /* doppler shift*/ - if ((VectorMagnitude(&ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->dsound->ds3dl.vVelocity) == 0)) - { - TRACE("doppler: Buffer and Listener don't have velocities\n"); - } - else - { - /* calculate length of ds3db.vVelocity component which causes Doppler Effect - NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE - if buffer moves AWAY from listener, it's velocity component is POSITIVE */ - flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance); - /* calculate length of ds3dl.vVelocity component which causes Doppler Effect - NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE - if listener moves AWAY from buffer, it's velocity component is NEGATIVE */ - flListenerVel = ProjectVector(&dsb->dsound->ds3dl.vVelocity, &vDistance); - /* formula taken from Gianicoli D.: Physics, 4th edition: */ - /* FIXME: replace dsb->freq with appropriate frequency ! */ - flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel)); - TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel, \ - dsb->freq, flFreq); - /* FIXME: replace following line with correct frequency setting ! */ - dsb->freq = flFreq; - } -#endif - - /* time for remix */ - DSOUND_RecalcVolPan(&dsb->volpan); -} - -static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb) -{ - TRACE("(%p)\n",dsb); - - DSOUND_Calc3DBuffer(dsb); - DSOUND_ForceRemix(dsb); -} - -static void WINAPI DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl) -{ - int i; - TRACE("(%p)\n",ds3dl); - for (i = 0; i < ds3dl->dsound->nrofbuffers; i++) - { - /* some buffers don't have 3d buffer (Ultima IX seems to - crash without the following line) */ - if (ds3dl->dsound->buffers[i]->ds3db == NULL) - continue; - if (ds3dl->dsound->buffers[i]->ds3db_need_recalc) - { - DSOUND_Mix3DBuffer(ds3dl->dsound->buffers[i]); - } - } -} - -/******************************************************************************* - * IDirectSound3DBuffer - */ - -/* IUnknown methods */ -static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface( - LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj); -} - -static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - ULONG ulReturn; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - if (!ulReturn) { - This->dsb->ds3db = NULL; - IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb); - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - - return ulReturn; -} - -/* IDirectSound3DBuffer methods */ -static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters( - LPDIRECTSOUND3DBUFFER iface, - LPDS3DBUFFER lpDs3dBuffer) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("(%p,%p)\n",This,lpDs3dBuffer); - - if (lpDs3dBuffer == NULL) { - WARN("invalid parameter: lpDs3dBuffer == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpDs3dBuffer->dwSize < sizeof(*lpDs3dBuffer)) { - WARN("invalid parameter: lpDs3dBuffer->dwSize = %ld < %d\n",lpDs3dBuffer->dwSize, sizeof(*lpDs3dBuffer)); - return DSERR_INVALIDPARAM; - } - - TRACE("returning: all parameters\n"); - *lpDs3dBuffer = This->dsb->ds3db_ds3db; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles( - LPDIRECTSOUND3DBUFFER iface, - LPDWORD lpdwInsideConeAngle, - LPDWORD lpdwOutsideConeAngle) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Inside Cone Angle = %ld degrees; Outside Cone Angle = %ld degrees\n", - This->dsb->ds3db_ds3db.dwInsideConeAngle, This->dsb->ds3db_ds3db.dwOutsideConeAngle); - *lpdwInsideConeAngle = This->dsb->ds3db_ds3db.dwInsideConeAngle; - *lpdwOutsideConeAngle = This->dsb->ds3db_ds3db.dwOutsideConeAngle; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation( - LPDIRECTSOUND3DBUFFER iface, - LPD3DVECTOR lpvConeOrientation) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Cone Orientation vector = (%f,%f,%f)\n", - This->dsb->ds3db_ds3db.vConeOrientation.x, - This->dsb->ds3db_ds3db.vConeOrientation.y, - This->dsb->ds3db_ds3db.vConeOrientation.z); - *lpvConeOrientation = This->dsb->ds3db_ds3db.vConeOrientation; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume( - LPDIRECTSOUND3DBUFFER iface, - LPLONG lplConeOutsideVolume) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Cone Outside Volume = %ld\n", This->dsb->ds3db_ds3db.lConeOutsideVolume); - *lplConeOutsideVolume = This->dsb->ds3db_ds3db.lConeOutsideVolume; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance( - LPDIRECTSOUND3DBUFFER iface, - LPD3DVALUE lpfMaxDistance) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Max Distance = %f\n", This->dsb->ds3db_ds3db.flMaxDistance); - *lpfMaxDistance = This->dsb->ds3db_ds3db.flMaxDistance; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance( - LPDIRECTSOUND3DBUFFER iface, - LPD3DVALUE lpfMinDistance) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Min Distance = %f\n", This->dsb->ds3db_ds3db.flMinDistance); - *lpfMinDistance = This->dsb->ds3db_ds3db.flMinDistance; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode( - LPDIRECTSOUND3DBUFFER iface, - LPDWORD lpdwMode) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Mode = %ld\n", This->dsb->ds3db_ds3db.dwMode); - *lpdwMode = This->dsb->ds3db_ds3db.dwMode; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition( - LPDIRECTSOUND3DBUFFER iface, - LPD3DVECTOR lpvPosition) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Position vector = (%f,%f,%f)\n", - This->dsb->ds3db_ds3db.vPosition.x, - This->dsb->ds3db_ds3db.vPosition.y, - This->dsb->ds3db_ds3db.vPosition.z); - *lpvPosition = This->dsb->ds3db_ds3db.vPosition; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity( - LPDIRECTSOUND3DBUFFER iface, - LPD3DVECTOR lpvVelocity) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("returning: Velocity vector = (%f,%f,%f)\n", - This->dsb->ds3db_ds3db.vVelocity.x, - This->dsb->ds3db_ds3db.vVelocity.y, - This->dsb->ds3db_ds3db.vVelocity.z); - *lpvVelocity = This->dsb->ds3db_ds3db.vVelocity; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters( - LPDIRECTSOUND3DBUFFER iface, - LPCDS3DBUFFER lpcDs3dBuffer, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - DWORD status = DSERR_INVALIDPARAM; - TRACE("(%p,%p,%lx)\n",iface,lpcDs3dBuffer,dwApply); - - if (lpcDs3dBuffer == NULL) { - WARN("invalid parameter: lpcDs3dBuffer == NULL\n"); - return status; - } - - if (lpcDs3dBuffer->dwSize != sizeof(DS3DBUFFER)) { - WARN("invalid parameter: lpcDs3dBuffer->dwSize = %ld != %d\n", - lpcDs3dBuffer->dwSize, sizeof(DS3DBUFFER)); - return status; - } - - TRACE("setting: all parameters; dwApply = %ld\n", dwApply); - This->dsb->ds3db_ds3db = *lpcDs3dBuffer; - - if (dwApply == DS3D_IMMEDIATE) - { - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - status = DS_OK; - - return status; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles( - LPDIRECTSOUND3DBUFFER iface, - DWORD dwInsideConeAngle, - DWORD dwOutsideConeAngle, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: Inside Cone Angle = %ld; Outside Cone Angle = %ld; dwApply = %ld\n", - dwInsideConeAngle, dwOutsideConeAngle, dwApply); - This->dsb->ds3db_ds3db.dwInsideConeAngle = dwInsideConeAngle; - This->dsb->ds3db_ds3db.dwOutsideConeAngle = dwOutsideConeAngle; - if (dwApply == DS3D_IMMEDIATE) - { - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation( - LPDIRECTSOUND3DBUFFER iface, - D3DVALUE x, D3DVALUE y, D3DVALUE z, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: Cone Orientation vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); - This->dsb->ds3db_ds3db.vConeOrientation.x = x; - This->dsb->ds3db_ds3db.vConeOrientation.y = y; - This->dsb->ds3db_ds3db.vConeOrientation.z = z; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume( - LPDIRECTSOUND3DBUFFER iface, - LONG lConeOutsideVolume, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: ConeOutsideVolume = %ld; dwApply = %ld\n", lConeOutsideVolume, dwApply); - This->dsb->ds3db_ds3db.lConeOutsideVolume = lConeOutsideVolume; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance( - LPDIRECTSOUND3DBUFFER iface, - D3DVALUE fMaxDistance, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: MaxDistance = %f; dwApply = %ld\n", fMaxDistance, dwApply); - This->dsb->ds3db_ds3db.flMaxDistance = fMaxDistance; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance( - LPDIRECTSOUND3DBUFFER iface, - D3DVALUE fMinDistance, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: MinDistance = %f; dwApply = %ld\n", fMinDistance, dwApply); - This->dsb->ds3db_ds3db.flMinDistance = fMinDistance; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode( - LPDIRECTSOUND3DBUFFER iface, - DWORD dwMode, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: Mode = %ld; dwApply = %ld\n", dwMode, dwApply); - This->dsb->ds3db_ds3db.dwMode = dwMode; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition( - LPDIRECTSOUND3DBUFFER iface, - D3DVALUE x, D3DVALUE y, D3DVALUE z, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); - This->dsb->ds3db_ds3db.vPosition.x = x; - This->dsb->ds3db_ds3db.vPosition.y = y; - This->dsb->ds3db_ds3db.vPosition.z = z; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity( - LPDIRECTSOUND3DBUFFER iface, - D3DVALUE x, D3DVALUE y, D3DVALUE z, - DWORD dwApply) -{ - IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; - TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); - This->dsb->ds3db_ds3db.vVelocity.x = x; - This->dsb->ds3db_ds3db.vVelocity.y = y; - This->dsb->ds3db_ds3db.vVelocity.z = z; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsb->ds3db_need_recalc = FALSE; - DSOUND_Mix3DBuffer(This->dsb); - } - This->dsb->ds3db_need_recalc = TRUE; - return DS_OK; -} - -static IDirectSound3DBufferVtbl ds3dbvt = -{ - /* IUnknown methods */ - IDirectSound3DBufferImpl_QueryInterface, - IDirectSound3DBufferImpl_AddRef, - IDirectSound3DBufferImpl_Release, - /* IDirectSound3DBuffer methods */ - IDirectSound3DBufferImpl_GetAllParameters, - IDirectSound3DBufferImpl_GetConeAngles, - IDirectSound3DBufferImpl_GetConeOrientation, - IDirectSound3DBufferImpl_GetConeOutsideVolume, - IDirectSound3DBufferImpl_GetMaxDistance, - IDirectSound3DBufferImpl_GetMinDistance, - IDirectSound3DBufferImpl_GetMode, - IDirectSound3DBufferImpl_GetPosition, - IDirectSound3DBufferImpl_GetVelocity, - IDirectSound3DBufferImpl_SetAllParameters, - IDirectSound3DBufferImpl_SetConeAngles, - IDirectSound3DBufferImpl_SetConeOrientation, - IDirectSound3DBufferImpl_SetConeOutsideVolume, - IDirectSound3DBufferImpl_SetMaxDistance, - IDirectSound3DBufferImpl_SetMinDistance, - IDirectSound3DBufferImpl_SetMode, - IDirectSound3DBufferImpl_SetPosition, - IDirectSound3DBufferImpl_SetVelocity, -}; - -HRESULT WINAPI IDirectSound3DBufferImpl_Create( - IDirectSoundBufferImpl *dsb, - IDirectSound3DBufferImpl **pds3db) -{ - IDirectSound3DBufferImpl *ds3db; - TRACE("(%p,%p)\n",dsb,pds3db); - - ds3db = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*ds3db)); - - if (ds3db == NULL) { - WARN("out of memory\n"); - *pds3db = 0; - return DSERR_OUTOFMEMORY; - } - - ds3db->ref = 0; - ds3db->dsb = dsb; - ds3db->lpVtbl = &ds3dbvt; - - ds3db->dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); - ds3db->dsb->ds3db_ds3db.vPosition.x = 0.0; - ds3db->dsb->ds3db_ds3db.vPosition.y = 0.0; - ds3db->dsb->ds3db_ds3db.vPosition.z = 0.0; - ds3db->dsb->ds3db_ds3db.vVelocity.x = 0.0; - ds3db->dsb->ds3db_ds3db.vVelocity.y = 0.0; - ds3db->dsb->ds3db_ds3db.vVelocity.z = 0.0; - ds3db->dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE; - ds3db->dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE; - ds3db->dsb->ds3db_ds3db.vConeOrientation.x = 0.0; - ds3db->dsb->ds3db_ds3db.vConeOrientation.y = 0.0; - ds3db->dsb->ds3db_ds3db.vConeOrientation.z = 0.0; - ds3db->dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; - ds3db->dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE; - ds3db->dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; - ds3db->dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL; - - ds3db->dsb->ds3db_need_recalc = TRUE; - - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb); - - *pds3db = ds3db; - return S_OK; -} - -HRESULT WINAPI IDirectSound3DBufferImpl_Destroy( - IDirectSound3DBufferImpl *pds3db) -{ - TRACE("(%p)\n",pds3db); - - while (IDirectSound3DBufferImpl_Release((LPDIRECTSOUND3DBUFFER)pds3db) > 0); - - return S_OK; -} - -/******************************************************************************* - * IDirectSound3DListener - */ - -/* IUnknown methods */ -static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface( - LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)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_IDirectSound3DListener ) ) { - IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This); - *ppobj = This; - return S_OK; - } - - if ( IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) { - if (!This->dsound->primary) - PrimaryBufferImpl_Create(This->dsound, &(This->dsound->primary), &(This->dsound->dsbd)); - if (This->dsound->primary) { - *ppobj = This->dsound->primary; - IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppobj); - return S_OK; - } - } - - FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); - return E_NOINTERFACE; -} - -static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - ULONG ulReturn; - - TRACE("(%p) ref was %ld, thread is %04lx\n",This, This->ref, GetCurrentThreadId()); - ulReturn = InterlockedDecrement(&(This->ref)); - - /* Free all resources */ - if( ulReturn == 0 ) { - This->dsound->listener = 0; - HeapFree(GetProcessHeap(),0,This); - TRACE("(%p) released\n",This); - } - - return ulReturn; -} - -/* IDirectSound3DListener methods */ -static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter( - LPDIRECTSOUND3DLISTENER iface, - LPDS3DLISTENER lpDS3DL) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("(%p,%p)\n",This,lpDS3DL); - - if (lpDS3DL == NULL) { - WARN("invalid parameter: lpDS3DL == NULL\n"); - return DSERR_INVALIDPARAM; - } - - if (lpDS3DL->dwSize < sizeof(*lpDS3DL)) { - WARN("invalid parameter: lpDS3DL->dwSize = %ld < %d\n",lpDS3DL->dwSize, sizeof(*lpDS3DL)); - return DSERR_INVALIDPARAM; - } - - TRACE("returning: all parameters\n"); - *lpDS3DL = This->dsound->ds3dl; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVALUE lpfDistanceFactor) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: Distance Factor = %f\n", This->dsound->ds3dl.flDistanceFactor); - *lpfDistanceFactor = This->dsound->ds3dl.flDistanceFactor; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVALUE lpfDopplerFactor) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: Doppler Factor = %f\n", This->dsound->ds3dl.flDopplerFactor); - *lpfDopplerFactor = This->dsound->ds3dl.flDopplerFactor; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVECTOR lpvOrientFront, - LPD3DVECTOR lpvOrientTop) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: OrientFront vector = (%f,%f,%f); OrientTop vector = (%f,%f,%f)\n", This->dsound->ds3dl.vOrientFront.x, \ - This->dsound->ds3dl.vOrientFront.y, This->dsound->ds3dl.vOrientFront.z, This->dsound->ds3dl.vOrientTop.x, This->dsound->ds3dl.vOrientTop.y, \ - This->dsound->ds3dl.vOrientTop.z); - *lpvOrientFront = This->dsound->ds3dl.vOrientFront; - *lpvOrientTop = This->dsound->ds3dl.vOrientTop; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVECTOR lpvPosition) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: Position vector = (%f,%f,%f)\n", This->dsound->ds3dl.vPosition.x, This->dsound->ds3dl.vPosition.y, This->dsound->ds3dl.vPosition.z); - *lpvPosition = This->dsound->ds3dl.vPosition; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVALUE lpfRolloffFactor) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: RolloffFactor = %f\n", This->dsound->ds3dl.flRolloffFactor); - *lpfRolloffFactor = This->dsound->ds3dl.flRolloffFactor; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity( - LPDIRECTSOUND3DLISTENER iface, - LPD3DVECTOR lpvVelocity) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->dsound->ds3dl.vVelocity.x, This->dsound->ds3dl.vVelocity.y, This->dsound->ds3dl.vVelocity.z); - *lpvVelocity = This->dsound->ds3dl.vVelocity; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters( - LPDIRECTSOUND3DLISTENER iface, - LPCDS3DLISTENER lpcDS3DL, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: all parameters; dwApply = %ld\n", dwApply); - This->dsound->ds3dl = *lpcDS3DL; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE fDistanceFactor, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Distance Factor = %f; dwApply = %ld\n", fDistanceFactor, dwApply); - This->dsound->ds3dl.flDistanceFactor = fDistanceFactor; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE fDopplerFactor, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Doppler Factor = %f; dwApply = %ld\n", fDopplerFactor, dwApply); - This->dsound->ds3dl.flDopplerFactor = fDopplerFactor; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, - D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Front vector = (%f,%f,%f); Top vector = (%f,%f,%f); dwApply = %ld\n", \ - xFront, yFront, zFront, xTop, yTop, zTop, dwApply); - This->dsound->ds3dl.vOrientFront.x = xFront; - This->dsound->ds3dl.vOrientFront.y = yFront; - This->dsound->ds3dl.vOrientFront.z = zFront; - This->dsound->ds3dl.vOrientTop.x = xTop; - This->dsound->ds3dl.vOrientTop.y = yTop; - This->dsound->ds3dl.vOrientTop.z = zTop; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE x, D3DVALUE y, D3DVALUE z, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); - This->dsound->ds3dl.vPosition.x = x; - This->dsound->ds3dl.vPosition.y = y; - This->dsound->ds3dl.vPosition.z = z; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE fRolloffFactor, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Rolloff Factor = %f; dwApply = %ld\n", fRolloffFactor, dwApply); - This->dsound->ds3dl.flRolloffFactor = fRolloffFactor; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity( - LPDIRECTSOUND3DLISTENER iface, - D3DVALUE x, D3DVALUE y, D3DVALUE z, - DWORD dwApply) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); - This->dsound->ds3dl.vVelocity.x = x; - This->dsound->ds3dl.vVelocity.y = y; - This->dsound->ds3dl.vVelocity.z = z; - if (dwApply == DS3D_IMMEDIATE) - { - This->dsound->ds3dl_need_recalc = FALSE; - DSOUND_ChangeListener(This); - } - This->dsound->ds3dl_need_recalc = TRUE; - return DS_OK; -} - -static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings( - LPDIRECTSOUND3DLISTENER iface) -{ - IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; - TRACE("\n"); - DSOUND_ChangeListener(This); - return DS_OK; -} - -static IDirectSound3DListenerVtbl ds3dlvt = -{ - /* IUnknown methods */ - IDirectSound3DListenerImpl_QueryInterface, - IDirectSound3DListenerImpl_AddRef, - IDirectSound3DListenerImpl_Release, - /* IDirectSound3DListener methods */ - IDirectSound3DListenerImpl_GetAllParameter, - IDirectSound3DListenerImpl_GetDistanceFactor, - IDirectSound3DListenerImpl_GetDopplerFactor, - IDirectSound3DListenerImpl_GetOrientation, - IDirectSound3DListenerImpl_GetPosition, - IDirectSound3DListenerImpl_GetRolloffFactor, - IDirectSound3DListenerImpl_GetVelocity, - IDirectSound3DListenerImpl_SetAllParameters, - IDirectSound3DListenerImpl_SetDistanceFactor, - IDirectSound3DListenerImpl_SetDopplerFactor, - IDirectSound3DListenerImpl_SetOrientation, - IDirectSound3DListenerImpl_SetPosition, - IDirectSound3DListenerImpl_SetRolloffFactor, - IDirectSound3DListenerImpl_SetVelocity, - IDirectSound3DListenerImpl_CommitDeferredSettings, -}; - -HRESULT WINAPI IDirectSound3DListenerImpl_Create( - PrimaryBufferImpl *This, - IDirectSound3DListenerImpl **pdsl) -{ - IDirectSound3DListenerImpl *dsl; - TRACE("(%p,%p)\n",This,pdsl); - - dsl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsl)); - - if (dsl == NULL) { - WARN("out of memory\n"); - *pdsl = 0; - return DSERR_OUTOFMEMORY; - } - - dsl->ref = 0; - dsl->lpVtbl = &ds3dlvt; - - dsl->dsound = This->dsound; - - dsl->dsound->ds3dl.dwSize = sizeof(DS3DLISTENER); - dsl->dsound->ds3dl.vPosition.x = 0.0; - dsl->dsound->ds3dl.vPosition.y = 0.0; - dsl->dsound->ds3dl.vPosition.z = 0.0; - dsl->dsound->ds3dl.vVelocity.x = 0.0; - dsl->dsound->ds3dl.vVelocity.y = 0.0; - dsl->dsound->ds3dl.vVelocity.z = 0.0; - dsl->dsound->ds3dl.vOrientFront.x = 0.0; - dsl->dsound->ds3dl.vOrientFront.y = 0.0; - dsl->dsound->ds3dl.vOrientFront.z = 1.0; - dsl->dsound->ds3dl.vOrientTop.x = 0.0; - dsl->dsound->ds3dl.vOrientTop.y = 1.0; - dsl->dsound->ds3dl.vOrientTop.z = 0.0; - dsl->dsound->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; - dsl->dsound->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; - dsl->dsound->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; - - dsl->dsound->ds3dl_need_recalc = TRUE; - - *pdsl = dsl; - return S_OK; -} +/* DirectSound + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Rob Riggs + * Copyright 2000-2001 TransGaming Technologies, Inc. + * Copyright 2002-2003 Rok Mandeljc + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * Most thread locking is complete. There may be a few race + * conditions still lurking. + * + * Tested with a Soundblaster clone, a Gravis UltraSound Classic, + * and a Turtle Beach Tropez+. + * + * TODO: + * Implement SetCooperativeLevel properly (need to address focus issues) + * Implement DirectSound3DBuffers (stubs in place) + * Use hardware 3D support if available + * Add critical section locking inside Release and AddRef methods + * Handle static buffers - put those in hardware, non-static not in hardware + * Hardware DuplicateSoundBuffer + * Proper volume calculation, and setting volume in HEL primary buffer + * Optimize WINMM and negotiate fragment size, decrease DS_HEL_MARGIN + */ + +#include +#include /* Insomnia - pow() function */ + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "winternl.h" +#include "mmddk.h" +#include "wine/debug.h" +#include "dsound.h" +#include "dsdriver.h" +#include "dsound_private.h" + +/* default intensity level for human ears */ +#define DEFAULT_INTENSITY 0.000000000001f +/* default velocity of sound in the air */ +#define DEFAULT_VELOCITY 340 + +WINE_DEFAULT_DEBUG_CHANNEL(dsound3d); + +/******************************************************************************* + * Auxiliary functions + */ + +/* scalar product (i believe it's called dot product in english) */ +static inline D3DVALUE ScalarProduct (LPD3DVECTOR a, LPD3DVECTOR b) +{ + D3DVALUE c; + c = (a->x*b->x) + (a->y*b->y) + (a->z*b->z); + TRACE("(%f,%f,%f) * (%f,%f,%f) = %f)\n", a->x, a->y, a->z, b->x, b->y, \ + b->z, c); + return c; +} + +/* vector product (i believe it's called cross product in english */ +static inline D3DVECTOR VectorProduct (LPD3DVECTOR a, LPD3DVECTOR b) +{ + D3DVECTOR c; + c.x = (a->y*b->z) - (a->z*b->y); + c.y = (a->z*b->x) - (a->x*b->z); + c.z = (a->x*b->y) - (a->y*b->x); + TRACE("(%f,%f,%f) x (%f,%f,%f) = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y, \ + b->z, c.x, c.y, c.z); + return c; +} + +/* magnitude (length) of vector */ +static inline D3DVALUE VectorMagnitude (LPD3DVECTOR a) +{ + D3DVALUE l; + l = sqrt (ScalarProduct (a, a)); + TRACE("|(%f,%f,%f)| = %f\n", a->x, a->y, a->z, l); + return l; +} + +/* conversion between radians and degrees */ +static inline D3DVALUE RadToDeg (D3DVALUE angle) +{ + D3DVALUE newangle; + newangle = angle * (360/(2*M_PI)); + TRACE("%f rad = %f deg\n", angle, newangle); + return newangle; +} + +/* conversion between degrees and radians */ +static inline D3DVALUE DegToRad (D3DVALUE angle) +{ + D3DVALUE newangle; + newangle = angle * (2*M_PI/360); + TRACE("%f deg = %f rad\n", angle, newangle); + return newangle; +} + +/* angle between vectors - deg version */ +static inline D3DVALUE AngleBetweenVectorsDeg (LPD3DVECTOR a, LPD3DVECTOR b) +{ + D3DVALUE la, lb, product, angle, cos; + /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */ + product = ScalarProduct (a,b); + la = VectorMagnitude (a); + lb = VectorMagnitude (b); + cos = product/(la*lb); + angle = acos(cos); + /* we now have angle in radians */ + angle = RadToDeg(angle); + TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f degrees\n", a->x, a->y, a->z, b->x, + b->y, b->z, angle); + return angle; +} + +/* angle between vectors - rad version */ +static inline D3DVALUE AngleBetweenVectorsRad (LPD3DVECTOR a, LPD3DVECTOR b) +{ + D3DVALUE la, lb, product, angle, cos; + /* definition of scalar product: a*b = |a|*|b|*cos...therefore: */ + product = ScalarProduct (a,b); + la = VectorMagnitude (a); + lb = VectorMagnitude (b); + cos = product/(la*lb); + angle = acos(cos); + TRACE("angle between (%f,%f,%f) and (%f,%f,%f) = %f radians\n", a->x, a->y, a->z, b->x, + b->y, b->z, angle); + return angle; +} + +/* calculates vector between two points */ +static inline D3DVECTOR VectorBetweenTwoPoints (LPD3DVECTOR a, LPD3DVECTOR b) +{ + D3DVECTOR c; + c.x = b->x - a->x; + c.y = b->y - a->y; + c.z = b->z - a->z; + TRACE("A (%f,%f,%f), B (%f,%f,%f), AB = (%f,%f,%f)\n", a->x, a->y, a->z, b->x, b->y, + b->z, c.x, c.y, c.z); + return c; +} + +/* calculates the length of vector's projection on another vector */ +static inline D3DVALUE ProjectVector (LPD3DVECTOR a, LPD3DVECTOR p) +{ + D3DVALUE prod, result; + prod = ScalarProduct(a, p); + result = prod/VectorMagnitude(p); + TRACE("length projection of (%f,%f,%f) on (%f,%f,%f) = %f\n", a->x, a->y, a->z, p->x, + p->y, p->z, result); + return result; +} + +/******************************************************************************* + * 3D Buffer and Listener mixing + */ + +void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) +{ + /* volume, at which the sound will be played after all calcs. */ + D3DVALUE lVolume = 0; + /* intensity (used for distance related stuff) */ + double flIntensity; + double flTemp; + /* stuff for distance related stuff calc. */ + D3DVECTOR vDistance; + D3DVALUE flDistance = 0; + /* panning related stuff */ + D3DVALUE flAngle; + D3DVECTOR vLeft; + /* doppler shift related stuff */ +#if 0 + D3DVALUE flFreq, flBufferVel, flListenerVel; +#endif + + TRACE("(%p)\n",dsb); + + /* initial buffer volume */ + lVolume = dsb->ds3db_lVolume; + + switch (dsb->ds3db_ds3db.dwMode) + { + case DS3DMODE_DISABLE: + TRACE("3D processing disabled\n"); + /* this one is here only to eliminate annoying warning message */ + DSOUND_RecalcVolPan (&dsb->volpan); + DSOUND_ForceRemix (dsb); + break; + case DS3DMODE_NORMAL: + TRACE("Normal 3D processing mode\n"); + /* we need to calculate distance between buffer and listener*/ + vDistance = VectorBetweenTwoPoints(&dsb->ds3db_ds3db.vPosition, &dsb->dsound->device->ds3dl.vPosition); + flDistance = VectorMagnitude (&vDistance); + break; + case DS3DMODE_HEADRELATIVE: + TRACE("Head-relative 3D processing mode\n"); + /* distance between buffer and listener is same as buffer's position */ + flDistance = VectorMagnitude (&dsb->ds3db_ds3db.vPosition); + break; + } + + if (flDistance > dsb->ds3db_ds3db.flMaxDistance) + { + /* some apps don't want you to hear too distant sounds... */ + if (dsb->dsbd.dwFlags & DSBCAPS_MUTE3DATMAXDISTANCE) + { + dsb->volpan.lVolume = DSBVOLUME_MIN; + DSOUND_RecalcVolPan (&dsb->volpan); + /* i guess mixing here would be a waste of power */ + return; + } + else + flDistance = dsb->ds3db_ds3db.flMaxDistance; + } + + if (flDistance < dsb->ds3db_ds3db.flMinDistance) + flDistance = dsb->ds3db_ds3db.flMinDistance; + + /* the following formula is taken from my physics book. I think it's ok for the *real* world...i hope m$ does it that way */ + lVolume += 10000; /* ms likes working with negative volume...i don't */ + lVolume /= 1000; /* convert hundreths of dB into B */ + /* intensity level (loudness) = log10(Intensity/DefaultIntensity)...therefore */ + flIntensity = pow(10,lVolume)*DEFAULT_INTENSITY; + flTemp = (flDistance/dsb->ds3db_ds3db.flMinDistance)*(flDistance/dsb->ds3db_ds3db.flMinDistance); + flIntensity /= flTemp; + lVolume = log10(flIntensity/DEFAULT_INTENSITY); + lVolume *= 1000; /* convert back to hundreths of dB */ + lVolume -= 10000; /* we need to do it in ms way */ + TRACE("dist. att: Distance = %f, MinDistance = %f => adjusting volume %ld to %f\n", flDistance, dsb->ds3db_ds3db.flMinDistance, dsb->ds3db_lVolume, lVolume); + + /* conning */ + /* sometimes it happens that vConeOrientation vector = (0,0,0); in this case angle is "nan" and it's useless*/ + if (dsb->ds3db_ds3db.vConeOrientation.x == 0 && dsb->ds3db_ds3db.vConeOrientation.y == 0 && dsb->ds3db_ds3db.vConeOrientation.z == 0) + { + TRACE("conning: cones not set\n"); + } + else + { + /* calculate angle */ + flAngle = AngleBetweenVectorsDeg(&dsb->ds3db_ds3db.vConeOrientation, &vDistance); + /* if by any chance it happens that OutsideConeAngle = InsideConeAngle (that means that conning has no effect) */ + if (dsb->ds3db_ds3db.dwInsideConeAngle != dsb->ds3db_ds3db.dwOutsideConeAngle) + { + /* my test show that for my way of calc., we need only half of angles */ + DWORD dwInsideConeAngle = dsb->ds3db_ds3db.dwInsideConeAngle/2; + DWORD dwOutsideConeAngle = dsb->ds3db_ds3db.dwOutsideConeAngle/2; + /* full volume */ + if (flAngle < dwInsideConeAngle) + flAngle = dwInsideConeAngle; + /* min (app defined) volume */ + if (flAngle > dwOutsideConeAngle) + flAngle = dwOutsideConeAngle; + /* this probably isn't the right thing, but it's ok for the time being */ + lVolume += ((dsb->ds3db_ds3db.lConeOutsideVolume)/((dwOutsideConeAngle) - (dwInsideConeAngle))) * flAngle; + } + TRACE("conning: Angle = %f deg; InsideConeAngle(/2) = %ld deg; OutsideConeAngle(/2) = %ld deg; ConeOutsideVolume = %ld => adjusting volume to %f\n", + flAngle, dsb->ds3db_ds3db.dwInsideConeAngle/2, dsb->ds3db_ds3db.dwOutsideConeAngle/2, dsb->ds3db_ds3db.lConeOutsideVolume, lVolume); + } + dsb->volpan.lVolume = lVolume; + + /* panning */ + if (dsb->dsound->device->ds3dl.vPosition.x == dsb->ds3db_ds3db.vPosition.x && + dsb->dsound->device->ds3dl.vPosition.y == dsb->ds3db_ds3db.vPosition.y && + dsb->dsound->device->ds3dl.vPosition.z == dsb->ds3db_ds3db.vPosition.z) { + dsb->volpan.lPan = 0; + flAngle = 0.0; + } + else + { + vDistance = VectorBetweenTwoPoints(&dsb->dsound->device->ds3dl.vPosition, &dsb->ds3db_ds3db.vPosition); + vLeft = VectorProduct(&dsb->dsound->device->ds3dl.vOrientFront, &dsb->dsound->device->ds3dl.vOrientTop); + flAngle = AngleBetweenVectorsRad(&vLeft, &vDistance); + /* for now, we'll use "linear formula" (which is probably incorrect); if someone has it in book, correct it */ + dsb->volpan.lPan = 10000*2*flAngle/M_PI - 10000; + } + TRACE("panning: Angle = %f rad, lPan = %ld\n", flAngle, dsb->volpan.lPan); + + /* FIXME: Doppler Effect disabled since i have no idea which frequency to change and how to do it */ +#if 0 + /* doppler shift*/ + if ((VectorMagnitude(&ds3db.vVelocity) == 0) && (VectorMagnitude(&dsb->dsound->device->ds3dl.vVelocity) == 0)) + { + TRACE("doppler: Buffer and Listener don't have velocities\n"); + } + else + { + /* calculate length of ds3db.vVelocity component which causes Doppler Effect + NOTE: if buffer moves TOWARDS the listener, it's velocity component is NEGATIVE + if buffer moves AWAY from listener, it's velocity component is POSITIVE */ + flBufferVel = ProjectVector(&dsb->ds3db_ds3db.vVelocity, &vDistance); + /* calculate length of ds3dl.vVelocity component which causes Doppler Effect + NOTE: if listener moves TOWARDS the buffer, it's velocity component is POSITIVE + if listener moves AWAY from buffer, it's velocity component is NEGATIVE */ + flListenerVel = ProjectVector(&dsb->dsound->device->ds3dl.vVelocity, &vDistance); + /* formula taken from Gianicoli D.: Physics, 4th edition: */ + /* FIXME: replace dsb->freq with appropriate frequency ! */ + flFreq = dsb->freq * ((DEFAULT_VELOCITY + flListenerVel)/(DEFAULT_VELOCITY + flBufferVel)); + TRACE("doppler: Buffer velocity (component) = %lf, Listener velocity (component) = %lf => Doppler shift: %ld Hz -> %lf Hz\n", flBufferVel, flListenerVel, \ + dsb->freq, flFreq); + /* FIXME: replace following line with correct frequency setting ! */ + dsb->freq = flFreq; + } +#endif + + /* time for remix */ + DSOUND_RecalcVolPan(&dsb->volpan); +} + +static void DSOUND_Mix3DBuffer(IDirectSoundBufferImpl *dsb) +{ + TRACE("(%p)\n",dsb); + + DSOUND_Calc3DBuffer(dsb); + DSOUND_ForceRemix(dsb); +} + +static void WINAPI DSOUND_ChangeListener(IDirectSound3DListenerImpl *ds3dl) +{ + int i; + TRACE("(%p)\n",ds3dl); + for (i = 0; i < ds3dl->dsound->device->nrofbuffers; i++) + { + /* some buffers don't have 3d buffer (Ultima IX seems to + crash without the following line) */ + if (ds3dl->dsound->device->buffers[i]->ds3db == NULL) + continue; + if (ds3dl->dsound->device->buffers[i]->ds3db_need_recalc) + { + DSOUND_Mix3DBuffer(ds3dl->dsound->device->buffers[i]); + } + } +} + +/******************************************************************************* + * IDirectSound3DBuffer + */ + +/* IUnknown methods */ +static HRESULT WINAPI IDirectSound3DBufferImpl_QueryInterface( + LPDIRECTSOUND3DBUFFER iface, REFIID riid, LPVOID *ppobj) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + return IDirectSoundBuffer_QueryInterface((LPDIRECTSOUNDBUFFER8)This->dsb, riid, ppobj); +} + +static ULONG WINAPI IDirectSound3DBufferImpl_AddRef(LPDIRECTSOUND3DBUFFER iface) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectSound3DBufferImpl_Release(LPDIRECTSOUND3DBUFFER iface) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + This->dsb->ds3db = NULL; + IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER8)This->dsb); + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +/* IDirectSound3DBuffer methods */ +static HRESULT WINAPI IDirectSound3DBufferImpl_GetAllParameters( + LPDIRECTSOUND3DBUFFER iface, + LPDS3DBUFFER lpDs3dBuffer) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("(%p,%p)\n",This,lpDs3dBuffer); + + if (lpDs3dBuffer == NULL) { + WARN("invalid parameter: lpDs3dBuffer == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpDs3dBuffer->dwSize < sizeof(*lpDs3dBuffer)) { + WARN("invalid parameter: lpDs3dBuffer->dwSize = %ld < %d\n",lpDs3dBuffer->dwSize, sizeof(*lpDs3dBuffer)); + return DSERR_INVALIDPARAM; + } + + TRACE("returning: all parameters\n"); + *lpDs3dBuffer = This->dsb->ds3db_ds3db; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeAngles( + LPDIRECTSOUND3DBUFFER iface, + LPDWORD lpdwInsideConeAngle, + LPDWORD lpdwOutsideConeAngle) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Inside Cone Angle = %ld degrees; Outside Cone Angle = %ld degrees\n", + This->dsb->ds3db_ds3db.dwInsideConeAngle, This->dsb->ds3db_ds3db.dwOutsideConeAngle); + *lpdwInsideConeAngle = This->dsb->ds3db_ds3db.dwInsideConeAngle; + *lpdwOutsideConeAngle = This->dsb->ds3db_ds3db.dwOutsideConeAngle; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOrientation( + LPDIRECTSOUND3DBUFFER iface, + LPD3DVECTOR lpvConeOrientation) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Cone Orientation vector = (%f,%f,%f)\n", + This->dsb->ds3db_ds3db.vConeOrientation.x, + This->dsb->ds3db_ds3db.vConeOrientation.y, + This->dsb->ds3db_ds3db.vConeOrientation.z); + *lpvConeOrientation = This->dsb->ds3db_ds3db.vConeOrientation; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetConeOutsideVolume( + LPDIRECTSOUND3DBUFFER iface, + LPLONG lplConeOutsideVolume) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Cone Outside Volume = %ld\n", This->dsb->ds3db_ds3db.lConeOutsideVolume); + *lplConeOutsideVolume = This->dsb->ds3db_ds3db.lConeOutsideVolume; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetMaxDistance( + LPDIRECTSOUND3DBUFFER iface, + LPD3DVALUE lpfMaxDistance) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Max Distance = %f\n", This->dsb->ds3db_ds3db.flMaxDistance); + *lpfMaxDistance = This->dsb->ds3db_ds3db.flMaxDistance; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetMinDistance( + LPDIRECTSOUND3DBUFFER iface, + LPD3DVALUE lpfMinDistance) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Min Distance = %f\n", This->dsb->ds3db_ds3db.flMinDistance); + *lpfMinDistance = This->dsb->ds3db_ds3db.flMinDistance; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetMode( + LPDIRECTSOUND3DBUFFER iface, + LPDWORD lpdwMode) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Mode = %ld\n", This->dsb->ds3db_ds3db.dwMode); + *lpdwMode = This->dsb->ds3db_ds3db.dwMode; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetPosition( + LPDIRECTSOUND3DBUFFER iface, + LPD3DVECTOR lpvPosition) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Position vector = (%f,%f,%f)\n", + This->dsb->ds3db_ds3db.vPosition.x, + This->dsb->ds3db_ds3db.vPosition.y, + This->dsb->ds3db_ds3db.vPosition.z); + *lpvPosition = This->dsb->ds3db_ds3db.vPosition; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_GetVelocity( + LPDIRECTSOUND3DBUFFER iface, + LPD3DVECTOR lpvVelocity) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("returning: Velocity vector = (%f,%f,%f)\n", + This->dsb->ds3db_ds3db.vVelocity.x, + This->dsb->ds3db_ds3db.vVelocity.y, + This->dsb->ds3db_ds3db.vVelocity.z); + *lpvVelocity = This->dsb->ds3db_ds3db.vVelocity; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetAllParameters( + LPDIRECTSOUND3DBUFFER iface, + LPCDS3DBUFFER lpcDs3dBuffer, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + DWORD status = DSERR_INVALIDPARAM; + TRACE("(%p,%p,%lx)\n",iface,lpcDs3dBuffer,dwApply); + + if (lpcDs3dBuffer == NULL) { + WARN("invalid parameter: lpcDs3dBuffer == NULL\n"); + return status; + } + + if (lpcDs3dBuffer->dwSize != sizeof(DS3DBUFFER)) { + WARN("invalid parameter: lpcDs3dBuffer->dwSize = %ld != %d\n", + lpcDs3dBuffer->dwSize, sizeof(DS3DBUFFER)); + return status; + } + + TRACE("setting: all parameters; dwApply = %ld\n", dwApply); + This->dsb->ds3db_ds3db = *lpcDs3dBuffer; + + if (dwApply == DS3D_IMMEDIATE) + { + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + status = DS_OK; + + return status; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeAngles( + LPDIRECTSOUND3DBUFFER iface, + DWORD dwInsideConeAngle, + DWORD dwOutsideConeAngle, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: Inside Cone Angle = %ld; Outside Cone Angle = %ld; dwApply = %ld\n", + dwInsideConeAngle, dwOutsideConeAngle, dwApply); + This->dsb->ds3db_ds3db.dwInsideConeAngle = dwInsideConeAngle; + This->dsb->ds3db_ds3db.dwOutsideConeAngle = dwOutsideConeAngle; + if (dwApply == DS3D_IMMEDIATE) + { + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOrientation( + LPDIRECTSOUND3DBUFFER iface, + D3DVALUE x, D3DVALUE y, D3DVALUE z, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: Cone Orientation vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); + This->dsb->ds3db_ds3db.vConeOrientation.x = x; + This->dsb->ds3db_ds3db.vConeOrientation.y = y; + This->dsb->ds3db_ds3db.vConeOrientation.z = z; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetConeOutsideVolume( + LPDIRECTSOUND3DBUFFER iface, + LONG lConeOutsideVolume, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: ConeOutsideVolume = %ld; dwApply = %ld\n", lConeOutsideVolume, dwApply); + This->dsb->ds3db_ds3db.lConeOutsideVolume = lConeOutsideVolume; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetMaxDistance( + LPDIRECTSOUND3DBUFFER iface, + D3DVALUE fMaxDistance, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: MaxDistance = %f; dwApply = %ld\n", fMaxDistance, dwApply); + This->dsb->ds3db_ds3db.flMaxDistance = fMaxDistance; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetMinDistance( + LPDIRECTSOUND3DBUFFER iface, + D3DVALUE fMinDistance, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: MinDistance = %f; dwApply = %ld\n", fMinDistance, dwApply); + This->dsb->ds3db_ds3db.flMinDistance = fMinDistance; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetMode( + LPDIRECTSOUND3DBUFFER iface, + DWORD dwMode, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: Mode = %ld; dwApply = %ld\n", dwMode, dwApply); + This->dsb->ds3db_ds3db.dwMode = dwMode; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetPosition( + LPDIRECTSOUND3DBUFFER iface, + D3DVALUE x, D3DVALUE y, D3DVALUE z, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); + This->dsb->ds3db_ds3db.vPosition.x = x; + This->dsb->ds3db_ds3db.vPosition.y = y; + This->dsb->ds3db_ds3db.vPosition.z = z; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DBufferImpl_SetVelocity( + LPDIRECTSOUND3DBUFFER iface, + D3DVALUE x, D3DVALUE y, D3DVALUE z, + DWORD dwApply) +{ + IDirectSound3DBufferImpl *This = (IDirectSound3DBufferImpl *)iface; + TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); + This->dsb->ds3db_ds3db.vVelocity.x = x; + This->dsb->ds3db_ds3db.vVelocity.y = y; + This->dsb->ds3db_ds3db.vVelocity.z = z; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsb->ds3db_need_recalc = FALSE; + DSOUND_Mix3DBuffer(This->dsb); + } + This->dsb->ds3db_need_recalc = TRUE; + return DS_OK; +} + +static const IDirectSound3DBufferVtbl ds3dbvt = +{ + /* IUnknown methods */ + IDirectSound3DBufferImpl_QueryInterface, + IDirectSound3DBufferImpl_AddRef, + IDirectSound3DBufferImpl_Release, + /* IDirectSound3DBuffer methods */ + IDirectSound3DBufferImpl_GetAllParameters, + IDirectSound3DBufferImpl_GetConeAngles, + IDirectSound3DBufferImpl_GetConeOrientation, + IDirectSound3DBufferImpl_GetConeOutsideVolume, + IDirectSound3DBufferImpl_GetMaxDistance, + IDirectSound3DBufferImpl_GetMinDistance, + IDirectSound3DBufferImpl_GetMode, + IDirectSound3DBufferImpl_GetPosition, + IDirectSound3DBufferImpl_GetVelocity, + IDirectSound3DBufferImpl_SetAllParameters, + IDirectSound3DBufferImpl_SetConeAngles, + IDirectSound3DBufferImpl_SetConeOrientation, + IDirectSound3DBufferImpl_SetConeOutsideVolume, + IDirectSound3DBufferImpl_SetMaxDistance, + IDirectSound3DBufferImpl_SetMinDistance, + IDirectSound3DBufferImpl_SetMode, + IDirectSound3DBufferImpl_SetPosition, + IDirectSound3DBufferImpl_SetVelocity, +}; + +HRESULT WINAPI IDirectSound3DBufferImpl_Create( + IDirectSoundBufferImpl *dsb, + IDirectSound3DBufferImpl **pds3db) +{ + IDirectSound3DBufferImpl *ds3db; + TRACE("(%p,%p)\n",dsb,pds3db); + + ds3db = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*ds3db)); + + if (ds3db == NULL) { + WARN("out of memory\n"); + *pds3db = 0; + return DSERR_OUTOFMEMORY; + } + + ds3db->ref = 0; + ds3db->dsb = dsb; + ds3db->lpVtbl = &ds3dbvt; + + ds3db->dsb->ds3db_ds3db.dwSize = sizeof(DS3DBUFFER); + ds3db->dsb->ds3db_ds3db.vPosition.x = 0.0; + ds3db->dsb->ds3db_ds3db.vPosition.y = 0.0; + ds3db->dsb->ds3db_ds3db.vPosition.z = 0.0; + ds3db->dsb->ds3db_ds3db.vVelocity.x = 0.0; + ds3db->dsb->ds3db_ds3db.vVelocity.y = 0.0; + ds3db->dsb->ds3db_ds3db.vVelocity.z = 0.0; + ds3db->dsb->ds3db_ds3db.dwInsideConeAngle = DS3D_DEFAULTCONEANGLE; + ds3db->dsb->ds3db_ds3db.dwOutsideConeAngle = DS3D_DEFAULTCONEANGLE; + ds3db->dsb->ds3db_ds3db.vConeOrientation.x = 0.0; + ds3db->dsb->ds3db_ds3db.vConeOrientation.y = 0.0; + ds3db->dsb->ds3db_ds3db.vConeOrientation.z = 0.0; + ds3db->dsb->ds3db_ds3db.lConeOutsideVolume = DS3D_DEFAULTCONEOUTSIDEVOLUME; + ds3db->dsb->ds3db_ds3db.flMinDistance = DS3D_DEFAULTMINDISTANCE; + ds3db->dsb->ds3db_ds3db.flMaxDistance = DS3D_DEFAULTMAXDISTANCE; + ds3db->dsb->ds3db_ds3db.dwMode = DS3DMODE_NORMAL; + + ds3db->dsb->ds3db_need_recalc = TRUE; + + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER8)dsb); + + *pds3db = ds3db; + return S_OK; +} + +HRESULT WINAPI IDirectSound3DBufferImpl_Destroy( + IDirectSound3DBufferImpl *pds3db) +{ + TRACE("(%p)\n",pds3db); + + while (IDirectSound3DBufferImpl_Release((LPDIRECTSOUND3DBUFFER)pds3db) > 0); + + return S_OK; +} + +/******************************************************************************* + * IDirectSound3DListener + */ + +/* IUnknown methods */ +static HRESULT WINAPI IDirectSound3DListenerImpl_QueryInterface( + LPDIRECTSOUND3DLISTENER iface, REFIID riid, LPVOID *ppobj) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)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_IDirectSound3DListener ) ) { + IDirectSound3DListener_AddRef((LPDIRECTSOUND3DLISTENER)This); + *ppobj = This; + return S_OK; + } + + if ( IsEqualGUID(riid, &IID_IDirectSoundBuffer) ) { + if (!This->dsound->device->primary) + PrimaryBufferImpl_Create(This->dsound, &(This->dsound->device->primary), &(This->dsound->device->dsbd)); + if (This->dsound->device->primary) { + *ppobj = This->dsound->device->primary; + IDirectSoundBuffer_AddRef((LPDIRECTSOUNDBUFFER)*ppobj); + return S_OK; + } + } + + FIXME( "Unknown IID %s\n", debugstr_guid( riid ) ); + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirectSound3DListenerImpl_AddRef(LPDIRECTSOUND3DLISTENER iface) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + ULONG ref = InterlockedIncrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectSound3DListenerImpl_Release(LPDIRECTSOUND3DLISTENER iface) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + TRACE("(%p) ref was %ld\n", This, ref + 1); + + if (!ref) { + This->dsound->device->listener = 0; + HeapFree(GetProcessHeap(), 0, This); + TRACE("(%p) released\n", This); + } + return ref; +} + +/* IDirectSound3DListener methods */ +static HRESULT WINAPI IDirectSound3DListenerImpl_GetAllParameter( + LPDIRECTSOUND3DLISTENER iface, + LPDS3DLISTENER lpDS3DL) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("(%p,%p)\n",This,lpDS3DL); + + if (lpDS3DL == NULL) { + WARN("invalid parameter: lpDS3DL == NULL\n"); + return DSERR_INVALIDPARAM; + } + + if (lpDS3DL->dwSize < sizeof(*lpDS3DL)) { + WARN("invalid parameter: lpDS3DL->dwSize = %ld < %d\n",lpDS3DL->dwSize, sizeof(*lpDS3DL)); + return DSERR_INVALIDPARAM; + } + + TRACE("returning: all parameters\n"); + *lpDS3DL = This->dsound->device->ds3dl; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetDistanceFactor( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVALUE lpfDistanceFactor) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: Distance Factor = %f\n", This->dsound->device->ds3dl.flDistanceFactor); + *lpfDistanceFactor = This->dsound->device->ds3dl.flDistanceFactor; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetDopplerFactor( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVALUE lpfDopplerFactor) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: Doppler Factor = %f\n", This->dsound->device->ds3dl.flDopplerFactor); + *lpfDopplerFactor = This->dsound->device->ds3dl.flDopplerFactor; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetOrientation( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVECTOR lpvOrientFront, + LPD3DVECTOR lpvOrientTop) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: OrientFront vector = (%f,%f,%f); OrientTop vector = (%f,%f,%f)\n", This->dsound->device->ds3dl.vOrientFront.x, \ + This->dsound->device->ds3dl.vOrientFront.y, This->dsound->device->ds3dl.vOrientFront.z, This->dsound->device->ds3dl.vOrientTop.x, This->dsound->device->ds3dl.vOrientTop.y, \ + This->dsound->device->ds3dl.vOrientTop.z); + *lpvOrientFront = This->dsound->device->ds3dl.vOrientFront; + *lpvOrientTop = This->dsound->device->ds3dl.vOrientTop; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetPosition( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVECTOR lpvPosition) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: Position vector = (%f,%f,%f)\n", This->dsound->device->ds3dl.vPosition.x, This->dsound->device->ds3dl.vPosition.y, This->dsound->device->ds3dl.vPosition.z); + *lpvPosition = This->dsound->device->ds3dl.vPosition; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetRolloffFactor( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVALUE lpfRolloffFactor) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: RolloffFactor = %f\n", This->dsound->device->ds3dl.flRolloffFactor); + *lpfRolloffFactor = This->dsound->device->ds3dl.flRolloffFactor; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_GetVelocity( + LPDIRECTSOUND3DLISTENER iface, + LPD3DVECTOR lpvVelocity) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("returning: Velocity vector = (%f,%f,%f)\n", This->dsound->device->ds3dl.vVelocity.x, This->dsound->device->ds3dl.vVelocity.y, This->dsound->device->ds3dl.vVelocity.z); + *lpvVelocity = This->dsound->device->ds3dl.vVelocity; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetAllParameters( + LPDIRECTSOUND3DLISTENER iface, + LPCDS3DLISTENER lpcDS3DL, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: all parameters; dwApply = %ld\n", dwApply); + This->dsound->device->ds3dl = *lpcDS3DL; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetDistanceFactor( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE fDistanceFactor, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Distance Factor = %f; dwApply = %ld\n", fDistanceFactor, dwApply); + This->dsound->device->ds3dl.flDistanceFactor = fDistanceFactor; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetDopplerFactor( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE fDopplerFactor, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Doppler Factor = %f; dwApply = %ld\n", fDopplerFactor, dwApply); + This->dsound->device->ds3dl.flDopplerFactor = fDopplerFactor; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetOrientation( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE xFront, D3DVALUE yFront, D3DVALUE zFront, + D3DVALUE xTop, D3DVALUE yTop, D3DVALUE zTop, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Front vector = (%f,%f,%f); Top vector = (%f,%f,%f); dwApply = %ld\n", \ + xFront, yFront, zFront, xTop, yTop, zTop, dwApply); + This->dsound->device->ds3dl.vOrientFront.x = xFront; + This->dsound->device->ds3dl.vOrientFront.y = yFront; + This->dsound->device->ds3dl.vOrientFront.z = zFront; + This->dsound->device->ds3dl.vOrientTop.x = xTop; + This->dsound->device->ds3dl.vOrientTop.y = yTop; + This->dsound->device->ds3dl.vOrientTop.z = zTop; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetPosition( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE x, D3DVALUE y, D3DVALUE z, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Position vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); + This->dsound->device->ds3dl.vPosition.x = x; + This->dsound->device->ds3dl.vPosition.y = y; + This->dsound->device->ds3dl.vPosition.z = z; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetRolloffFactor( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE fRolloffFactor, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Rolloff Factor = %f; dwApply = %ld\n", fRolloffFactor, dwApply); + This->dsound->device->ds3dl.flRolloffFactor = fRolloffFactor; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_SetVelocity( + LPDIRECTSOUND3DLISTENER iface, + D3DVALUE x, D3DVALUE y, D3DVALUE z, + DWORD dwApply) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("setting: Velocity vector = (%f,%f,%f); dwApply = %ld\n", x, y, z, dwApply); + This->dsound->device->ds3dl.vVelocity.x = x; + This->dsound->device->ds3dl.vVelocity.y = y; + This->dsound->device->ds3dl.vVelocity.z = z; + if (dwApply == DS3D_IMMEDIATE) + { + This->dsound->device->ds3dl_need_recalc = FALSE; + DSOUND_ChangeListener(This); + } + This->dsound->device->ds3dl_need_recalc = TRUE; + return DS_OK; +} + +static HRESULT WINAPI IDirectSound3DListenerImpl_CommitDeferredSettings( + LPDIRECTSOUND3DLISTENER iface) +{ + IDirectSound3DListenerImpl *This = (IDirectSound3DListenerImpl *)iface; + TRACE("\n"); + DSOUND_ChangeListener(This); + return DS_OK; +} + +static const IDirectSound3DListenerVtbl ds3dlvt = +{ + /* IUnknown methods */ + IDirectSound3DListenerImpl_QueryInterface, + IDirectSound3DListenerImpl_AddRef, + IDirectSound3DListenerImpl_Release, + /* IDirectSound3DListener methods */ + IDirectSound3DListenerImpl_GetAllParameter, + IDirectSound3DListenerImpl_GetDistanceFactor, + IDirectSound3DListenerImpl_GetDopplerFactor, + IDirectSound3DListenerImpl_GetOrientation, + IDirectSound3DListenerImpl_GetPosition, + IDirectSound3DListenerImpl_GetRolloffFactor, + IDirectSound3DListenerImpl_GetVelocity, + IDirectSound3DListenerImpl_SetAllParameters, + IDirectSound3DListenerImpl_SetDistanceFactor, + IDirectSound3DListenerImpl_SetDopplerFactor, + IDirectSound3DListenerImpl_SetOrientation, + IDirectSound3DListenerImpl_SetPosition, + IDirectSound3DListenerImpl_SetRolloffFactor, + IDirectSound3DListenerImpl_SetVelocity, + IDirectSound3DListenerImpl_CommitDeferredSettings, +}; + +HRESULT WINAPI IDirectSound3DListenerImpl_Create( + PrimaryBufferImpl *This, + IDirectSound3DListenerImpl **pdsl) +{ + IDirectSound3DListenerImpl *dsl; + TRACE("(%p,%p)\n",This,pdsl); + + dsl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*dsl)); + + if (dsl == NULL) { + WARN("out of memory\n"); + *pdsl = 0; + return DSERR_OUTOFMEMORY; + } + + dsl->ref = 0; + dsl->lpVtbl = &ds3dlvt; + + dsl->dsound = This->dsound; + + dsl->dsound->device->ds3dl.dwSize = sizeof(DS3DLISTENER); + dsl->dsound->device->ds3dl.vPosition.x = 0.0; + dsl->dsound->device->ds3dl.vPosition.y = 0.0; + dsl->dsound->device->ds3dl.vPosition.z = 0.0; + dsl->dsound->device->ds3dl.vVelocity.x = 0.0; + dsl->dsound->device->ds3dl.vVelocity.y = 0.0; + dsl->dsound->device->ds3dl.vVelocity.z = 0.0; + dsl->dsound->device->ds3dl.vOrientFront.x = 0.0; + dsl->dsound->device->ds3dl.vOrientFront.y = 0.0; + dsl->dsound->device->ds3dl.vOrientFront.z = 1.0; + dsl->dsound->device->ds3dl.vOrientTop.x = 0.0; + dsl->dsound->device->ds3dl.vOrientTop.y = 1.0; + dsl->dsound->device->ds3dl.vOrientTop.z = 0.0; + dsl->dsound->device->ds3dl.flDistanceFactor = DS3D_DEFAULTDISTANCEFACTOR; + dsl->dsound->device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR; + dsl->dsound->device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; + + dsl->dsound->device->ds3dl_need_recalc = TRUE; + + *pdsl = dsl; + return S_OK; +} diff --git a/reactos/lib/dsound/tests/Makefile.in b/reactos/lib/dsound/tests/Makefile.in index 6f597764b4d..506ca752ab0 100644 --- a/reactos/lib/dsound/tests/Makefile.in +++ b/reactos/lib/dsound/tests/Makefile.in @@ -1,19 +1,19 @@ -TOPSRCDIR = @top_srcdir@ -TOPOBJDIR = ../../.. -SRCDIR = @srcdir@ -VPATH = @srcdir@ -TESTDLL = dsound.dll -IMPORTS = dsound ole32 user32 kernel32 -EXTRALIBS = -ldxguid -luuid -ldxerr8 - -CTESTS = \ - capture.c \ - ds3d.c \ - ds3d8.c \ - dsound.c \ - dsound8.c \ - propset.c - -@MAKE_TEST_RULES@ - -### Dependencies: +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +TESTDLL = dsound.dll +IMPORTS = dsound ole32 version user32 kernel32 +EXTRALIBS = -ldxguid -luuid -ldxerr8 + +CTESTS = \ + capture.c \ + ds3d.c \ + ds3d8.c \ + dsound.c \ + dsound8.c \ + propset.c + +@MAKE_TEST_RULES@ + +### Dependencies: diff --git a/reactos/lib/dsound/tests/capture.c b/reactos/lib/dsound/tests/capture.c index 37d4ebcd72c..d2cb51cc87b 100644 --- a/reactos/lib/dsound/tests/capture.c +++ b/reactos/lib/dsound/tests/capture.c @@ -1,530 +1,723 @@ -/* - * Unit tests for capture functions - * - * Copyright (c) 2002 Francois Gouget - * Copyright (c) 2003 Robert Reif - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSSTRUCT -#define NONAMELESSUNION -#include - -#include -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "mmreg.h" -#include "dxerr8.h" - -#include "dsound_test.h" - -#define NOTIFICATIONS 5 - -static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; -static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; - -static const char * get_format_str(WORD format) -{ - static char msg[32]; -#define WAVE_FORMAT(f) case f: return #f - switch (format) { - WAVE_FORMAT(WAVE_FORMAT_PCM); - WAVE_FORMAT(WAVE_FORMAT_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD); - WAVE_FORMAT(WAVE_FORMAT_ALAW); - WAVE_FORMAT(WAVE_FORMAT_MULAW); - WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_DIGISTD); - WAVE_FORMAT(WAVE_FORMAT_DIGIFIX); - WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_SONARC); - WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH); - WAVE_FORMAT(WAVE_FORMAT_ECHOSC1); - WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36); - WAVE_FORMAT(WAVE_FORMAT_APTX); - WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10); - WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2); - WAVE_FORMAT(WAVE_FORMAT_GSM610); - WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME); - WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC); - WAVE_FORMAT(WAVE_FORMAT_DIGIREAL); - WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM); - WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10); - WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM); - WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_MPEG); - WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3); - WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM); - WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8); - WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10); - WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND); - WAVE_FORMAT(WAVE_FORMAT_OLIGSM); - WAVE_FORMAT(WAVE_FORMAT_OLIADPCM); - WAVE_FORMAT(WAVE_FORMAT_OLICELP); - WAVE_FORMAT(WAVE_FORMAT_OLISBC); - WAVE_FORMAT(WAVE_FORMAT_OLIOPR); - WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT); - WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE); - } -#undef WAVE_FORMAT - sprintf(msg, "Unknown(0x%04x)", format); - return msg; -} - -static char * format_string(WAVEFORMATEX* wfx) -{ - static char str[64]; - - sprintf(str, "%5ldx%2dx%d %s", - wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels, - get_format_str(wfx->wFormatTag)); - - return str; -} - -typedef struct { - char* wave; - DWORD wave_len; - - LPDIRECTSOUNDCAPTUREBUFFER dscbo; - LPWAVEFORMATEX wfx; - DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS]; - HANDLE event[NOTIFICATIONS]; - LPDIRECTSOUNDNOTIFY notify; - - DWORD buffer_size; - DWORD read; - DWORD offset; - DWORD size; - - DWORD last_pos; -} capture_state_t; - -static int capture_buffer_service(capture_state_t* state) -{ - HRESULT rc; - LPVOID ptr1,ptr2; - DWORD len1,len2; - DWORD capture_pos,read_pos; - - rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos, - &read_pos); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return 0; - - rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return 0; - - rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return 0; - - state->offset = (state->offset + state->size) % state->buffer_size; - - return 1; -} - -static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, - LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record) -{ - HRESULT rc; - DSCBCAPS dscbcaps; - WAVEFORMATEX wfx; - DWORD size,status; - capture_state_t state; - int i, ref; - - /* Private dsound.dll: Error: Invalid caps pointer */ - rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " - "have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - /* Private dsound.dll: Error: Invalid caps pointer */ - dscbcaps.dwSize=0; - rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " - "have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - dscbcaps.dwSize=sizeof(dscbcaps); - rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Caps: size = %ld flags=0x%08lx buffer size=%ld\n", - dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes); - } - - /* Query the format size. Note that it may not match sizeof(wfx) */ - /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must - * be non-NULL */ - rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetFormat() should " - "have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - size=0; - rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size); - ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should " - "have returned the needed size: rc=%s, size=%ld\n", - DXGetErrorString8(rc),size); - - rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Format: tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* Private dsound.dll: Error: Invalid status pointer */ - rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetStatus() should " - "have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Status=0x%04lx\n",status); - } - - ZeroMemory(&state, sizeof(state)); - state.dscbo=dscbo; - state.wfx=&wfx; - state.buffer_size = dscbcaps.dwBufferBytes; - for (i = 0; i < NOTIFICATIONS; i++) - state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); - state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS; - - rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify, - (void **)&(state.notify)); - ok((rc==DS_OK)&&(state.notify!=NULL), - "IDirectSoundCaptureBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - for (i = 0; i < NOTIFICATIONS; i++) { - state.posnotify[i].dwOffset = (i * state.size) + state.size - 1; - state.posnotify[i].hEventNotify = state.event[i]; - } - - rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS, - state.posnotify); - ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - ref=IDirectSoundNotify_Release(state.notify); - ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have " - "0\n",ref); - if (ref!=0) - return; - - if (record) { - rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING), - "GetStatus: bad status: %lx\n",status); - if (rc!=DS_OK) - return; - - /* wait for the notifications */ - for (i = 0; i < (NOTIFICATIONS * 2); i++) { - rc=MsgWaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE, - 3000,QS_ALLEVENTS); - ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)), - "MsgWaitForMultipleObjects failed: 0x%lx\n",rc); - if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) { - ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED), - "Wrong notification: should be %d, got %ld\n", - i%NOTIFICATIONS,rc-WAIT_OBJECT_0); - } - if (!capture_buffer_service(&state)) - break; - } - - rc=IDirectSoundCaptureBuffer_Stop(dscbo); - ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - } -} - -static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, - LPCSTR lpcstrModule, LPVOID lpContext) -{ - HRESULT rc; - LPDIRECTSOUNDCAPTURE dsco=NULL; - LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL; - DSCBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - DSCCAPS dsccaps; - DWORD f; - int ref; - - /* Private dsound.dll: Error: Invalid interface buffer */ - trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); - rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL); - ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - ref=IDirectSoundCapture_Release(dsco); - ok(ref==0,"IDirectSoundCapture_Release() has %d references, should " - "have 0\n",ref); - } - - rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL); - ok((rc==DS_OK)||(rc==DSERR_NODRIVER),"DirectSoundCaptureCreate() failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) { - if (rc==DSERR_NODRIVER) - trace(" No Driver\n"); - goto EXIT; - } - - /* Private dsound.dll: Error: Invalid caps buffer */ - rc=IDirectSoundCapture_GetCaps(dsco,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* Private dsound.dll: Error: Invalid caps buffer */ - dsccaps.dwSize=0; - rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - dsccaps.dwSize=sizeof(dsccaps); - rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); - ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Caps: size=%ld flags=0x%08lx formats=%05lx channels=%ld\n", - dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats, - dsccaps.dwChannels); - } - - /* Private dsound.dll: Error: Invalid size */ - /* Private dsound.dll: Error: Invalid capture buffer description */ - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=0; - bufdesc.dwFlags=0; - bufdesc.dwBufferBytes=0; - bufdesc.dwReserved=0; - bufdesc.lpwfxFormat=NULL; - rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - ref=IDirectSoundCaptureBuffer_Release(dscbo); - ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " - "should have 0\n",ref); - } - - /* Private dsound.dll: Error: Invalid buffer size */ - /* Private dsound.dll: Error: Invalid capture buffer description */ - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=0; - bufdesc.dwBufferBytes=0; - bufdesc.dwReserved=0; - bufdesc.lpwfxFormat=NULL; - rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " - "should have returned DSERR_INVALIDPARAM, returned %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - ref=IDirectSoundCaptureBuffer_Release(dscbo); - ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " - "should have 0\n",ref); - } - - /* Private dsound.dll: Error: Invalid buffer size */ - /* Private dsound.dll: Error: Invalid capture buffer description */ - ZeroMemory(&bufdesc, sizeof(bufdesc)); - ZeroMemory(&wfx, sizeof(wfx)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=0; - bufdesc.dwBufferBytes=0; - bufdesc.dwReserved=0; - bufdesc.lpwfxFormat=&wfx; - rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " - "should have returned DSERR_INVALIDPARAM, returned :%s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - ref=IDirectSoundCaptureBuffer_Release(dscbo); - ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " - "should have 0\n",ref); - } - - /* Private dsound.dll: Error: Invalid buffer size */ - /* Private dsound.dll: Error: Invalid capture buffer description */ - init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=0; - bufdesc.dwBufferBytes=0; - bufdesc.dwReserved=0; - bufdesc.lpwfxFormat=&wfx; - rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - ref=IDirectSoundCaptureBuffer_Release(dscbo); - ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " - "should have 0\n",ref); - } - - for (f=0;f + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "mmreg.h" +#include "dxerr8.h" +#include "dsconf.h" + +#include "dsound_test.h" + +#define NOTIFICATIONS 5 + +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID,LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA,LPVOID)=NULL; + +static const char * get_format_str(WORD format) +{ + static char msg[32]; +#define WAVE_FORMAT(f) case f: return #f + switch (format) { + WAVE_FORMAT(WAVE_FORMAT_PCM); + WAVE_FORMAT(WAVE_FORMAT_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IBM_CVSD); + WAVE_FORMAT(WAVE_FORMAT_ALAW); + WAVE_FORMAT(WAVE_FORMAT_MULAW); + WAVE_FORMAT(WAVE_FORMAT_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_IMA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MEDIASPACE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SIERRA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_G723_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_DIGISTD); + WAVE_FORMAT(WAVE_FORMAT_DIGIFIX); + WAVE_FORMAT(WAVE_FORMAT_DIALOGIC_OKI_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_YAMAHA_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_SONARC); + WAVE_FORMAT(WAVE_FORMAT_DSPGROUP_TRUESPEECH); + WAVE_FORMAT(WAVE_FORMAT_ECHOSC1); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF36); + WAVE_FORMAT(WAVE_FORMAT_APTX); + WAVE_FORMAT(WAVE_FORMAT_AUDIOFILE_AF10); + WAVE_FORMAT(WAVE_FORMAT_DOLBY_AC2); + WAVE_FORMAT(WAVE_FORMAT_GSM610); + WAVE_FORMAT(WAVE_FORMAT_ANTEX_ADPCME); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_VQLPC); + WAVE_FORMAT(WAVE_FORMAT_DIGIREAL); + WAVE_FORMAT(WAVE_FORMAT_DIGIADPCM); + WAVE_FORMAT(WAVE_FORMAT_CONTROL_RES_CR10); + WAVE_FORMAT(WAVE_FORMAT_NMS_VBXADPCM); + WAVE_FORMAT(WAVE_FORMAT_G721_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_MPEG); + WAVE_FORMAT(WAVE_FORMAT_MPEGLAYER3); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_ADPCM); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH8); + WAVE_FORMAT(WAVE_FORMAT_CREATIVE_FASTSPEECH10); + WAVE_FORMAT(WAVE_FORMAT_FM_TOWNS_SND); + WAVE_FORMAT(WAVE_FORMAT_OLIGSM); + WAVE_FORMAT(WAVE_FORMAT_OLIADPCM); + WAVE_FORMAT(WAVE_FORMAT_OLICELP); + WAVE_FORMAT(WAVE_FORMAT_OLISBC); + WAVE_FORMAT(WAVE_FORMAT_OLIOPR); + WAVE_FORMAT(WAVE_FORMAT_DEVELOPMENT); + WAVE_FORMAT(WAVE_FORMAT_EXTENSIBLE); + } +#undef WAVE_FORMAT + sprintf(msg, "Unknown(0x%04x)", format); + return msg; +} + +static char * format_string(WAVEFORMATEX* wfx) +{ + static char str[64]; + + sprintf(str, "%5ldx%2dx%d %s", + wfx->nSamplesPerSec, wfx->wBitsPerSample, wfx->nChannels, + get_format_str(wfx->wFormatTag)); + + return str; +} + +static void IDirectSoundCapture_test(LPDIRECTSOUNDCAPTURE dsco, + BOOL initialized, LPCGUID lpGuid) +{ + HRESULT rc; + DSCCAPS dsccaps; + int ref; + IUnknown * unknown; + IDirectSoundCapture * dsc; + + /* Try to Query for objects */ + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IUnknown, + (LPVOID*)&unknown); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IUnknown) " + "failed: %s\n", DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSoundCapture_Release(unknown); + + rc=IDirectSoundCapture_QueryInterface(dsco, &IID_IDirectSoundCapture, + (LPVOID*)&dsc); + ok(rc==DS_OK, "IDirectSoundCapture_QueryInterface(IID_IDirectSoundCapture) " + "failed: %s\n", DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSoundCapture_Release(dsc); + + if (initialized == FALSE) { + /* try unitialized object */ + rc=IDirectSoundCapture_GetCaps(dsco,0); + ok(rc==DSERR_UNINITIALIZED, "IDirectSoundCapture_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSoundCapture_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSoundCapture_Initialize() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSoundCapture_Initialize(dsco, lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSoundCapture_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco, 0); + ok(rc==DSERR_INVALIDPARAM, "IDirectSoundCapture_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + ZeroMemory(&dsccaps, sizeof(dsccaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dsco, &dsccaps); + ok(rc==DSERR_INVALIDPARAM, "IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + dsccaps.dwSize=sizeof(dsccaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSoundCapture_GetCaps(dsco, &dsccaps); + ok(rc==DS_OK, "IDirectSoundCapture_GetCaps() failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSoundCapture_Release(dsco); + ok(ref==0, "IDirectSoundCapture_Release() has %d references, " + "should have 0\n", ref); +} + +static void IDirectSoundCapture_tests(void) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + + trace("Testing IDirectSoundCapture\n"); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK||rc==REGDB_E_CLASSNOTREG,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==REGDB_E_CLASSNOTREG) { + trace(" Class Not Registered\n"); + return; + } + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, NULL); + + /* try the COM class factory method of creation with default capture + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %s\n", + DXGetErrorString8(rc)); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultCapture); + + /* try the COM class factory method of creation with default voice + * capture device specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSoundCapture, (void**)&dsco); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSoundCapture) failed: %s\n", + DXGetErrorString8(rc)); + if (dsco) + IDirectSoundCapture_test(dsco, FALSE, &DSDEVID_DefaultVoiceCapture); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dsco); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSoundCapture,CLSID_DirectSoundPrivate) " + "should have failed: %s\n",DXGetErrorString8(rc)); + + /* try with no device specified */ + rc=pDirectSoundCaptureCreate(NULL,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(NULL) failed: %s\n",DXGetErrorString8(rc)); + if (rc==S_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultCapture) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with default voice capture device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoiceCapture,&dsco,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoiceCapture) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && dsco) + IDirectSoundCapture_test(dsco, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCaptureCreate(&DSDEVID_DefaultVoicePlayback,&dsco,NULL); + ok(rc==DSERR_NODRIVER, + "DirectSoundCaptureCreate(DSDEVID_DefaultVoicePlatback) " + "should have failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && dsco) + IDirectSoundCapture_Release(dsco); +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDCAPTUREBUFFER dscbo; + LPWAVEFORMATEX wfx; + DSBPOSITIONNOTIFY posnotify[NOTIFICATIONS]; + HANDLE event[NOTIFICATIONS]; + LPDIRECTSOUNDNOTIFY notify; + + DWORD buffer_size; + DWORD read; + DWORD offset; + DWORD size; + + DWORD last_pos; +} capture_state_t; + +static int capture_buffer_service(capture_state_t* state) +{ + HRESULT rc; + LPVOID ptr1,ptr2; + DWORD len1,len2; + DWORD capture_pos,read_pos; + + rc=IDirectSoundCaptureBuffer_GetCurrentPosition(state->dscbo,&capture_pos, + &read_pos); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCurrentPosition() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Lock(state->dscbo,state->offset,state->size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Lock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return 0; + + rc=IDirectSoundCaptureBuffer_Unlock(state->dscbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Unlock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return 0; + + state->offset = (state->offset + state->size) % state->buffer_size; + + return 1; +} + +static void test_capture_buffer(LPDIRECTSOUNDCAPTURE dsco, + LPDIRECTSOUNDCAPTUREBUFFER dscbo, int record) +{ + HRESULT rc; + DSCBCAPS dscbcaps; + WAVEFORMATEX wfx; + DWORD size,status; + capture_state_t state; + int i, ref; + + /* Private dsound.dll: Error: Invalid caps pointer */ + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + /* Private dsound.dll: Error: Invalid caps pointer */ + dscbcaps.dwSize=0; + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetCaps() should " + "have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + dscbcaps.dwSize=sizeof(dscbcaps); + rc=IDirectSoundCaptureBuffer_GetCaps(dscbo,&dscbcaps); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetCaps() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size = %ld flags=0x%08lx buffer size=%ld\n", + dscbcaps.dwSize,dscbcaps.dwFlags,dscbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + /* Private dsound.dll: Error: Either pwfxFormat or pdwSizeWritten must + * be non-NULL */ + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + size=0; + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundCaptureBuffer_GetFormat() should " + "have returned the needed size: rc=%s, size=%ld\n", + DXGetErrorString8(rc),size); + + rc=IDirectSoundCaptureBuffer_GetFormat(dscbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetFormat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* Private dsound.dll: Error: Invalid status pointer */ + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCaptureBuffer_GetStatus() should " + "have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Status=0x%04lx\n",status); + } + + ZeroMemory(&state, sizeof(state)); + state.dscbo=dscbo; + state.wfx=&wfx; + state.buffer_size = dscbcaps.dwBufferBytes; + for (i = 0; i < NOTIFICATIONS; i++) + state.event[i] = CreateEvent( NULL, FALSE, FALSE, NULL ); + state.size = dscbcaps.dwBufferBytes / NOTIFICATIONS; + + rc=IDirectSoundCaptureBuffer_QueryInterface(dscbo,&IID_IDirectSoundNotify, + (void **)&(state.notify)); + ok((rc==DS_OK)&&(state.notify!=NULL), + "IDirectSoundCaptureBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + for (i = 0; i < NOTIFICATIONS; i++) { + state.posnotify[i].dwOffset = (i * state.size) + state.size - 1; + state.posnotify[i].hEventNotify = state.event[i]; + } + + rc=IDirectSoundNotify_SetNotificationPositions(state.notify,NOTIFICATIONS, + state.posnotify); + ok(rc==DS_OK,"IDirectSoundNotify_SetNotificationPositions() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + ref=IDirectSoundNotify_Release(state.notify); + ok(ref==0,"IDirectSoundNotify_Release(): has %d references, should have " + "0\n",ref); + if (ref!=0) + return; + + if (record) { + rc=IDirectSoundCaptureBuffer_Start(dscbo,DSCBSTART_LOOPING); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Start() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + rc=IDirectSoundCaptureBuffer_GetStatus(dscbo,&status); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + ok(status==(DSCBSTATUS_CAPTURING|DSCBSTATUS_LOOPING), + "GetStatus: bad status: %lx\n",status); + if (rc!=DS_OK) + return; + + /* wait for the notifications */ + for (i = 0; i < (NOTIFICATIONS * 2); i++) { + rc=WaitForMultipleObjects(NOTIFICATIONS,state.event,FALSE,3000); + ok(rc==(WAIT_OBJECT_0+(i%NOTIFICATIONS)), + "WaitForMultipleObjects failed: 0x%lx\n",rc); + if (rc!=(WAIT_OBJECT_0+(i%NOTIFICATIONS))) { + ok((rc==WAIT_TIMEOUT)||(rc==WAIT_FAILED), + "Wrong notification: should be %d, got %ld\n", + i%NOTIFICATIONS,rc-WAIT_OBJECT_0); + } + if (!capture_buffer_service(&state)) + break; + } + + rc=IDirectSoundCaptureBuffer_Stop(dscbo); + ok(rc==DS_OK,"IDirectSoundCaptureBuffer_Stop() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + } +} + +static BOOL WINAPI dscenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUNDCAPTURE dsco=NULL; + LPDIRECTSOUNDCAPTUREBUFFER dscbo=NULL; + DSCBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + DSCCAPS dsccaps; + DWORD f; + int ref; + + /* Private dsound.dll: Error: Invalid interface buffer */ + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + rc=pDirectSoundCaptureCreate(lpGuid,NULL,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCaptureCreate() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + ref=IDirectSoundCapture_Release(dsco); + ok(ref==0,"IDirectSoundCapture_Release() has %d references, should " + "have 0\n",ref); + } + + rc=pDirectSoundCaptureCreate(lpGuid,&dsco,NULL); + ok((rc==DS_OK)||(rc==DSERR_NODRIVER)||(rc==E_FAIL)||(rc==DSERR_ALLOCATED), + "DirectSoundCaptureCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc==E_FAIL) + trace(" No Device\n"); + else if (rc==DSERR_ALLOCATED) + trace(" Already In Use\n"); + goto EXIT; + } + + /* Private dsound.dll: Error: Invalid caps buffer */ + rc=IDirectSoundCapture_GetCaps(dsco,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* Private dsound.dll: Error: Invalid caps buffer */ + dsccaps.dwSize=0; + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + dsccaps.dwSize=sizeof(dsccaps); + rc=IDirectSoundCapture_GetCaps(dsco,&dsccaps); + ok(rc==DS_OK,"IDirectSoundCapture_GetCaps() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: size=%ld flags=0x%08lx formats=%05lx channels=%ld\n", + dsccaps.dwSize,dsccaps.dwFlags,dsccaps.dwFormats, + dsccaps.dwChannels); + } + + /* Private dsound.dll: Error: Invalid size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=0; + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=NULL; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + ZeroMemory(&bufdesc, sizeof(bufdesc)); + ZeroMemory(&wfx, sizeof(wfx)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned :%s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + /* Private dsound.dll: Error: Invalid buffer size */ + /* Private dsound.dll: Error: Invalid capture buffer description */ + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=0; + bufdesc.dwBufferBytes=0; + bufdesc.dwReserved=0; + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSoundCapture_CreateCaptureBuffer(dsco,&bufdesc,&dscbo,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundCapture_CreateCaptureBuffer() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + ref=IDirectSoundCaptureBuffer_Release(dscbo); + ok(ref==0,"IDirectSoundCaptureBuffer_Release() has %d references, " + "should have 0\n",ref); + } + + for (f=0;f - -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "dxerr8.h" - -#include "dsound_test.h" - -#define PI 3.14159265358979323846 -char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) -{ - int i; - int nb_samples; - char* buf; - char* b; - - nb_samples=(int)(duration*wfx->nSamplesPerSec); - *size=nb_samples*wfx->nBlockAlign; - b=buf=malloc(*size); - for (i=0;inSamplesPerSec); - if (wfx->wBitsPerSample==8) { - unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); - *b++=sample; - if (wfx->nChannels==2) - *b++=sample; - } else { - signed short sample=(signed short)((double)32767.5*y-0.5); - b[0]=sample & 0xff; - b[1]=sample >> 8; - b+=2; - if (wfx->nChannels==2) { - b[0]=sample & 0xff; - b[1]=sample >> 8; - b+=2; - } - } - } - return buf; -} - -const char * getDSBCAPS(DWORD xmask) { - static struct { - DWORD mask; - char *name; - } flags[] = { -#define FE(x) { x, #x }, - FE(DSBCAPS_PRIMARYBUFFER) - FE(DSBCAPS_STATIC) - FE(DSBCAPS_LOCHARDWARE) - FE(DSBCAPS_LOCSOFTWARE) - FE(DSBCAPS_CTRL3D) - FE(DSBCAPS_CTRLFREQUENCY) - FE(DSBCAPS_CTRLPAN) - FE(DSBCAPS_CTRLVOLUME) - FE(DSBCAPS_CTRLPOSITIONNOTIFY) - FE(DSBCAPS_STICKYFOCUS) - FE(DSBCAPS_GLOBALFOCUS) - FE(DSBCAPS_GETCURRENTPOSITION2) - FE(DSBCAPS_MUTE3DATMAXDISTANCE) -#undef FE - }; - static char buffer[512]; - int i; - BOOL first = TRUE; - - buffer[0] = 0; - - for (i=0;iwFormatTag=format; - wfx->nChannels=channels; - wfx->wBitsPerSample=depth; - wfx->nSamplesPerSec=rate; - wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; - /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */ - if (wfx->nBlockAlign==0) - { - /* align compressed formats to byte boundary */ - wfx->nBlockAlign=1; - } - wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; - wfx->cbSize=0; -} - -typedef struct { - char* wave; - DWORD wave_len; - - LPDIRECTSOUNDBUFFER dsbo; - LPWAVEFORMATEX wfx; - DWORD buffer_size; - DWORD written; - DWORD played; - DWORD offset; -} play_state_t; - -static int buffer_refill(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - - if (size>state->wave_len-state->written) - size=state->wave_len-state->written; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - - memcpy(ptr1,state->wave+state->written,len1); - state->written+=len1; - if (ptr2!=NULL) { - memcpy(ptr2,state->wave+state->written,len2); - state->written+=len2; - } - state->offset=state->written % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_silence(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - BYTE s; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - - s=(state->wfx->wBitsPerSample==8?0x80:0); - memset(ptr1,s,len1); - if (ptr2!=NULL) { - memset(ptr2,s,len2); - } - state->offset=(state->offset+size) % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_service(play_state_t* state) -{ - DWORD last_play_pos,play_pos,buf_free; - HRESULT rc; - - rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) { - goto STOP; - } - - /* Update the amount played */ - last_play_pos=state->played % state->buffer_size; - if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; - else - state->played+=play_pos-last_play_pos; - - if (winetest_debug > 1) - trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n", - state->buffer_size,last_play_pos,play_pos,state->played, - state->wave_len); - - if (state->played>state->wave_len) - { - /* Everything has been played */ - goto STOP; - } - - /* Refill the buffer */ - if (state->offset<=play_pos) - buf_free=play_pos-state->offset; - else - buf_free=state->buffer_size-state->offset+play_pos; - - if (winetest_debug > 1) - trace("offset=%ld free=%ld written=%ld / %ld\n", - state->offset,buf_free,state->written,state->wave_len); - if (buf_free==0) - return 1; - - if (state->writtenwave_len) - { - int w=buffer_refill(state,buf_free); - if (w==-1) - goto STOP; - buf_free-=w; - if (state->written==state->wave_len && winetest_debug > 1) - trace("last sound byte at %ld\n", - (state->written % state->buffer_size)); - } - - if (buf_free>0) { - /* Fill with silence */ - if (winetest_debug > 1) - trace("writing %ld bytes of silence\n",buf_free); - if (buffer_silence(state,buf_free)==-1) - goto STOP; - } - return 1; - -STOP: - if (winetest_debug > 1) - trace("stopping playback\n"); - rc=IDirectSoundBuffer_Stop(state->dsbo); - ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %s\n", - DXGetErrorString8(rc)); - return 0; -} - -void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo, - BOOL is_primary, BOOL set_volume, LONG volume, - BOOL set_pan, LONG pan, BOOL play, double duration, - BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, - BOOL move_listener, BOOL move_sound) -{ - HRESULT rc; - DSBCAPS dsbcaps; - WAVEFORMATEX wfx,wfx2; - DWORD size,status,freq; - int ref; - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - ZeroMemory(&dsbcaps, sizeof(dsbcaps)); - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - dsbcaps.dwSize=sizeof(dsbcaps); - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, - dsbcaps.dwBufferBytes); - } - - /* Query the format size. Note that it may not match sizeof(wfx) */ - size=0; - rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); - ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " - "returned the needed size: rc=%s size=%ld\n",DXGetErrorString8(rc),size); - - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Format: %s tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - is_primary ? "Primary" : "Secondary", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* DSOUND: Error: Invalid frequency buffer */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); - ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || - (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), - "IDirectSoundBuffer_GetFrequency() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency " - "%ld does not match the format %ld\n",freq,wfx.nSamplesPerSec); - } - - /* DSOUND: Error: Invalid status pointer */ - rc=IDirectSoundBuffer_GetStatus(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - ok(status==0,"status=0x%lx instead of 0\n",status); - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call SetFormat */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - /* DSOUND: Error: Invalid format pointer */ - rc=IDirectSoundBuffer_SetFormat(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); - rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); - ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat() failed: %s\n", - DXGetErrorString8(rc)); - - /* There is no garantee that SetFormat will actually change the - * format to what we asked for. It depends on what the soundcard - * supports. So we must re-query the format. - */ - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && - (wfx.wFormatTag!=wfx2.wFormatTag || - wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || - wfx.wBitsPerSample!=wfx2.wBitsPerSample || - wfx.nChannels!=wfx2.nChannels)) { - trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, - wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); - trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: " - "%s\n",DXGetErrorString8(rc)); - } - - if (play) { - play_state_t state; - DS3DLISTENER listener_param; - LPDIRECTSOUND3DBUFFER buffer=NULL; - DS3DBUFFER buffer_param; - DWORD start_time,now; - - if (winetest_interactive) { - trace(" Playing %g second 440Hz tone at %ldx%dx%d\n", duration, - wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); - } - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call Lock */ - /* DSOUND: Setting DirectSound cooperative level to - * DSSCL_WRITEPRIMARY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(), - DSSCL_WRITEPRIMARY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) " - "failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - } - if (buffer3d) { - LPDIRECTSOUNDBUFFER temp_buffer; - - rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer, - (LPVOID *)&buffer); - ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - /* check the COM interface */ - rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, - (LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - temp_buffer=NULL; - rc=IDirectSound3DBuffer_QueryInterface(dsbo, - &IID_IDirectSoundBuffer, - (LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSound3DBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - -#if 0 - /* FIXME: this works on windows */ - ref=IDirectSoundBuffer_Release(dsbo); - ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " - "should have 0\n",ref); - - rc=IDirectSound3DBuffer_QueryInterface(buffer, - &IID_IDirectSoundBuffer, - (LPVOID *)&dsbo); - ok(rc==DS_OK && dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " - "failed: %s\n",DXGetErrorString8(rc)); -#endif - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - - ZeroMemory(&buffer_param, sizeof(buffer_param)); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - - buffer_param.dwSize=sizeof(buffer_param); - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %s\n", - DXGetErrorString8(rc)); - } - if (set_volume) { - if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { - LONG val; - rc=IDirectSoundBuffer_GetVolume(dsbo,&val); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetVolume(dsbo,volume); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %s\n", - DXGetErrorString8(rc)); - } else { - /* DSOUND: Error: Buffer does not have CTRLVOLUME */ - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " - "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", - DXGetErrorString8(rc)); - } - } - - if (set_pan) { - if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { - LONG val; - rc=IDirectSoundBuffer_GetPan(dsbo,&val); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetPan(dsbo,pan); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %s\n", - DXGetErrorString8(rc)); - } else { - /* DSOUND: Error: Buffer does not have CTRLPAN */ - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " - "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", - DXGetErrorString8(rc)); - } - } - - state.wave=wave_generate_la(&wfx,duration,&state.wave_len); - - state.dsbo=dsbo; - state.wfx=&wfx; - state.buffer_size=dsbcaps.dwBufferBytes; - state.played=state.written=state.offset=0; - buffer_refill(&state,state.buffer_size); - - rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); - ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), - "GetStatus: bad status: %lx\n",status); - - if (listener) { - ZeroMemory(&listener_param,sizeof(listener_param)); - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener, - &listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - if (move_listener) { - listener_param.vPosition.x = -5.0; - listener_param.vVelocity.x = 10.0/duration; - } - rc=IDirectSound3DListener_SetAllParameters(listener, - &listener_param, - DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - if (buffer3d) { - if (move_sound) { - buffer_param.vPosition.x = 100.0; - buffer_param.vVelocity.x = -200.0/duration; - } - buffer_param.flMinDistance = 10; - rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, - DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - - start_time=GetTickCount(); - while (buffer_service(&state)) { - WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); - now=GetTickCount(); - if (listener && move_listener) { - listener_param.vPosition.x = -5.0+10.0*(now-start_time)/ - 1000/duration; - if (winetest_debug>2) - trace("listener position=%g\n",listener_param.vPosition.x); - rc=IDirectSound3DListener_SetPosition(listener, - listener_param.vPosition.x,listener_param.vPosition.y, - listener_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: " - "%s\n",DXGetErrorString8(rc)); - } - if (buffer3d && move_sound) { - buffer_param.vPosition.x = 100-200.0*(now-start_time)/ - 1000/duration; - if (winetest_debug>2) - trace("sound position=%g\n",buffer_param.vPosition.x); - rc=IDirectSound3DBuffer_SetPosition(buffer, - buffer_param.vPosition.x,buffer_param.vPosition.y, - buffer_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - } - /* Check the sound duration was within 10% of the expected value */ - now=GetTickCount(); - ok(fabs(1000*duration-now+start_time)<=100*duration, - "The sound played for %ld ms instead of %g ms\n", - now-start_time,1000*duration); - - free(state.wave); - if (is_primary) { - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) " - "failed: %s\n",DXGetErrorString8(rc)); - } - if (buffer3d) { - ref=IDirectSound3DBuffer_Release(buffer); - ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " - "should have 0\n",ref); - } - } -} - -static HRESULT test_secondary(LPGUID lpGuid, int play, - int has_3d, int has_3dbuffer, - int has_listener, int has_duplicate, - int move_listener, int move_sound) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - LPDIRECTSOUND3DLISTENER listener=NULL; - DSBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* We must call SetCooperativeLevel before creating primary buffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - if (has_3d) - bufdesc.dwFlags|=DSBCAPS_CTRL3D; - else - bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() " - "failed to create a %sprimary buffer: %s\n",has_3d?"3D ":"", - DXGetErrorString8(rc)); - - if (rc==DS_OK && primary!=NULL) { - if (has_listener) { - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSound3DListener, - (void **)&listener); - ok(rc==DS_OK && listener!=NULL, - "IDirectSoundBuffer_QueryInterface() failed to get a 3D " - "listener: %s\n",DXGetErrorString8(rc)); - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - if (rc==DS_OK && listener!=NULL) { - DS3DLISTENER listener_param; - ZeroMemory(&listener_param,sizeof(listener_param)); - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound3dListener_GetAllParameters() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener, - &listener_param); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound3dListener_GetAllParameters() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener, - &listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - } - else - goto EXIT; - } - - init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); - secondary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; - if (has_3d) - bufdesc.dwFlags|=DSBCAPS_CTRL3D; - else - bufdesc.dwFlags|= - (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); - bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000; - bufdesc.lpwfxFormat=&wfx; - if (winetest_interactive) { - trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d\n", - has_3dbuffer?"3D ":"", - has_duplicate?"duplicated ":"", - listener!=NULL||move_sound?"with ":"", - move_listener?"moving ":"", - listener!=NULL?"listener ":"", - listener&&move_sound?"and moving sound ":move_sound? - "moving sound ":"", - wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); - } - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() " - "failed to create a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d (%s): %s\n", - has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", - listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", - listener!=NULL?"listener ":"", - listener&&move_sound?"and moving sound ":move_sound? - "moving sound ":"", - wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, - getDSBCAPS(bufdesc.dwFlags),DXGetErrorString8(rc)); - if (rc==DS_OK && secondary!=NULL) { - if (!has_3d) { - DWORD refpan,pan; - LONG refvol,vol; - - /* Check the initial secondary buffer's volume and pan */ - rc=IDirectSoundBuffer_GetVolume(secondary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(vol==0,"wrong volume for a new secondary buffer: %ld\n",vol); - rc=IDirectSoundBuffer_GetPan(secondary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(pan==0,"wrong pan for a new secondary buffer: %ld\n",pan); - - /* Check that changing the secondary buffer's volume and pan - * does not impact the primary buffer's volume and pan - */ - rc=IDirectSoundBuffer_GetVolume(primary,&refvol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetPan(primary,&refpan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetVolume(secondary,-1000); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetVolume(secondary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(vol==-1000,"secondary: wrong volume %ld instead of -1000\n", - vol); - rc=IDirectSoundBuffer_SetPan(secondary,-1000); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetPan(secondary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(pan==-1000,"secondary: wrong pan %ld instead of -1000\n", - pan); - - rc=IDirectSoundBuffer_GetVolume(primary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(vol==refvol,"The primary volume changed from %ld to %ld\n", - refvol,vol); - rc=IDirectSoundBuffer_GetPan(primary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n", - DXGetErrorString8(rc)); - ok(pan==refpan,"The primary pan changed from %ld to %ld\n", - refpan,pan); - - rc=IDirectSoundBuffer_SetVolume(secondary,0); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_SetPan(secondary,0); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - } - if (has_duplicate) { - LPDIRECTSOUNDBUFFER duplicated=NULL; - - /* DSOUND: Error: Invalid source buffer */ - rc=IDirectSound_DuplicateSoundBuffer(dso,0,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid dest buffer */ - rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid source buffer */ - rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - duplicated=NULL; - rc=IDirectSound_DuplicateSoundBuffer(dso,secondary, - &duplicated); - ok(rc==DS_OK && duplicated!=NULL, - "IDirectSound_DuplicateSoundBuffer() failed to duplicate " - "a secondary buffer: %s\n",DXGetErrorString8(rc)); - - if (rc==DS_OK && duplicated!=NULL) { - ref=IDirectSoundBuffer_Release(secondary); - ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " - "references, should have 0\n",ref); - secondary=duplicated; - } - } - - if (rc==DS_OK && secondary!=NULL) { - double duration; - duration=(move_listener || move_sound?4.0:1.0); - test_buffer(dso,secondary,0,FALSE,0,FALSE,0, - winetest_interactive,duration,has_3dbuffer, - listener,move_listener,move_sound); - ref=IDirectSoundBuffer_Release(secondary); - ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " - "should have 0\n",has_duplicate?"duplicated":"secondary", - ref); - } - } - } - if (has_listener) { - ref=IDirectSound3DListener_Release(listener); - ok(ref==0,"IDirectSound3dListener_Release() listener has %d " - "references, should have 0\n",ref); - } else { - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", - DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_for_driver(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref, i; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* Testing the primary buffer */ - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " - "to create a primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - test_buffer(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); - if (winetest_interactive) { - LONG volume,pan; - - volume = DSBVOLUME_MAX; - for (i = 0; i < 6; i++) { - test_buffer(dso,primary,1,TRUE,volume,TRUE,0, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER), - 1.0,0,NULL,0,0); - volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); - } - - pan = DSBPAN_LEFT; - for (i = 0; i < 7; i++) { - test_buffer(dso,primary,1,TRUE,0,TRUE,pan, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); - pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); - } - } - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", - DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary_3d(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " - "to create a primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() " - "failed to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - } - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", - DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary_3d_with_listener(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " - "to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - LPDIRECTSOUND3DLISTENER listener=NULL; - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSound3DListener,(void **)&listener); - ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " - "failed to get a 3D listener: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && listener!=NULL) { - LPDIRECTSOUNDBUFFER temp_buffer=NULL; - - /* Checking the COM interface */ - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==primary, - "COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)primary); - if (rc==DS_OK && temp_buffer!=NULL) { - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - temp_buffer=NULL; - rc=IDirectSound3DListener_QueryInterface(listener, - &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==primary, - "COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)primary); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - /* Testing the buffer */ - test_buffer(dso,primary,1,FALSE,0,FALSE,0, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0, - listener,0,0); - } - - /* Testing the reference counting */ - ref=IDirectSound3DListener_Release(listener); - ok(ref==0,"IDirectSound3DListener_Release() listener has %d " - "references, should have 0\n",ref); - } - - /* Testing the reference counting */ - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - -EXIT: - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) -return DSERR_GENERIC; - - return rc; -} - -static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, - LPCSTR lpcstrModule, LPVOID lpContext) -{ - HRESULT rc; - trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); - - rc = test_for_driver(lpGuid); - if (rc == DSERR_NODRIVER) { - trace(" No Driver\n"); - return 1; - } else if (rc == DSERR_ALLOCATED) { - trace(" Already In Use\n"); - return 1; - } - - trace(" Testing the primary buffer\n"); - test_primary(lpGuid); - - trace(" Testing 3D primary buffer\n"); - test_primary_3d(lpGuid); - - trace(" Testing 3D primary buffer with listener\n"); - test_primary_3d_with_listener(lpGuid); - - /* Testing secondary buffers */ - test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0); - test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0); - - /* Testing 3D secondary buffers */ - test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0); - test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0); - test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0); - test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0); - test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0); - test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0); - test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0); - test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0); - test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); - test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1); - - return 1; -} - -static void ds3d_tests() -{ - HRESULT rc; - rc=DirectSoundEnumerateA(&dsenum_callback,NULL); - ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); -} - -START_TEST(ds3d) -{ - ds3d_tests(); -} +/* + * Tests the panning and 3D functions of DirectSound + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dxerr8.h" + +#include "dsound_test.h" + +#define PI 3.14159265358979323846 +char* wave_generate_la(WAVEFORMATEX* wfx, double duration, DWORD* size) +{ + int i; + int nb_samples; + char* buf; + char* b; + + nb_samples=(int)(duration*wfx->nSamplesPerSec); + *size=nb_samples*wfx->nBlockAlign; + b=buf=malloc(*size); + for (i=0;inSamplesPerSec); + if (wfx->wBitsPerSample==8) { + unsigned char sample=(unsigned char)((double)127.5*(y+1.0)); + *b++=sample; + if (wfx->nChannels==2) + *b++=sample; + } else { + signed short sample=(signed short)((double)32767.5*y-0.5); + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + if (wfx->nChannels==2) { + b[0]=sample & 0xff; + b[1]=sample >> 8; + b+=2; + } + } + } + return buf; +} + +const char * getDSBCAPS(DWORD xmask) { + static struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x }, + FE(DSBCAPS_PRIMARYBUFFER) + FE(DSBCAPS_STATIC) + FE(DSBCAPS_LOCHARDWARE) + FE(DSBCAPS_LOCSOFTWARE) + FE(DSBCAPS_CTRL3D) + FE(DSBCAPS_CTRLFREQUENCY) + FE(DSBCAPS_CTRLPAN) + FE(DSBCAPS_CTRLVOLUME) + FE(DSBCAPS_CTRLPOSITIONNOTIFY) + FE(DSBCAPS_STICKYFOCUS) + FE(DSBCAPS_GLOBALFOCUS) + FE(DSBCAPS_GETCURRENTPOSITION2) + FE(DSBCAPS_MUTE3DATMAXDISTANCE) +#undef FE + }; + static char buffer[512]; + unsigned int i; + BOOL first = TRUE; + + buffer[0] = 0; + + for (i=0;iwFormatTag=format; + wfx->nChannels=channels; + wfx->wBitsPerSample=depth; + wfx->nSamplesPerSec=rate; + wfx->nBlockAlign=wfx->nChannels*wfx->wBitsPerSample/8; + /* FIXME: Shouldn't this test be if (format!=WAVE_FORMAT_PCM) */ + if (wfx->nBlockAlign==0) + { + /* align compressed formats to byte boundary */ + wfx->nBlockAlign=1; + } + wfx->nAvgBytesPerSec=wfx->nSamplesPerSec*wfx->nBlockAlign; + wfx->cbSize=0; +} + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDBUFFER dsbo; + LPWAVEFORMATEX wfx; + DWORD buffer_size; + DWORD written; + DWORD played; + DWORD offset; +} play_state_t; + +static int buffer_refill(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + + if (size>state->wave_len-state->written) + size=state->wave_len-state->written; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + + memcpy(ptr1,state->wave+state->written,len1); + state->written+=len1; + if (ptr2!=NULL) { + memcpy(ptr2,state->wave+state->written,len2); + state->written+=len2; + } + state->offset=state->written % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_silence(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + BYTE s; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + + s=(state->wfx->wBitsPerSample==8?0x80:0); + memset(ptr1,s,len1); + if (ptr2!=NULL) { + memset(ptr2,s,len2); + } + state->offset=(state->offset+size) % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_service(play_state_t* state) +{ + DWORD last_play_pos,play_pos,buf_free; + HRESULT rc; + + rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + goto STOP; + } + + /* Update the amount played */ + last_play_pos=state->played % state->buffer_size; + if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; + else + state->played+=play_pos-last_play_pos; + + if (winetest_debug > 1) + trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n", + state->buffer_size,last_play_pos,play_pos,state->played, + state->wave_len); + + if (state->played>state->wave_len) + { + /* Everything has been played */ + goto STOP; + } + + /* Refill the buffer */ + if (state->offset<=play_pos) + buf_free=play_pos-state->offset; + else + buf_free=state->buffer_size-state->offset+play_pos; + + if (winetest_debug > 1) + trace("offset=%ld free=%ld written=%ld / %ld\n", + state->offset,buf_free,state->written,state->wave_len); + if (buf_free==0) + return 1; + + if (state->writtenwave_len) + { + int w=buffer_refill(state,buf_free); + if (w==-1) + goto STOP; + buf_free-=w; + if (state->written==state->wave_len && winetest_debug > 1) + trace("last sound byte at %ld\n", + (state->written % state->buffer_size)); + } + + if (buf_free>0) { + /* Fill with silence */ + if (winetest_debug > 1) + trace("writing %ld bytes of silence\n",buf_free); + if (buffer_silence(state,buf_free)==-1) + goto STOP; + } + return 1; + +STOP: + if (winetest_debug > 1) + trace("stopping playback\n"); + rc=IDirectSoundBuffer_Stop(state->dsbo); + ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %s\n", + DXGetErrorString8(rc)); + return 0; +} + +void test_buffer(LPDIRECTSOUND dso, LPDIRECTSOUNDBUFFER dsbo, + BOOL is_primary, BOOL set_volume, LONG volume, + BOOL set_pan, LONG pan, BOOL play, double duration, + BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, + BOOL move_listener, BOOL move_sound, + BOOL set_frequency, DWORD frequency) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + if (set_frequency) { + rc=IDirectSoundBuffer_SetFrequency(dsbo,frequency); + ok(rc==DS_OK||rc==DSERR_CONTROLUNAVAIL, + "IDirectSoundBuffer_SetFrequency() failed to set frequency " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + } + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + dsbcaps.dwSize=sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, + dsbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + size=0; + rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " + "returned the needed size: rc=%s size=%ld\n",DXGetErrorString8(rc),size); + + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: %s tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + is_primary ? "Primary" : "Secondary", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* DSOUND: Error: Invalid frequency buffer */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); + ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || + (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), + "IDirectSoundBuffer_GetFrequency() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + DWORD f = set_frequency?frequency:wfx.nSamplesPerSec; + ok(freq==f,"The frequency returned by GetFrequency " + "%ld does not match the format %ld\n",freq,f); + } + + /* DSOUND: Error: Invalid status pointer */ + rc=IDirectSoundBuffer_GetStatus(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + ok(status==0,"status=0x%lx instead of 0\n",status); + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call SetFormat */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + /* DSOUND: Error: Invalid format pointer */ + rc=IDirectSoundBuffer_SetFormat(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); + rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); + ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat() failed: %s\n", + DXGetErrorString8(rc)); + + /* There is no garantee that SetFormat will actually change the + * format to what we asked for. It depends on what the soundcard + * supports. So we must re-query the format. + */ + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && + (wfx.wFormatTag!=wfx2.wFormatTag || + wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || + wfx.wBitsPerSample!=wfx2.wBitsPerSample || + wfx.nChannels!=wfx2.nChannels)) { + trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, + wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); + trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: " + "%s\n",DXGetErrorString8(rc)); + } + + if (play) { + play_state_t state; + DS3DLISTENER listener_param; + LPDIRECTSOUND3DBUFFER buffer=NULL; + DS3DBUFFER buffer_param; + DWORD start_time,now; + + if (winetest_interactive) { + if (set_frequency) + trace(" Playing %g second 440Hz tone at %ldx%dx%d with a " + "frequency of %ld (%ldHz)\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels, + frequency, (440 * frequency) / wfx.nSamplesPerSec); + else + trace(" Playing %g second 440Hz tone at %ldx%dx%d\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nChannels); + } + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call Lock */ + /* DSOUND: Setting DirectSound cooperative level to + * DSSCL_WRITEPRIMARY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(), + DSSCL_WRITEPRIMARY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_WRITEPRIMARY) " + "failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + } + if (buffer3d) { + LPDIRECTSOUNDBUFFER temp_buffer; + + rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer, + (LPVOID *)&buffer); + ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + /* check the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==dsbo,"COM interface broken: %p != %p\n", + temp_buffer,dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DBuffer_QueryInterface(dsbo, + &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSound3DBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==dsbo,"COM interface broken: %p != %p\n", + temp_buffer,dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + +#if 0 + /* FIXME: this works on windows */ + ref=IDirectSoundBuffer_Release(dsbo); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + + rc=IDirectSound3DBuffer_QueryInterface(buffer, + &IID_IDirectSoundBuffer, + (LPVOID *)&dsbo); + ok(rc==DS_OK && dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " + "failed: %s\n",DXGetErrorString8(rc)); +#endif + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + + ZeroMemory(&buffer_param, sizeof(buffer_param)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + + buffer_param.dwSize=sizeof(buffer_param); + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %s\n", + DXGetErrorString8(rc)); + } + if (set_volume) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { + LONG val; + rc=IDirectSoundBuffer_GetVolume(dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetVolume(dsbo,volume); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %s\n", + DXGetErrorString8(rc)); + } else { + /* DSOUND: Error: Buffer does not have CTRLVOLUME */ + rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", + DXGetErrorString8(rc)); + } + } + + if (set_pan) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { + LONG val; + rc=IDirectSoundBuffer_GetPan(dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetPan(dsbo,pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %s\n", + DXGetErrorString8(rc)); + } else { + /* DSOUND: Error: Buffer does not have CTRLPAN */ + rc=IDirectSoundBuffer_GetPan(dsbo,&pan); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", + DXGetErrorString8(rc)); + } + } + + if (set_frequency) + state.wave=wave_generate_la(&wfx,(duration*frequency)/wfx.nSamplesPerSec,&state.wave_len); + else + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.played=state.written=state.offset=0; + buffer_refill(&state,state.buffer_size); + + rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); + ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), + "GetStatus: bad status: %lx\n",status); + + if (listener) { + ZeroMemory(&listener_param,sizeof(listener_param)); + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + if (move_listener) { + listener_param.vPosition.x = -5.0; + listener_param.vVelocity.x = 10.0/duration; + } + rc=IDirectSound3DListener_SetAllParameters(listener, + &listener_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + if (buffer3d) { + if (move_sound) { + buffer_param.vPosition.x = 100.0; + buffer_param.vVelocity.x = -200.0/duration; + } + buffer_param.flMinDistance = 10; + rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + + start_time=GetTickCount(); + while (buffer_service(&state)) { + WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); + now=GetTickCount(); + if (listener && move_listener) { + listener_param.vPosition.x = -5.0+10.0*(now-start_time)/ + 1000/duration; + if (winetest_debug>2) + trace("listener position=%g\n",listener_param.vPosition.x); + rc=IDirectSound3DListener_SetPosition(listener, + listener_param.vPosition.x,listener_param.vPosition.y, + listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: " + "%s\n",DXGetErrorString8(rc)); + } + if (buffer3d && move_sound) { + buffer_param.vPosition.x = 100-200.0*(now-start_time)/ + 1000/duration; + if (winetest_debug>2) + trace("sound position=%g\n",buffer_param.vPosition.x); + rc=IDirectSound3DBuffer_SetPosition(buffer, + buffer_param.vPosition.x,buffer_param.vPosition.y, + buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + } + /* Check the sound duration was within 10% of the expected value */ + now=GetTickCount(); + ok(fabs(1000*duration-now+start_time)<=100*duration, + "The sound played for %ld ms instead of %g ms\n", + now-start_time,1000*duration); + + free(state.wave); + if (is_primary) { + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %s\n",DXGetErrorString8(rc)); + } + if (buffer3d) { + ref=IDirectSound3DBuffer_Release(buffer); + ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +} + +static HRESULT test_secondary(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx, wfx1; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a %sprimary buffer: " + "%s\n",has_3d?"3D ":"", DXGetErrorString8(rc)); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT1; + + if (has_listener) { + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL, + "IDirectSoundBuffer_QueryInterface() failed to get a 3D " + "listener: %s\n",DXGetErrorString8(rc)); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + if (rc==DS_OK && listener!=NULL) { + DS3DLISTENER listener_param; + ZeroMemory(&listener_param,sizeof(listener_param)); + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + } + else + goto EXIT; + } + + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); + secondary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|= + (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + if (winetest_interactive) { + trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d " + "with a primary buffer at %ldx%dx%d\n", + has_3dbuffer?"3D ":"", + has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", + move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d (%s): %s\n", + has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + getDSBCAPS(bufdesc.dwFlags),DXGetErrorString8(rc)); + if (rc==DS_OK && secondary!=NULL) { + if (!has_3d) { + LONG refvol,vol,refpan,pan; + + /* Check the initial secondary buffer's volume and pan */ + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(vol==0,"wrong volume for a new secondary buffer: %ld\n",vol); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(pan==0,"wrong pan for a new secondary buffer: %ld\n",pan); + + /* Check that changing the secondary buffer's volume and pan + * does not impact the primary buffer's volume and pan + */ + rc=IDirectSoundBuffer_GetVolume(primary,&refvol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetPan(primary,&refpan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetVolume(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(vol==-1000,"secondary: wrong volume %ld instead of -1000\n", + vol); + rc=IDirectSoundBuffer_SetPan(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(pan==-1000,"secondary: wrong pan %ld instead of -1000\n", + pan); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(vol==refvol,"The primary volume changed from %ld to %ld\n", + refvol,vol); + rc=IDirectSoundBuffer_GetPan(primary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: %s\n", + DXGetErrorString8(rc)); + ok(pan==refpan,"The primary pan changed from %ld to %ld\n", + refpan,pan); + + rc=IDirectSoundBuffer_SetVolume(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_SetPan(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + } + if (has_duplicate) { + LPDIRECTSOUNDBUFFER duplicated=NULL; + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + duplicated=NULL; + rc=IDirectSound_DuplicateSoundBuffer(dso,secondary, + &duplicated); + ok(rc==DS_OK && duplicated!=NULL, + "IDirectSound_DuplicateSoundBuffer() failed to duplicate " + "a secondary buffer: %s\n",DXGetErrorString8(rc)); + + if (rc==DS_OK && duplicated!=NULL) { + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + secondary=duplicated; + } + } + + if (rc==DS_OK && secondary!=NULL) { + double duration; + duration=(move_listener || move_sound?4.0:1.0); + test_buffer(dso,secondary,0,FALSE,0,FALSE,0, + winetest_interactive,duration,has_3dbuffer, + listener,move_listener,move_sound,FALSE,0); + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " + "should have 0\n",has_duplicate?"duplicated":"secondary", + ref); + } + } + } +EXIT1: + if (has_listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has %d " + "references, should have 0\n",ref); + } else { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_for_driver(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: " + "%s\n",DXGetErrorString8(rc)); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0, + FALSE,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer(dso,primary,1,TRUE,volume,TRUE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,NULL,0,0,FALSE,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer(dso,primary,1,TRUE,0,TRUE,pan, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0,FALSE,0); + pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); + } + } + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " + "to create a primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0, + FALSE,0); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_NORMAL) failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound_CreateSoundBuffer() failed " + "to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=NULL; + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener,(void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " + "failed to get a 3D listener: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && listener!=NULL) { + LPDIRECTSOUNDBUFFER temp_buffer=NULL; + + /* Checking the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==primary, + "COM interface broken: %p != %p\n", + temp_buffer,primary); + if (rc==DS_OK && temp_buffer!=NULL) { + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DListener_QueryInterface(listener, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==primary, + "COM interface broken: %p != %p\n", + temp_buffer,primary); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + /* Testing the buffer */ + test_buffer(dso,primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0, + listener,0,0,FALSE,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc = test_for_driver(lpGuid); + if (rc == DSERR_NODRIVER) { + trace(" No Driver\n"); + return 1; + } else if (rc == DSERR_ALLOCATED) { + trace(" Already In Use\n"); + return 1; + } else if (rc == E_FAIL) { + trace(" No Device\n"); + return 1; + } + + trace(" Testing the primary buffer\n"); + test_primary(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener(lpGuid); + + /* Testing secondary buffers */ + test_secondary(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d_tests(void) +{ + HRESULT rc; + rc=DirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); +} + +START_TEST(ds3d) +{ + CoInitialize(NULL); + + trace("DLL Version: %s\n", get_file_version("dsound.dll")); + + ds3d_tests(); + + CoUninitialize(); +} diff --git a/reactos/lib/dsound/tests/ds3d8.c b/reactos/lib/dsound/tests/ds3d8.c index 3ce5a32b57b..e217e40f448 100644 --- a/reactos/lib/dsound/tests/ds3d8.c +++ b/reactos/lib/dsound/tests/ds3d8.c @@ -1,1133 +1,1148 @@ -/* - * Tests the panning and 3D functions of DirectSound - * - * Part of this test involves playing test tones. But this only makes - * sense if someone is going to carefully listen to it, and would only - * bother everyone else. - * So this is only done if the test is being run in interactive mode. - * - * Copyright (c) 2002-2004 Francois Gouget - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSSTRUCT -#define NONAMELESSUNION -#include - -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "dxerr8.h" - -#include "dsound_test.h" - -static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; - -typedef struct { - char* wave; - DWORD wave_len; - - LPDIRECTSOUNDBUFFER dsbo; - LPWAVEFORMATEX wfx; - DWORD buffer_size; - DWORD written; - DWORD played; - DWORD offset; -} play_state_t; - -static int buffer_refill8(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - - if (size>state->wave_len-state->written) - size=state->wave_len-state->written; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - - memcpy(ptr1,state->wave+state->written,len1); - state->written+=len1; - if (ptr2!=NULL) { - memcpy(ptr2,state->wave+state->written,len2); - state->written+=len2; - } - state->offset=state->written % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_silence8(play_state_t* state, DWORD size) -{ - LPVOID ptr1,ptr2; - DWORD len1,len2; - HRESULT rc; - BYTE s; - - rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, - &ptr1,&len1,&ptr2,&len2,0); - ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - - s=(state->wfx->wBitsPerSample==8?0x80:0); - memset(ptr1,s,len1); - if (ptr2!=NULL) { - memset(ptr2,s,len2); - } - state->offset=(state->offset+size) % state->buffer_size; - rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); - ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return -1; - return size; -} - -static int buffer_service8(play_state_t* state) -{ - DWORD last_play_pos,play_pos,buf_free; - HRESULT rc; - - rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) { - goto STOP; - } - - /* Update the amount played */ - last_play_pos=state->played % state->buffer_size; - if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; - else - state->played+=play_pos-last_play_pos; - - if (winetest_debug > 1) - trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n", - state->buffer_size,last_play_pos,play_pos,state->played, - state->wave_len); - - if (state->played>state->wave_len) - { - /* Everything has been played */ - goto STOP; - } - - /* Refill the buffer */ - if (state->offset<=play_pos) - buf_free=play_pos-state->offset; - else - buf_free=state->buffer_size-state->offset+play_pos; - - if (winetest_debug > 1) - trace("offset=%ld free=%ld written=%ld / %ld\n", - state->offset,buf_free,state->written,state->wave_len); - if (buf_free==0) - return 1; - - if (state->writtenwave_len) - { - int w=buffer_refill8(state,buf_free); - if (w==-1) - goto STOP; - buf_free-=w; - if (state->written==state->wave_len && winetest_debug > 1) - trace("last sound byte at %ld\n", - (state->written % state->buffer_size)); - } - - if (buf_free>0) { - /* Fill with silence */ - if (winetest_debug > 1) - trace("writing %ld bytes of silence\n",buf_free); - if (buffer_silence8(state,buf_free)==-1) - goto STOP; - } - return 1; - -STOP: - if (winetest_debug > 1) - trace("stopping playback\n"); - rc=IDirectSoundBuffer_Stop(state->dsbo); - ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %s\n", - DXGetErrorString8(rc)); - return 0; -} - -void test_buffer8(LPDIRECTSOUND8 dso, LPDIRECTSOUNDBUFFER dsbo, - BOOL is_primary, BOOL set_volume, LONG volume, - BOOL set_pan, LONG pan, BOOL play, double duration, - BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, - BOOL move_listener, BOOL move_sound) -{ - HRESULT rc; - DSBCAPS dsbcaps; - WAVEFORMATEX wfx,wfx2; - DWORD size,status,freq; - int ref; - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - ZeroMemory(&dsbcaps, sizeof(dsbcaps)); - - /* DSOUND: Error: Invalid caps pointer */ - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - dsbcaps.dwSize=sizeof(dsbcaps); - rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); - ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, - dsbcaps.dwBufferBytes); - } - - /* Query the format size. Note that it may not match sizeof(wfx) */ - size=0; - rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); - ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " - "returned the needed size: rc=%s size=%ld\n",DXGetErrorString8(rc),size); - - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && winetest_debug > 1) { - trace(" Format: %s tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - is_primary ? "Primary" : "Secondary", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* DSOUND: Error: Invalid frequency buffer */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ - rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); - ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || - (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), - "IDirectSoundBuffer_GetFrequency() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency " - "%ld does not match the format %ld\n",freq,wfx.nSamplesPerSec); - } - - /* DSOUND: Error: Invalid status pointer */ - rc=IDirectSoundBuffer_GetStatus(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - ok(status==0,"status=0x%lx instead of 0\n",status); - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call SetFormat */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) " - "failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - /* DSOUND: Error: Invalid format pointer */ - rc=IDirectSoundBuffer_SetFormat(dsbo,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); - rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); - ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat() failed: %s\n", - DXGetErrorString8(rc)); - - /* There is no garantee that SetFormat will actually change the - * format to what we asked for. It depends on what the soundcard - * supports. So we must re-query the format. - */ - rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); - ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && - (wfx.wFormatTag!=wfx2.wFormatTag || - wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || - wfx.wBitsPerSample!=wfx2.wBitsPerSample || - wfx.nChannels!=wfx2.nChannels)) { - trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, - wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); - trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", - wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, - wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " - "failed: %s\n",DXGetErrorString8(rc)); - } - - if (play) { - play_state_t state; - DS3DLISTENER listener_param; - LPDIRECTSOUND3DBUFFER buffer=NULL; - DS3DBUFFER buffer_param; - DWORD start_time,now; - - if (winetest_interactive) { - trace(" Playing %g second 440Hz tone at %ldx%dx%d\n", duration, - wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); - } - - if (is_primary) { - /* We must call SetCooperativeLevel to be allowed to call Lock */ - /* DSOUND: Setting DirectSound cooperative level to - * DSSCL_WRITEPRIMARY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(), - DSSCL_WRITEPRIMARY); - ok(rc==DS_OK, - "IDirectSound8_SetCooperativeLevel(DSSCL_WRITEPRIMARY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - } - if (buffer3d) { - LPDIRECTSOUNDBUFFER temp_buffer; - - rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer, - (LPVOID *)&buffer); - ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return; - - /* check the COM interface */ - rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, - (LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - temp_buffer=NULL; - rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, - (LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSound3DBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==dsbo,"COM interface broken: 0x%08lx != 0x%08lx\n", - (DWORD)temp_buffer,(DWORD)dsbo); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - -#if 0 - /* FIXME: this works on windows */ - ref=IDirectSoundBuffer_Release(dsbo); - ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " - "should have 0\n",ref); - - rc=IDirectSound3DBuffer_QueryInterface(buffer, - &IID_IDirectSoundBuffer, - (LPVOID *)&dsbo); - ok(rc==DS_OK && dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " - "failed: %s\n",DXGetErrorString8(rc), -#endif - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - - ZeroMemory(&buffer_param, sizeof(buffer_param)); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - - buffer_param.dwSize=sizeof(buffer_param); - rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); - ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %s\n", - DXGetErrorString8(rc)); - } - if (set_volume) { - if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { - LONG val; - rc=IDirectSoundBuffer_GetVolume(dsbo,&val); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetVolume(dsbo,volume); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %s\n", - DXGetErrorString8(rc)); - } else { - /* DSOUND: Error: Buffer does not have CTRLVOLUME */ - rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); - ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " - "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", - DXGetErrorString8(rc)); - } - } - - if (set_pan) { - if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { - LONG val; - rc=IDirectSoundBuffer_GetPan(dsbo,&val); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetPan(dsbo,pan); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %s\n", - DXGetErrorString8(rc)); - } else { - /* DSOUND: Error: Buffer does not have CTRLPAN */ - rc=IDirectSoundBuffer_GetPan(dsbo,&pan); - ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " - "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", - DXGetErrorString8(rc)); - } - } - - state.wave=wave_generate_la(&wfx,duration,&state.wave_len); - - state.dsbo=dsbo; - state.wfx=&wfx; - state.buffer_size=dsbcaps.dwBufferBytes; - state.played=state.written=state.offset=0; - buffer_refill8(&state,state.buffer_size); - - rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); - ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetStatus(dsbo,&status); - ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", - DXGetErrorString8(rc)); - ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), - "GetStatus: bad status: %lx\n",status); - - if (listener) { - ZeroMemory(&listener_param,sizeof(listener_param)); - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - if (move_listener) { - listener_param.vPosition.x = -5.0; - listener_param.vVelocity.x = 10.0/duration; - } - rc=IDirectSound3DListener_SetAllParameters(listener, - &listener_param, - DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - if (buffer3d) { - if (move_sound) { - buffer_param.vPosition.x = 100.0; - buffer_param.vVelocity.x = -200.0/duration; - } - buffer_param.flMinDistance = 10; - rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, - DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - - start_time=GetTickCount(); - while (buffer_service8(&state)) { - WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); - now=GetTickCount(); - if (listener && move_listener) { - listener_param.vPosition.x = -5.0+10.0*(now-start_time)/ - 1000/duration; - if (winetest_debug>2) - trace("listener position=%g\n",listener_param.vPosition.x); - rc=IDirectSound3DListener_SetPosition(listener, - listener_param.vPosition.x,listener_param.vPosition.y, - listener_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: " - "%s\n",DXGetErrorString8(rc)); - } - if (buffer3d && move_sound) { - buffer_param.vPosition.x = 100-200.0*(now-start_time)/ - 1000/duration; - if (winetest_debug>2) - trace("sound position=%g\n",buffer_param.vPosition.x); - rc=IDirectSound3DBuffer_SetPosition(buffer, - buffer_param.vPosition.x,buffer_param.vPosition.y, - buffer_param.vPosition.z,DS3D_IMMEDIATE); - ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", - DXGetErrorString8(rc)); - } - } - /* Check the sound duration was within 10% of the expected value */ - now=GetTickCount(); - ok(fabs(1000*duration-now+start_time)<=100*duration, - "The sound played for %ld ms instead of %g ms\n", - now-start_time,1000*duration); - - free(state.wave); - if (is_primary) { - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " - "failed: %s\n",DXGetErrorString8(rc)); - } - if (buffer3d) { - ref=IDirectSound3DBuffer_Release(buffer); - ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " - "should have 0\n",ref); - } - } -} - -static HRESULT test_secondary8(LPGUID lpGuid, int play, - int has_3d, int has_3dbuffer, - int has_listener, int has_duplicate, - int move_listener, int move_sound) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - LPDIRECTSOUND3DLISTENER listener=NULL; - DSBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - int ref; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* We must call SetCooperativeLevel before creating primary buffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - if (has_3d) - bufdesc.dwFlags|=DSBCAPS_CTRL3D; - else - bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() " - "failed to create a %sprimary buffer: %s\n",has_3d?"3D ":"", - DXGetErrorString8(rc)); - - if (rc==DS_OK && primary!=NULL) { - if (has_listener) { - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSound3DListener, - (void **)&listener); - ok(rc==DS_OK && listener!=NULL, - "IDirectSoundBuffer_QueryInterface() failed to get a 3D " - "listener %s\n",DXGetErrorString8(rc)); - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - if (rc==DS_OK && listener!=NULL) { - DS3DLISTENER listener_param; - ZeroMemory(&listener_param,sizeof(listener_param)); - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound3dListener_GetAllParameters() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid buffer */ - rc=IDirectSound3DListener_GetAllParameters(listener, - &listener_param); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound3dListener_GetAllParameters() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - listener_param.dwSize=sizeof(listener_param); - rc=IDirectSound3DListener_GetAllParameters(listener, - &listener_param); - ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " - "failed: %s\n",DXGetErrorString8(rc)); - } - else - goto EXIT; - } - - init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); - secondary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; - if (has_3d) - bufdesc.dwFlags|=DSBCAPS_CTRL3D; - else - bufdesc.dwFlags|= - (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); - bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000; - bufdesc.lpwfxFormat=&wfx; - if (has_3d) { - /* a stereo 3D buffer should fail */ - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound8_CreateSoundBuffer(secondary) should have " - "returned DSERR_INVALIDPARAM, returned %s\n", - DXGetErrorString8(rc)); - if (secondary) - ref=IDirectSoundBuffer_Release(secondary); - init_format(&wfx,WAVE_FORMAT_PCM,22050,16,1); - } - - if (winetest_interactive) { - trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d\n", - has_3dbuffer?"3D ":"", - has_duplicate?"duplicated ":"", - listener!=NULL||move_sound?"with ":"", - move_listener?"moving ":"", - listener!=NULL?"listener ":"", - listener&&move_sound?"and moving sound ":move_sound? - "moving sound ":"", - wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); - } - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DS_OK && secondary!=NULL,"IDirectSound8_CreateSoundBuffer() " - "failed to create a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d (%s): %s\n", - has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", - listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", - listener!=NULL?"listener ":"", - listener&&move_sound?"and moving sound ":move_sound? - "moving sound ":"", - wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, - getDSBCAPS(bufdesc.dwFlags),DXGetErrorString8(rc)); - if (rc==DS_OK && secondary!=NULL) { - if (!has_3d) { - DWORD refpan,pan; - LONG refvol,vol; - - /* Check the initial secondary buffer's volume and pan */ - rc=IDirectSoundBuffer_GetVolume(secondary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(vol==0,"wrong volume for a new secondary buffer: %ld\n",vol); - rc=IDirectSoundBuffer_GetPan(secondary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(pan==0,"wrong pan for a new secondary buffer: %ld\n",pan); - - /* Check that changing the secondary buffer's volume and pan - * does not impact the primary buffer's volume and pan - */ - rc=IDirectSoundBuffer_GetVolume(primary,&refvol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetPan(primary,&refpan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: " - "%s\n",DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_SetVolume(secondary,-1000); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetVolume(secondary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(vol==-1000,"secondary: wrong volume %ld instead of -1000\n", - vol); - rc=IDirectSoundBuffer_SetPan(secondary,-1000); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_GetPan(secondary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(pan==-1000,"secondary: wrong pan %ld instead of -1000\n", - pan); - - rc=IDirectSoundBuffer_GetVolume(primary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_`GetVolume(primary) failed: i" - "%s\n",DXGetErrorString8(rc)); - ok(vol==refvol,"The primary volume changed from %ld to %ld\n", - refvol,vol); - rc=IDirectSoundBuffer_GetPan(primary,&pan); - ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: " - "%s\n",DXGetErrorString8(rc)); - ok(pan==refpan,"The primary pan changed from %ld to %ld\n", - refpan,pan); - - rc=IDirectSoundBuffer_SetVolume(secondary,0); - ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - rc=IDirectSoundBuffer_SetPan(secondary,0); - ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " - "%s\n",DXGetErrorString8(rc)); - } - if (has_duplicate) { - LPDIRECTSOUNDBUFFER duplicated=NULL; - - /* DSOUND: Error: Invalid source buffer */ - rc=IDirectSound8_DuplicateSoundBuffer(dso,0,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound8_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid dest buffer */ - rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,0); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound8_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid source buffer */ - rc=IDirectSound8_DuplicateSoundBuffer(dso,0,&duplicated); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound8_DuplicateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - duplicated=NULL; - rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary, - &duplicated); - ok(rc==DS_OK && duplicated!=NULL, - "IDirectSound8_DuplicateSoundBuffer() failed to duplicate " - "a secondary buffer: %s\n",DXGetErrorString8(rc)); - - if (rc==DS_OK && duplicated!=NULL) { - ref=IDirectSoundBuffer_Release(secondary); - ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " - "references, should have 0\n",ref); - secondary=duplicated; - } - } - - if (rc==DS_OK && secondary!=NULL) { - double duration; - duration=(move_listener || move_sound?4.0:1.0); - test_buffer8(dso,secondary,0,FALSE,0,FALSE,0, - winetest_interactive,duration,has_3dbuffer, - listener,move_listener,move_sound); - ref=IDirectSoundBuffer_Release(secondary); - ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " - "should have 0\n",has_duplicate?"duplicated":"secondary", - ref); - } - } - } - if (has_listener) { - ref=IDirectSound3DListener_Release(listener); - ok(ref==0,"IDirectSound3dListener_Release() listener has %d " - "references, should have 0\n",ref); - } else { - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " - "%s\n",DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_for_driver8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref, i; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* Testing the primary buffer */ - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " - "to create a primary buffer: 0x%lx\n",rc); - if (rc==DS_OK && primary!=NULL) { - test_buffer8(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); - if (winetest_interactive) { - LONG volume,pan; - - volume = DSBVOLUME_MAX; - for (i = 0; i < 6; i++) { - test_buffer8(dso,primary,1,TRUE,volume,TRUE,0, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER), - 1.0,0,NULL,0,0); - volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); - } - - pan = DSBPAN_LEFT; - for (i = 0; i < 7; i++) { - test_buffer8(dso,primary,1,TRUE,0,TRUE,pan, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); - pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); - } - } - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " - "%s\n",DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary_3d8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " - "to create a primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() " - "failed to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - test_buffer8(dso,primary,1,FALSE,0,FALSE,0, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - } - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " - "%s\n",DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -static HRESULT test_primary_3d_with_listener8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - int ref; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " - "%s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " - "to create a 3D primary buffer %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - LPDIRECTSOUND3DLISTENER listener=NULL; - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSound3DListener, - (void **)&listener); - ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " - "failed to get a 3D listener: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && listener!=NULL) { - LPDIRECTSOUNDBUFFER temp_buffer=NULL; - - /* Checking the COM interface */ - rc=IDirectSoundBuffer_QueryInterface(primary, - &IID_IDirectSoundBuffer, - (LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==primary,"COM interface broken: 0x%08lx != " - "0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary); - if (rc==DS_OK && temp_buffer!=NULL) { - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - temp_buffer=NULL; - rc=IDirectSound3DListener_QueryInterface(listener, - &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); - ok(rc==DS_OK && temp_buffer!=NULL, - "IDirectSoundBuffer_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - ok(temp_buffer==primary,"COM interface broken: 0x%08lx != " - "0x%08lx\n",(DWORD)temp_buffer,(DWORD)primary); - ref=IDirectSoundBuffer_Release(temp_buffer); - ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " - "should have 1\n",ref); - - /* Testing the buffer */ - test_buffer8(dso,primary,1,FALSE,0,FALSE,0, - winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER), - 1.0,0,listener,0,0); - } - - /* Testing the reference counting */ - ref=IDirectSound3DListener_Release(listener); - ok(ref==0,"IDirectSound3DListener_Release() listener has %d " - "references, should have 0\n",ref); - } - - /* Testing the reference counting */ - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - -EXIT: - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) -return DSERR_GENERIC; - - return rc; -} - -static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, - LPCSTR lpcstrModule, LPVOID lpContext) -{ - HRESULT rc; - trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); - - rc = test_for_driver8(lpGuid); - if (rc == DSERR_NODRIVER) { - trace(" No Driver\n"); - return 1; - } else if (rc == DSERR_ALLOCATED) { - trace(" Already In Use\n"); - return 1; - } - - trace(" Testing the primary buffer\n"); - test_primary8(lpGuid); - - trace(" Testing 3D primary buffer\n"); - test_primary_3d8(lpGuid); - - trace(" Testing 3D primary buffer with listener\n"); - test_primary_3d_with_listener8(lpGuid); - - /* Testing secondary buffers */ - test_secondary8(lpGuid,winetest_interactive,0,0,0,0,0,0); - test_secondary8(lpGuid,winetest_interactive,0,0,0,1,0,0); - - /* Testing 3D secondary buffers */ - test_secondary8(lpGuid,winetest_interactive,1,0,0,0,0,0); - test_secondary8(lpGuid,winetest_interactive,1,1,0,0,0,0); - test_secondary8(lpGuid,winetest_interactive,1,1,0,1,0,0); - test_secondary8(lpGuid,winetest_interactive,1,0,1,0,0,0); - test_secondary8(lpGuid,winetest_interactive,1,0,1,1,0,0); - test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,0); - test_secondary8(lpGuid,winetest_interactive,1,1,1,1,0,0); - test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,0); - test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,1); - test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,1); - - return 1; -} - -static void ds3d8_tests() -{ - HRESULT rc; - rc=DirectSoundEnumerateA(&dsenum_callback,NULL); - ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); -} - -START_TEST(ds3d8) -{ - HMODULE hDsound; - - CoInitialize(NULL); - - hDsound = LoadLibraryA("dsound.dll"); - if (!hDsound) { - trace("dsound.dll not found\n"); - return; - } - - pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, "DirectSoundCreate8"); - if (!pDirectSoundCreate8) { - trace("ds3d8 test skipped\n"); - return; - } - - ds3d8_tests(); -} +/* + * Tests the panning and 3D functions of DirectSound + * + * Part of this test involves playing test tones. But this only makes + * sense if someone is going to carefully listen to it, and would only + * bother everyone else. + * So this is only done if the test is being run in interactive mode. + * + * Copyright (c) 2002-2004 Francois Gouget + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#include + +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dxerr8.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +typedef struct { + char* wave; + DWORD wave_len; + + LPDIRECTSOUNDBUFFER dsbo; + LPWAVEFORMATEX wfx; + DWORD buffer_size; + DWORD written; + DWORD played; + DWORD offset; +} play_state_t; + +static int buffer_refill8(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + + if (size>state->wave_len-state->written) + size=state->wave_len-state->written; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + + memcpy(ptr1,state->wave+state->written,len1); + state->written+=len1; + if (ptr2!=NULL) { + memcpy(ptr2,state->wave+state->written,len2); + state->written+=len2; + } + state->offset=state->written % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_silence8(play_state_t* state, DWORD size) +{ + LPVOID ptr1,ptr2; + DWORD len1,len2; + HRESULT rc; + BYTE s; + + rc=IDirectSoundBuffer_Lock(state->dsbo,state->offset,size, + &ptr1,&len1,&ptr2,&len2,0); + ok(rc==DS_OK,"IDirectSoundBuffer_Lock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + + s=(state->wfx->wBitsPerSample==8?0x80:0); + memset(ptr1,s,len1); + if (ptr2!=NULL) { + memset(ptr2,s,len2); + } + state->offset=(state->offset+size) % state->buffer_size; + rc=IDirectSoundBuffer_Unlock(state->dsbo,ptr1,len1,ptr2,len2); + ok(rc==DS_OK,"IDirectSoundBuffer_Unlock() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return -1; + return size; +} + +static int buffer_service8(play_state_t* state) +{ + DWORD last_play_pos,play_pos,buf_free; + HRESULT rc; + + rc=IDirectSoundBuffer_GetCurrentPosition(state->dsbo,&play_pos,NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCurrentPosition() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + goto STOP; + } + + /* Update the amount played */ + last_play_pos=state->played % state->buffer_size; + if (play_posplayed+=state->buffer_size-last_play_pos+play_pos; + else + state->played+=play_pos-last_play_pos; + + if (winetest_debug > 1) + trace("buf size=%ld last_play_pos=%ld play_pos=%ld played=%ld / %ld\n", + state->buffer_size,last_play_pos,play_pos,state->played, + state->wave_len); + + if (state->played>state->wave_len) + { + /* Everything has been played */ + goto STOP; + } + + /* Refill the buffer */ + if (state->offset<=play_pos) + buf_free=play_pos-state->offset; + else + buf_free=state->buffer_size-state->offset+play_pos; + + if (winetest_debug > 1) + trace("offset=%ld free=%ld written=%ld / %ld\n", + state->offset,buf_free,state->written,state->wave_len); + if (buf_free==0) + return 1; + + if (state->writtenwave_len) + { + int w=buffer_refill8(state,buf_free); + if (w==-1) + goto STOP; + buf_free-=w; + if (state->written==state->wave_len && winetest_debug > 1) + trace("last sound byte at %ld\n", + (state->written % state->buffer_size)); + } + + if (buf_free>0) { + /* Fill with silence */ + if (winetest_debug > 1) + trace("writing %ld bytes of silence\n",buf_free); + if (buffer_silence8(state,buf_free)==-1) + goto STOP; + } + return 1; + +STOP: + if (winetest_debug > 1) + trace("stopping playback\n"); + rc=IDirectSoundBuffer_Stop(state->dsbo); + ok(rc==DS_OK,"IDirectSoundBuffer_Stop() failed: %s\n", + DXGetErrorString8(rc)); + return 0; +} + +void test_buffer8(LPDIRECTSOUND8 dso, LPDIRECTSOUNDBUFFER dsbo, + BOOL is_primary, BOOL set_volume, LONG volume, + BOOL set_pan, LONG pan, BOOL play, double duration, + BOOL buffer3d, LPDIRECTSOUND3DLISTENER listener, + BOOL move_listener, BOOL move_sound) +{ + HRESULT rc; + DSBCAPS dsbcaps; + WAVEFORMATEX wfx,wfx2; + DWORD size,status,freq; + int ref; + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + ZeroMemory(&dsbcaps, sizeof(dsbcaps)); + + /* DSOUND: Error: Invalid caps pointer */ + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetCaps() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + dsbcaps.dwSize=sizeof(dsbcaps); + rc=IDirectSoundBuffer_GetCaps(dsbo,&dsbcaps); + ok(rc==DS_OK,"IDirectSoundBuffer_GetCaps() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Caps: flags=0x%08lx size=%ld\n",dsbcaps.dwFlags, + dsbcaps.dwBufferBytes); + } + + /* Query the format size. Note that it may not match sizeof(wfx) */ + size=0; + rc=IDirectSoundBuffer_GetFormat(dsbo,NULL,0,&size); + ok(rc==DS_OK && size!=0,"IDirectSoundBuffer_GetFormat() should have " + "returned the needed size: rc=%s size=%ld\n",DXGetErrorString8(rc),size); + + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && winetest_debug > 1) { + trace(" Format: %s tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + is_primary ? "Primary" : "Secondary", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* DSOUND: Error: Invalid frequency buffer */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetFrequency() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Primary buffers don't support CTRLFREQUENCY */ + rc=IDirectSoundBuffer_GetFrequency(dsbo,&freq); + ok((rc==DS_OK && !is_primary) || (rc==DSERR_CONTROLUNAVAIL&&is_primary) || + (rc==DSERR_CONTROLUNAVAIL&&!(dsbcaps.dwFlags&DSBCAPS_CTRLFREQUENCY)), + "IDirectSoundBuffer_GetFrequency() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + ok(freq==wfx.nSamplesPerSec,"The frequency returned by GetFrequency " + "%ld does not match the format %ld\n",freq,wfx.nSamplesPerSec); + } + + /* DSOUND: Error: Invalid status pointer */ + rc=IDirectSoundBuffer_GetStatus(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_GetStatus() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + ok(status==0,"status=0x%lx instead of 0\n",status); + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call SetFormat */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) " + "failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + /* DSOUND: Error: Invalid format pointer */ + rc=IDirectSoundBuffer_SetFormat(dsbo,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSoundBuffer_SetFormat() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + init_format(&wfx2,WAVE_FORMAT_PCM,11025,16,2); + rc=IDirectSoundBuffer_SetFormat(dsbo,&wfx2); + ok(rc==DS_OK,"IDirectSoundBuffer_SetFormat() failed: %s\n", + DXGetErrorString8(rc)); + + /* There is no garantee that SetFormat will actually change the + * format to what we asked for. It depends on what the soundcard + * supports. So we must re-query the format. + */ + rc=IDirectSoundBuffer_GetFormat(dsbo,&wfx,sizeof(wfx),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer_GetFormat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && + (wfx.wFormatTag!=wfx2.wFormatTag || + wfx.nSamplesPerSec!=wfx2.nSamplesPerSec || + wfx.wBitsPerSample!=wfx2.wBitsPerSample || + wfx.nChannels!=wfx2.nChannels)) { + trace("Requested format tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx2.wFormatTag,wfx2.nSamplesPerSec,wfx2.wBitsPerSample, + wfx2.nChannels,wfx2.nAvgBytesPerSec,wfx2.nBlockAlign); + trace("Got tag=0x%04x %ldx%dx%d avg.B/s=%ld align=%d\n", + wfx.wFormatTag,wfx.nSamplesPerSec,wfx.wBitsPerSample, + wfx.nChannels,wfx.nAvgBytesPerSec,wfx.nBlockAlign); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %s\n",DXGetErrorString8(rc)); + } + + if (play) { + play_state_t state; + DS3DLISTENER listener_param; + LPDIRECTSOUND3DBUFFER buffer=NULL; + DS3DBUFFER buffer_param; + DWORD start_time,now; + + if (winetest_interactive) { + trace(" Playing %g second 440Hz tone at %ldx%dx%d\n", duration, + wfx.nSamplesPerSec, wfx.wBitsPerSample,wfx.nChannels); + } + + if (is_primary) { + /* We must call SetCooperativeLevel to be allowed to call Lock */ + /* DSOUND: Setting DirectSound cooperative level to + * DSSCL_WRITEPRIMARY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(), + DSSCL_WRITEPRIMARY); + ok(rc==DS_OK, + "IDirectSound8_SetCooperativeLevel(DSSCL_WRITEPRIMARY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + } + if (buffer3d) { + LPDIRECTSOUNDBUFFER temp_buffer; + + rc=IDirectSoundBuffer_QueryInterface(dsbo,&IID_IDirectSound3DBuffer, + (LPVOID *)&buffer); + ok(rc==DS_OK,"IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return; + + /* check the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==dsbo,"COM interface broken: %p != %p\n", + temp_buffer,dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DBuffer_QueryInterface(dsbo, &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSound3DBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==dsbo,"COM interface broken: %p != %p\n", + temp_buffer,dsbo); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + +#if 0 + /* FIXME: this works on windows */ + ref=IDirectSoundBuffer_Release(dsbo); + ok(ref==0,"IDirectSoundBuffer_Release() has %d references, " + "should have 0\n",ref); + + rc=IDirectSound3DBuffer_QueryInterface(buffer, + &IID_IDirectSoundBuffer, + (LPVOID *)&dsbo); + ok(rc==DS_OK && dsbo!=NULL,"IDirectSound3DBuffer_QueryInterface() " + "failed: %s\n",DXGetErrorString8(rc), +#endif + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + + ZeroMemory(&buffer_param, sizeof(buffer_param)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound3DBuffer_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + + buffer_param.dwSize=sizeof(buffer_param); + rc=IDirectSound3DBuffer_GetAllParameters(buffer,&buffer_param); + ok(rc==DS_OK,"IDirectSound3DBuffer_GetAllParameters() failed: %s\n", + DXGetErrorString8(rc)); + } + if (set_volume) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLVOLUME) { + LONG val; + rc=IDirectSoundBuffer_GetVolume(dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetVolume(dsbo,volume); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume() failed: %s\n", + DXGetErrorString8(rc)); + } else { + /* DSOUND: Error: Buffer does not have CTRLVOLUME */ + rc=IDirectSoundBuffer_GetVolume(dsbo,&volume); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetVolume() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", + DXGetErrorString8(rc)); + } + } + + if (set_pan) { + if (dsbcaps.dwFlags & DSBCAPS_CTRLPAN) { + LONG val; + rc=IDirectSoundBuffer_GetPan(dsbo,&val); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetPan(dsbo,pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan() failed: %s\n", + DXGetErrorString8(rc)); + } else { + /* DSOUND: Error: Buffer does not have CTRLPAN */ + rc=IDirectSoundBuffer_GetPan(dsbo,&pan); + ok(rc==DSERR_CONTROLUNAVAIL,"IDirectSoundBuffer_GetPan() " + "should have returned DSERR_CONTROLUNAVAIL, returned: %s\n", + DXGetErrorString8(rc)); + } + } + + state.wave=wave_generate_la(&wfx,duration,&state.wave_len); + + state.dsbo=dsbo; + state.wfx=&wfx; + state.buffer_size=dsbcaps.dwBufferBytes; + state.played=state.written=state.offset=0; + buffer_refill8(&state,state.buffer_size); + + rc=IDirectSoundBuffer_Play(dsbo,0,0,DSBPLAY_LOOPING); + ok(rc==DS_OK,"IDirectSoundBuffer_Play() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetStatus(dsbo,&status); + ok(rc==DS_OK,"IDirectSoundBuffer_GetStatus() failed: %s\n", + DXGetErrorString8(rc)); + ok(status==(DSBSTATUS_PLAYING|DSBSTATUS_LOOPING), + "GetStatus: bad status: %lx\n",status); + + if (listener) { + ZeroMemory(&listener_param,sizeof(listener_param)); + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener,&listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + if (move_listener) { + listener_param.vPosition.x = -5.0; + listener_param.vVelocity.x = 10.0/duration; + } + rc=IDirectSound3DListener_SetAllParameters(listener, + &listener_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + if (buffer3d) { + if (move_sound) { + buffer_param.vPosition.x = 100.0; + buffer_param.vVelocity.x = -200.0/duration; + } + buffer_param.flMinDistance = 10; + rc=IDirectSound3DBuffer_SetAllParameters(buffer,&buffer_param, + DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + + start_time=GetTickCount(); + while (buffer_service8(&state)) { + WaitForSingleObject(GetCurrentProcess(),TIME_SLICE); + now=GetTickCount(); + if (listener && move_listener) { + listener_param.vPosition.x = -5.0+10.0*(now-start_time)/ + 1000/duration; + if (winetest_debug>2) + trace("listener position=%g\n",listener_param.vPosition.x); + rc=IDirectSound3DListener_SetPosition(listener, + listener_param.vPosition.x,listener_param.vPosition.y, + listener_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dListener_SetPosition() failed: " + "%s\n",DXGetErrorString8(rc)); + } + if (buffer3d && move_sound) { + buffer_param.vPosition.x = 100-200.0*(now-start_time)/ + 1000/duration; + if (winetest_debug>2) + trace("sound position=%g\n",buffer_param.vPosition.x); + rc=IDirectSound3DBuffer_SetPosition(buffer, + buffer_param.vPosition.x,buffer_param.vPosition.y, + buffer_param.vPosition.z,DS3D_IMMEDIATE); + ok(rc==DS_OK,"IDirectSound3dBuffer_SetPosition() failed: %s\n", + DXGetErrorString8(rc)); + } + } + /* Check the sound duration was within 10% of the expected value */ + now=GetTickCount(); + ok(fabs(1000*duration-now+start_time)<=100*duration, + "The sound played for %ld ms instead of %g ms\n", + now-start_time,1000*duration); + + free(state.wave); + if (is_primary) { + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) " + "failed: %s\n",DXGetErrorString8(rc)); + } + if (buffer3d) { + ref=IDirectSound3DBuffer_Release(buffer); + ok(ref==0,"IDirectSound3DBuffer_Release() has %d references, " + "should have 0\n",ref); + } + } +} + +static HRESULT test_secondary8(LPGUID lpGuid, int play, + int has_3d, int has_3dbuffer, + int has_listener, int has_duplicate, + int move_listener, int move_sound) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + LPDIRECTSOUND3DLISTENER listener=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx, wfx1; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|=(DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a %sprimary buffer: " + "%s\n",has_3d?"3D ":"", DXGetErrorString8(rc)); + if (rc == DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + rc=IDirectSoundBuffer_GetFormat(primary,&wfx1,sizeof(wfx1),NULL); + ok(rc==DS_OK,"IDirectSoundBuffer8_Getformat() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT1; + + if (has_listener) { + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL, + "IDirectSoundBuffer_QueryInterface() failed to get a 3D " + "listener %s\n",DXGetErrorString8(rc)); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + if (rc==DS_OK && listener!=NULL) { + DS3DLISTENER listener_param; + ZeroMemory(&listener_param,sizeof(listener_param)); + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid buffer */ + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound3dListener_GetAllParameters() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + listener_param.dwSize=sizeof(listener_param); + rc=IDirectSound3DListener_GetAllParameters(listener, + &listener_param); + ok(rc==DS_OK,"IDirectSound3dListener_GetAllParameters() " + "failed: %s\n",DXGetErrorString8(rc)); + } + else + goto EXIT; + } + + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,2); + secondary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2; + if (has_3d) + bufdesc.dwFlags|=DSBCAPS_CTRL3D; + else + bufdesc.dwFlags|= + (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN); + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + if (has_3d) { + /* a stereo 3D buffer should fail */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer(secondary) should have " + "returned DSERR_INVALIDPARAM, returned %s\n", + DXGetErrorString8(rc)); + if (secondary) + ref=IDirectSoundBuffer_Release(secondary); + init_format(&wfx,WAVE_FORMAT_PCM,22050,16,1); + } + + if (winetest_interactive) { + trace(" Testing a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d " + "with a primary buffer at %ldx%dx%d\n", + has_3dbuffer?"3D ":"", + has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", + move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + wfx1.nSamplesPerSec,wfx1.wBitsPerSample,wfx1.nChannels); + } + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL,"IDirectSound8_CreateSoundBuffer() " + "failed to create a %s%ssecondary buffer %s%s%s%sat %ldx%dx%d (%s): %s\n", + has_3dbuffer?"3D ":"", has_duplicate?"duplicated ":"", + listener!=NULL||move_sound?"with ":"", move_listener?"moving ":"", + listener!=NULL?"listener ":"", + listener&&move_sound?"and moving sound ":move_sound? + "moving sound ":"", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels, + getDSBCAPS(bufdesc.dwFlags),DXGetErrorString8(rc)); + if (rc==DS_OK && secondary!=NULL) { + if (!has_3d) { + LONG refvol,vol,refpan,pan; + + /* Check the initial secondary buffer's volume and pan */ + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(vol==0,"wrong volume for a new secondary buffer: %ld\n",vol); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(pan==0,"wrong pan for a new secondary buffer: %ld\n",pan); + + /* Check that changing the secondary buffer's volume and pan + * does not impact the primary buffer's volume and pan + */ + rc=IDirectSoundBuffer_GetVolume(primary,&refvol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume(primary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetPan(primary,&refpan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: " + "%s\n",DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_SetVolume(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetVolume(secondary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(vol==-1000,"secondary: wrong volume %ld instead of -1000\n", + vol); + rc=IDirectSoundBuffer_SetPan(secondary,-1000); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_GetPan(secondary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(pan==-1000,"secondary: wrong pan %ld instead of -1000\n", + pan); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_`GetVolume(primary) failed: i" + "%s\n",DXGetErrorString8(rc)); + ok(vol==refvol,"The primary volume changed from %ld to %ld\n", + refvol,vol); + rc=IDirectSoundBuffer_GetPan(primary,&pan); + ok(rc==DS_OK,"IDirectSoundBuffer_GetPan(primary) failed: " + "%s\n",DXGetErrorString8(rc)); + ok(pan==refpan,"The primary pan changed from %ld to %ld\n", + refpan,pan); + + rc=IDirectSoundBuffer_SetVolume(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetVolume(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + rc=IDirectSoundBuffer_SetPan(secondary,0); + ok(rc==DS_OK,"IDirectSoundBuffer_SetPan(secondary) failed: " + "%s\n",DXGetErrorString8(rc)); + } + if (has_duplicate) { + LPDIRECTSOUNDBUFFER duplicated=NULL; + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,0,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid dest buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary,0); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid source buffer */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,0,&duplicated); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_DuplicateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + duplicated=NULL; + rc=IDirectSound8_DuplicateSoundBuffer(dso,secondary, + &duplicated); + ok(rc==DS_OK && duplicated!=NULL, + "IDirectSound8_DuplicateSoundBuffer() failed to duplicate " + "a secondary buffer: %s\n",DXGetErrorString8(rc)); + + if (rc==DS_OK && duplicated!=NULL) { + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + secondary=duplicated; + } + } + + if (rc==DS_OK && secondary!=NULL) { + double duration; + duration=(move_listener || move_sound?4.0:1.0); + test_buffer8(dso,secondary,0,FALSE,0,FALSE,0, + winetest_interactive,duration,has_3dbuffer, + listener,move_listener,move_sound); + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() %s has %d references, " + "should have 0\n",has_duplicate?"duplicated":"secondary", + ref); + } + } + } +EXIT1: + if (has_listener) { + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3dListener_Release() listener has %d " + "references, should have 0\n",ref); + } else { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " + "%s\n",DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_for_driver8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref, i; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc == DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: " + "%s\n",DXGetErrorString8(rc)); + if (rc == DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + test_buffer8(dso,primary,1,TRUE,0,TRUE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,NULL,0,0); + if (winetest_interactive) { + LONG volume,pan; + + volume = DSBVOLUME_MAX; + for (i = 0; i < 6; i++) { + test_buffer8(dso,primary,1,TRUE,volume,TRUE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,NULL,0,0); + volume -= ((DSBVOLUME_MAX-DSBVOLUME_MIN) / 40); + } + + pan = DSBPAN_LEFT; + for (i = 0; i < 7; i++) { + test_buffer8(dso,primary,1,TRUE,0,TRUE,pan, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + pan += ((DSBPAN_RIGHT-DSBPAN_LEFT) / 6); + } + } + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " + "%s\n",DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " + "to create a primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() " + "failed to create a 3D primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + test_buffer8(dso,primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),1.0,0,0,0,0); + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + } + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_NORMAL) failed: " + "%s\n",DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +static HRESULT test_primary_3d_with_listener8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER,"DirectSoundCreate8() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel(DSSCL_PRIORITY) failed: " + "%s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL,"IDirectSound8_CreateSoundBuffer() failed " + "to create a 3D primary buffer %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) { + LPDIRECTSOUND3DLISTENER listener=NULL; + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSound3DListener, + (void **)&listener); + ok(rc==DS_OK && listener!=NULL,"IDirectSoundBuffer_QueryInterface() " + "failed to get a 3D listener: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && listener!=NULL) { + LPDIRECTSOUNDBUFFER temp_buffer=NULL; + + /* Checking the COM interface */ + rc=IDirectSoundBuffer_QueryInterface(primary, + &IID_IDirectSoundBuffer, + (LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary); + if (rc==DS_OK && temp_buffer!=NULL) { + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + temp_buffer=NULL; + rc=IDirectSound3DListener_QueryInterface(listener, + &IID_IDirectSoundBuffer,(LPVOID *)&temp_buffer); + ok(rc==DS_OK && temp_buffer!=NULL, + "IDirectSoundBuffer_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + ok(temp_buffer==primary,"COM interface broken: %p != %p\n",temp_buffer,primary); + ref=IDirectSoundBuffer_Release(temp_buffer); + ok(ref==1,"IDirectSoundBuffer_Release() has %d references, " + "should have 1\n",ref); + + /* Testing the buffer */ + test_buffer8(dso,primary,1,FALSE,0,FALSE,0, + winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER), + 1.0,0,listener,0,0); + } + + /* Testing the reference counting */ + ref=IDirectSound3DListener_Release(listener); + ok(ref==0,"IDirectSound3DListener_Release() listener has %d " + "references, should have 0\n",ref); + } + + /* Testing the reference counting */ + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) +return DSERR_GENERIC; + + return rc; +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc = test_for_driver8(lpGuid); + if (rc == DSERR_NODRIVER) { + trace(" No Driver\n"); + return 1; + } else if (rc == DSERR_ALLOCATED) { + trace(" Already In Use\n"); + return 1; + } else if (rc == E_FAIL) { + trace(" No Device\n"); + return 1; + } + + trace(" Testing the primary buffer\n"); + test_primary8(lpGuid); + + trace(" Testing 3D primary buffer\n"); + test_primary_3d8(lpGuid); + + trace(" Testing 3D primary buffer with listener\n"); + test_primary_3d_with_listener8(lpGuid); + + /* Testing secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,0,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,0,0,0,1,0,0); + + /* Testing 3D secondary buffers */ + test_secondary8(lpGuid,winetest_interactive,1,0,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,0,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,0,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,1,0,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,0); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,0,1); + test_secondary8(lpGuid,winetest_interactive,1,1,1,0,1,1); + + return 1; +} + +static void ds3d8_tests(void) +{ + HRESULT rc; + rc=DirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); +} + +START_TEST(ds3d8) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibraryA("dsound.dll"); + if (!hDsound) { + trace("dsound.dll not found\n"); + return; + } + + trace("DLL Version: %s\n", get_file_version("dsound.dll")); + + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, "DirectSoundCreate8"); + if (!pDirectSoundCreate8) { + trace("ds3d8 test skipped\n"); + return; + } + + ds3d8_tests(); + + CoUninitialize(); +} diff --git a/reactos/lib/dsound/tests/dsound.c b/reactos/lib/dsound/tests/dsound.c index 51a70c870ec..a353acf3e92 100644 --- a/reactos/lib/dsound/tests/dsound.c +++ b/reactos/lib/dsound/tests/dsound.c @@ -1,759 +1,947 @@ -/* - * Tests basic sound playback in DirectSound. - * In particular we test each standard Windows sound format to make sure - * we handle the sound card/driver quirks correctly. - * - * Part of this test involves playing test tones. But this only makes - * sense if someone is going to carefully listen to it, and would only - * bother everyone else. - * So this is only done if the test is being run in interactive mode. - * - * Copyright (c) 2002-2004 Francois Gouget - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSSTRUCT -#define NONAMELESSUNION -#include - -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "dxerr8.h" -#include "dsconf.h" - -#include "dsound_test.h" - -static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, - LPCGUID lpGuid) -{ - HRESULT rc; - DSCAPS dscaps; - int ref; - IUnknown * unknown; - IDirectSound * ds; - IDirectSound8 * ds8; - DWORD speaker_config, new_speaker_config; - - /* Try to Query for objects */ - rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); - ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound_Release(unknown); - - rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); - ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound_Release(ds); - - rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); - ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) " - "should have failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound8_Release(ds8); - - if (initialized == FALSE) { - /* try unitialized object */ - rc=IDirectSound_GetCaps(dso,0); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_Compact(dso); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_Initialize(dso,lpGuid); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "IDirectSound_Initialize() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DSERR_NODRIVER) { - trace(" No Driver\n"); - return; - } else if (rc==DSERR_ALLOCATED) { - trace(" Already Allocated\n"); - return; - } - } - - /* DSOUND: Error: Invalid caps buffer */ - rc=IDirectSound_GetCaps(dso,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - ZeroMemory(&dscaps, sizeof(dscaps)); - - /* DSOUND: Error: Invalid caps buffer */ - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - dscaps.dwSize=sizeof(dscaps); - - /* DSOUND: Running on a certified driver */ - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSound_Compact(dso); - ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_Compact(dso); - ok(rc==DS_OK,"IDirectSound_Compact() failed: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSound_GetSpeakerConfig(dso,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); - ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - - speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, - DSSPEAKER_GEOMETRY_WIDE); - rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); - ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); - ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && speaker_config!=new_speaker_config) - trace("IDirectSound_GetSpeakerConfig() failed to set speaker " - "config: expected 0x%08lx, got 0x%08lx\n", - speaker_config,new_speaker_config); - } - - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); -} - -static void IDirectSound_tests() -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - - trace("Testing IDirectSound\n"); - - /* try the COM class factory method of creation with no device specified */ - rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound_test(dso, FALSE, NULL); - - /* try the COM class factory method of creation with default playback - * device specified */ - rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback); - - /* try the COM class factory method of creation with default voice - * playback device specified */ - rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); - - /* try the COM class factory method of creation with a bad - * IID specified */ - rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &CLSID_DirectSoundPrivate, (void**)&dso); - ok(rc==E_NOINTERFACE, - "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) " - "should have failed: %s\n",DXGetErrorString8(rc)); - - /* try the COM class factory method of creation with a bad - * GUID and IID specified */ - rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&dso); - ok(rc==REGDB_E_CLASSNOTREG, - "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) " - "should have failed: %s\n",DXGetErrorString8(rc)); - - /* try with no device specified */ - rc=DirectSoundCreate(NULL,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate(NULL) failed: %s\n",DXGetErrorString8(rc)); - if (rc==S_OK && dso) - IDirectSound_test(dso, TRUE, NULL); - - /* try with default playback device specified */ - rc=DirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && dso) - IDirectSound_test(dso, TRUE, NULL); - - /* try with default voice playback device specified */ - rc=DirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && dso) - IDirectSound_test(dso, TRUE, NULL); - - /* try with a bad device specified */ - rc=DirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL); - ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) " - "should have failed: %s\n",DXGetErrorString8(rc)); -} - -static HRESULT test_dsound(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - int ref; - - /* DSOUND: Error: Invalid interface buffer */ - rc=DirectSoundCreate(lpGuid,0,NULL); - ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Try the enumerated device */ - IDirectSound_test(dso, TRUE, lpGuid); - - /* Try the COM class factory method of creation with enumerated device */ - rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound_test(dso, FALSE, lpGuid); - - /* Create a DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - LPDIRECTSOUND dso1=NULL; - - /* Create a second DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso1,NULL); - ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - /* Release the second DirectSound object */ - ref=IDirectSound_Release(dso1); - ok(ref==0,"IDirectSound_Release() has %d references, should have " - "0\n",ref); - ok(dso!=dso1,"DirectSound objects should be unique: " - "dso=0x%08lx,dso1=0x%08lx\n",(DWORD)dso,(DWORD)dso1); - } - - /* Release the first DirectSound object */ - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", - ref); - if (ref!=0) - return DSERR_GENERIC; - } else - return rc; - - /* Create a DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - LPDIRECTSOUNDBUFFER secondary; - DSBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - - init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; - bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000; - bufdesc.lpwfxFormat=&wfx; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DS_OK && secondary!=NULL, - "IDirectSound_CreateSoundBuffer() failed to create a secondary " - "buffer %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && secondary!=NULL) { - LPDIRECTSOUND3DBUFFER buffer3d; - rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer, - (void **)&buffer3d); - ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() " - "failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && buffer3d!=NULL) { - ref=IDirectSound3DBuffer_AddRef(buffer3d); - ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " - "should have 2\n",ref); - } - ref=IDirectSoundBuffer_AddRef(secondary); - ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, " - "should have 2\n",ref); - } - /* release with buffer */ - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", - ref); - if (ref!=0) - return DSERR_GENERIC; - } else - return rc; - - return DS_OK; -} - -static HRESULT test_primary(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx; - int ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound_CreateSoundBuffer() should have failed: %s\n", - DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," - "dsbo=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary); - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,0,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," - "dsbo=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary); - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - - /* DSOUND: Error: Invalid size */ - /* DSOUND: Error: Invalid buffer description */ - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," - "primary=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary); - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* Testing the primary buffer */ - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; - bufdesc.lpwfxFormat = &wfx; - init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) - IDirectSoundBuffer_Release(primary); - - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL, - "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: " - "%s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - LONG vol; - - /* Try to create a second primary buffer */ - /* DSOUND: Error: The primary buffer already exists. - * Any changes made to the buffer description will be ignored. */ - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL); - ok(rc==DS_OK && second==primary, - "IDirectSound_CreateSoundBuffer() should have returned original " - "primary buffer: %s\n",DXGetErrorString8(rc)); - ref=IDirectSoundBuffer_Release(second); - ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 1\n",ref); - - /* Try to duplicate a primary buffer */ - /* DSOUND: Error: Can't duplicate primary buffers */ - rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third); - /* rc=0x88780032 */ - ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer " - "should have failed %s\n",DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetVolume(primary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", - DXGetErrorString8(rc)); - - if (winetest_interactive) { - trace("Playing a 5 seconds reference tone at the current " - "volume.\n"); - if (rc==DS_OK) - trace("(the current volume is %ld according to DirectSound)\n", - vol); - trace("All subsequent tones should be identical to this one.\n"); - trace("Listen for stutter, changes in pitch, volume, etc.\n"); - } - test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0); - - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -/* - * Test the primary buffer at different formats while keeping the - * secondary buffer at a constant format. - */ -static HRESULT test_primary_secondary(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx, wfx2; - int f,ref; - - /* Create the DirectSound object */ - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before creating primary buffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL, - "IDirectSound_CreateSoundBuffer() failed to create a primary buffer " - "%s\n",DXGetErrorString8(rc)); - - if (rc==DS_OK && primary!=NULL) { - for (f=0;f + +#include "wine/test.h" +#include "dsound.h" +#include "dxerr8.h" +#include "dsconf.h" + +#include "dsound_test.h" + +static void IDirectSound_test(LPDIRECTSOUND dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + + /* Try to Query for objects */ + rc=IDirectSound_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IUnknown) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound_Release(unknown); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound_QueryInterface(IID_IDirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==E_NOINTERFACE,"IDirectSound_QueryInterface(IID_IDirectSound8) " + "should have failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try unitialized object */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound_Initialize() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSound_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound_Compact() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_Compact(dso); + ok(rc==DS_OK,"IDirectSound_Compact() failed: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSound_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound_SetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + rc=IDirectSound_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound_GetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08lx, got 0x%08lx\n", + speaker_config,new_speaker_config); + } + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + + trace("Testing IDirectSound\n"); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound,CLSID_DirectSoundPrivate) " + "should have failed: %s\n",DXGetErrorString8(rc)); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound) " + "should have failed: %s\n",DXGetErrorString8(rc)); + + /* try with no device specified */ + rc=DirectSoundCreate(NULL,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(NULL) failed: %s\n",DXGetErrorString8(rc)); + if (rc==S_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=DirectSoundCreate(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultPlayback) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=DirectSoundCreate(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate(DSDEVID_DefaultVoicePlayback) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=DirectSoundCreate(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate(DSDEVID_DefaultVoiceCapture) " + "should have failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound_Release(dso); +} + +static HRESULT test_dsound(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=DirectSoundCreate(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Try the enumerated device */ + IDirectSound_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound_test(dso, FALSE, lpGuid); + + /* Create a DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + LPDIRECTSOUND dso1=NULL; + + /* Create a second DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + /* Release the second DirectSound object */ + ref=IDirectSound_Release(dso1); + ok(ref==0,"IDirectSound_Release() has %d references, should have " + "0\n",ref); + ok(dso!=dso1,"DirectSound objects should be unique: dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound object */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a secondary " + "buffer %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + rc=IDirectSound_QueryInterface(secondary, &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL,"IDirectSound_QueryInterface() " + "failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==2,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + /* release with buffer */ + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound_CreateSoundBuffer() should have failed: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," + "dsbo=%p\n",DXGetErrorString8(rc),primary); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,0,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," + "dsbo=0x%p\n",DXGetErrorString8(rc),primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound_CreateSoundBuffer() should have failed: rc=%s," + "primary=%p\n",DXGetErrorString8(rc),primary); + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer: " + "%s\n",DXGetErrorString8(rc)); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound_CreateSoundBuffer() should have returned original " + "primary buffer: %s\n",DXGetErrorString8(rc)); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound_DuplicateSoundBuffer() primary buffer " + "should have failed %s\n",DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", + DXGetErrorString8(rc)); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current " + "volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %ld according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0,FALSE,0); + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int f,ref; + + /* Create the DirectSound object */ + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound_CreateSoundBuffer() failed to create a primary buffer " + "%s\n",DXGetErrorString8(rc)); + + if (rc==DS_OK && primary!=NULL) { + for (f=0;f - -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "dxerr8.h" -#include "dsconf.h" - -#include "dsound_test.h" - -static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; - -static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, - LPCGUID lpGuid) -{ - HRESULT rc; - DSCAPS dscaps; - int ref; - IUnknown * unknown; - IDirectSound * ds; - IDirectSound8 * ds8; - DWORD speaker_config, new_speaker_config; - DWORD certified; - - /* Try to Query for objects */ - rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); - ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound8_Release(unknown); - - rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); - ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound_Release(ds); - - rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); - ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) - IDirectSound8_Release(ds8); - - if (initialized == FALSE) { - /* try unitialized object */ - rc=IDirectSound8_GetCaps(dso,0); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_Compact(dso); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_VerifyCertification(dso, &certified); - ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() " - "should have returned DSERR_UNINITIALIZED, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_Initialize(dso,lpGuid); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "IDirectSound8_Initialize() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DSERR_NODRIVER) { - trace(" No Driver\n"); - return; - } else if (rc==DSERR_ALLOCATED) { - trace(" Already In Use\n"); - return; - } - } - - /* DSOUND: Error: Invalid caps buffer */ - rc=IDirectSound8_GetCaps(dso,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - ZeroMemory(&dscaps, sizeof(dscaps)); - - /* DSOUND: Error: Invalid caps buffer */ - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - dscaps.dwSize=sizeof(dscaps); - - /* DSOUND: Running on a certified driver */ - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSound8_Compact(dso); - ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_Compact(dso); - ok(rc==DS_OK,"IDirectSound8_Compact() failed: %s\n",DXGetErrorString8(rc)); - - rc=IDirectSound8_GetSpeakerConfig(dso,0); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) " - "should have returned DSERR_INVALIDPARAM, returned: %s\n", - DXGetErrorString8(rc)); - - rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); - ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - - speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, - DSSPEAKER_GEOMETRY_WIDE); - rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); - ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK) { - rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config); - ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && speaker_config!=new_speaker_config) - trace("IDirectSound8_GetSpeakerConfig() failed to set speaker " - "config: expected 0x%08lx, got 0x%08lx\n", - speaker_config,new_speaker_config); - } - - rc=IDirectSound8_VerifyCertification(dso, &certified); - ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %s\n", - DXGetErrorString8(rc)); - - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); -} - -static void IDirectSound8_tests() -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - - trace("Testing IDirectSound8\n"); - - /* try the COM class factory method of creation with no device specified */ - rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound8, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance() failed: %s\n",DXGetErrorString8(rc)); - if (dso) - IDirectSound8_test(dso, FALSE, NULL); - - /* try the COM class factory method of creation with default playback - * device specified */ - rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound8, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback); - - /* try the COM class factory method of creation with default voice - * playback device specified */ - rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound8, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); - - /* try the COM class factory method of creation with a bad - * IID specified */ - rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, - &CLSID_DirectSoundPrivate, (void**)&dso); - ok(rc==E_NOINTERFACE, - "CoCreateInstance(CLSID_DirectSound8,CLSID_DirectSoundPrivate) " - "should have failed: %s\n",DXGetErrorString8(rc)); - - /* try the COM class factory method of creation with a bad - * GUID and IID specified */ - rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound8, (void**)&dso); - ok(rc==REGDB_E_CLASSNOTREG, - "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound8) " - "should have failed: %s\n",DXGetErrorString8(rc)); - - /* try with no device specified */ - rc=pDirectSoundCreate8(NULL,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && dso) - IDirectSound8_test(dso, TRUE, NULL); - - /* try with default playback device specified */ - rc=pDirectSoundCreate8(&DSDEVID_DefaultPlayback,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && dso) - IDirectSound8_test(dso, TRUE, NULL); - - /* try with default voice playback device specified */ - rc=pDirectSoundCreate8(&DSDEVID_DefaultVoicePlayback,&dso,NULL); - ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && dso) - IDirectSound8_test(dso, TRUE, NULL); - - /* try with a bad device specified */ - rc=pDirectSoundCreate8(&DSDEVID_DefaultVoiceCapture,&dso,NULL); - ok(rc==DSERR_NODRIVER,"DirectSoundCreate8(DSDEVID_DefaultVoiceCapture) " - "should have failed: %s\n",DXGetErrorString8(rc)); -} - -static HRESULT test_dsound8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - int ref; - - /* DSOUND: Error: Invalid interface buffer */ - rc=pDirectSoundCreate8(lpGuid,0,NULL); - ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8() should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* Create the DirectSound8 object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Try the enumerated device */ - IDirectSound8_test(dso, TRUE, lpGuid); - - /* Try the COM class factory method of creation with enumerated device */ - rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound8, (void**)&dso); - ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", - DXGetErrorString8(rc)); - if (dso) - IDirectSound8_test(dso, FALSE, lpGuid); - - /* Create a DirectSound8 object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - LPDIRECTSOUND8 dso1=NULL; - - /* Create a second DirectSound8 object */ - rc=pDirectSoundCreate8(lpGuid,&dso1,NULL); - ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - /* Release the second DirectSound8 object */ - ref=IDirectSound8_Release(dso1); - ok(ref==0,"IDirectSound8_Release() has %d references, " - "should have 0\n",ref); - ok(dso!=dso1,"DirectSound8 objects should be unique: " - "dso=0x%08lx,dso1=0x%08lx\n",(DWORD)dso,(DWORD)dso1); - } - - /* Release the first DirectSound8 object */ - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", - ref); - if (ref!=0) - return DSERR_GENERIC; - } else - return rc; - - /* Create a DirectSound8 object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK) { - LPDIRECTSOUNDBUFFER secondary; - DSBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - - init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; - bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec*BUFFER_LEN/1000; - bufdesc.lpwfxFormat=&wfx; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DS_OK && secondary!=NULL, - "IDirectSound8_CreateSoundBuffer() failed to create a secondary " - "buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && secondary!=NULL) { - LPDIRECTSOUND3DBUFFER buffer3d; - LPDIRECTSOUNDBUFFER8 buffer8; - rc=IDirectSound8_QueryInterface(secondary, - &IID_IDirectSound3DBuffer, - (void **)&buffer3d); - ok(rc==DS_OK && buffer3d!=NULL, - "IDirectSound8_QueryInterface() failed: %s\n", - DXGetErrorString8(rc)); - if (rc==DS_OK && buffer3d!=NULL) { - ref=IDirectSound3DBuffer_AddRef(buffer3d); - ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " - "should have 2\n",ref); - } - rc=IDirectSound8_QueryInterface(secondary, - &IID_IDirectSoundBuffer8, - (void **)&buffer8); - if (rc==DS_OK && buffer8!=NULL) { - ref=IDirectSoundBuffer8_AddRef(buffer8); - ok(ref==3,"IDirectSoundBuffer8_AddRef() has %d references, " - "should have 3\n",ref); - } - ref=IDirectSoundBuffer_AddRef(secondary); - ok(ref==4,"IDirectSoundBuffer_AddRef() has %d references, " - "should have 4\n",ref); - } - /* release with buffer */ - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", - ref); - if (ref!=0) - return DSERR_GENERIC; - } else - return rc; - - return DS_OK; -} - -static HRESULT test_primary8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx; - int ref; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL); - ok(rc==DSERR_INVALIDPARAM, - "IDirectSound8_CreateSoundBuffer should have returned " - "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound8_CreateSoundBuffer() should have returned " - "DSERR_INVALIDPARAM, returned: rc=%s,dsbo=0x%lx\n", - DXGetErrorString8(rc),(DWORD)primary); - - /* DSOUND: Error: Invalid buffer description pointer */ - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound8_CreateSoundBuffer() should have failed: rc=%s," - "dsbo=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary); - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - - /* DSOUND: Error: Invalid size */ - /* DSOUND: Error: Invalid buffer description */ - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM && primary==0, - "IDirectSound8_CreateSoundBuffer() should have failed: rc=%s," - "primary=0x%lx\n",DXGetErrorString8(rc),(DWORD)primary); - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* Testing the primary buffer */ - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; - bufdesc.lpwfxFormat = &wfx; - init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have " - "returned DSERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) - IDirectSoundBuffer_Release(primary); - - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL, - "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: " - "%s\n",DXGetErrorString8(rc)); - if (rc==DS_OK && primary!=NULL) { - LONG vol; - - /* Try to create a second primary buffer */ - /* DSOUND: Error: The primary buffer already exists. - * Any changes made to the buffer description will be ignored. */ - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL); - ok(rc==DS_OK && second==primary, - "IDirectSound8_CreateSoundBuffer() should have returned original " - "primary buffer: %s\n",DXGetErrorString8(rc)); - ref=IDirectSoundBuffer_Release(second); - ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 1\n",ref); - - /* Try to duplicate a primary buffer */ - /* DSOUND: Error: Can't duplicate primary buffers */ - rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third); - /* rc=0x88780032 */ - ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer " - "should have failed %s\n",DXGetErrorString8(rc)); - - rc=IDirectSoundBuffer_GetVolume(primary,&vol); - ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", - DXGetErrorString8(rc)); - - if (winetest_interactive) { - trace("Playing a 5 seconds reference tone at the current volume.\n"); - if (rc==DS_OK) - trace("(the current volume is %ld according to DirectSound)\n", - vol); - trace("All subsequent tones should be identical to this one.\n"); - trace("Listen for stutter, changes in pitch, volume, etc.\n"); - } - test_buffer8(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && - !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0); - - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - - /* Set the CooperativeLevel back to normal */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - -EXIT: - ref=IDirectSound8_Release(dso); - ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); - if (ref!=0) - return DSERR_GENERIC; - - return rc; -} - -/* - * Test the primary buffer at different formats while keeping the - * secondary buffer at a constant format. - */ -static HRESULT test_primary_secondary8(LPGUID lpGuid) -{ - HRESULT rc; - LPDIRECTSOUND8 dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - DSBUFFERDESC bufdesc; - DSCAPS dscaps; - WAVEFORMATEX wfx, wfx2; - int f,ref; - - /* Create the DirectSound object */ - rc=pDirectSoundCreate8(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - return rc; - - /* Get the device capabilities */ - ZeroMemory(&dscaps, sizeof(dscaps)); - dscaps.dwSize=sizeof(dscaps); - rc=IDirectSound8_GetCaps(dso,&dscaps); - ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* We must call SetCooperativeLevel before creating primary buffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; - rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK && primary!=NULL, - "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer " - "%s\n",DXGetErrorString8(rc)); - - if (rc==DS_OK && primary!=NULL) { - for (f=0;f +#include + +#include "wine/test.h" +#include "dsound.h" +#include "dxerr8.h" +#include "dsconf.h" + +#include "dsound_test.h" + +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*,LPUNKNOWN)=NULL; + +int align(int length, int align) +{ + return (length / align) * align; +} + +static void IDirectSound8_test(LPDIRECTSOUND8 dso, BOOL initialized, + LPCGUID lpGuid) +{ + HRESULT rc; + DSCAPS dscaps; + int ref; + IUnknown * unknown; + IDirectSound * ds; + IDirectSound8 * ds8; + DWORD speaker_config, new_speaker_config; + DWORD certified; + + /* Try to Query for objects */ + rc=IDirectSound8_QueryInterface(dso,&IID_IUnknown,(LPVOID*)&unknown); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IUnknown) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound8_Release(unknown); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound,(LPVOID*)&ds); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound_Release(ds); + + rc=IDirectSound8_QueryInterface(dso,&IID_IDirectSound8,(LPVOID*)&ds8); + ok(rc==DS_OK,"IDirectSound8_QueryInterface(IID_IDirectSound8) " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) + IDirectSound8_Release(ds8); + + if (initialized == FALSE) { + /* try unitialized object */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps(NULL) " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetCaps() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_Compact() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_GetSpeakerConfig() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DSERR_UNINITIALIZED,"IDirectSound8_VerifyCertification() " + "should have returned DSERR_UNINITIALIZED, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "IDirectSound8_Initialize() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DSERR_NODRIVER) { + trace(" No Driver\n"); + goto EXIT; + } else if (rc==E_FAIL) { + trace(" No Device\n"); + goto EXIT; + } else if (rc==DSERR_ALLOCATED) { + trace(" Already In Use\n"); + goto EXIT; + } + } + + rc=IDirectSound8_Initialize(dso,lpGuid); + ok(rc==DSERR_ALREADYINITIALIZED, "IDirectSound8_Initialize() " + "should have returned DSERR_ALREADYINITIALIZED: %s\n", + DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + ZeroMemory(&dscaps, sizeof(dscaps)); + + /* DSOUND: Error: Invalid caps buffer */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetCaps() " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + dscaps.dwSize=sizeof(dscaps); + + /* DSOUND: Running on a certified driver */ + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSound8_Compact(dso); + ok(rc==DSERR_PRIOLEVELNEEDED,"IDirectSound8_Compact() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_Compact(dso); + ok(rc==DS_OK,"IDirectSound8_Compact() failed: %s\n",DXGetErrorString8(rc)); + + rc=IDirectSound8_GetSpeakerConfig(dso,0); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_GetSpeakerConfig(NULL) " + "should have returned DSERR_INVALIDPARAM, returned: %s\n", + DXGetErrorString8(rc)); + + rc=IDirectSound8_GetSpeakerConfig(dso,&speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + + speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, + DSSPEAKER_GEOMETRY_WIDE); + rc=IDirectSound8_SetSpeakerConfig(dso,speaker_config); + ok(rc==DS_OK,"IDirectSound8_SetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK) { + rc=IDirectSound8_GetSpeakerConfig(dso,&new_speaker_config); + ok(rc==DS_OK,"IDirectSound8_GetSpeakerConfig() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && speaker_config!=new_speaker_config) + trace("IDirectSound8_GetSpeakerConfig() failed to set speaker " + "config: expected 0x%08lx, got 0x%08lx\n", + speaker_config,new_speaker_config); + } + + rc=IDirectSound8_VerifyCertification(dso, &certified); + ok(rc==DS_OK||rc==E_NOTIMPL,"IDirectSound8_VerifyCertification() failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); +} + +static void IDirectSound8_tests(void) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + + trace("Testing IDirectSound8\n"); + + /* try the COM class factory method of creation with no device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance() failed: %s\n",DXGetErrorString8(rc)); + if (dso) + IDirectSound8_test(dso, FALSE, NULL); + + /* try the COM class factory method of creation with default playback + * device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultPlayback); + + /* try the COM class factory method of creation with default voice + * playback device specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound8) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound8_test(dso, FALSE, &DSDEVID_DefaultVoicePlayback); + + /* try the COM class factory method of creation with a bad + * IID specified */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &CLSID_DirectSoundPrivate, (void**)&dso); + ok(rc==E_NOINTERFACE, + "CoCreateInstance(CLSID_DirectSound8,CLSID_DirectSoundPrivate) " + "should have failed: %s\n",DXGetErrorString8(rc)); + + /* try the COM class factory method of creation with a bad + * GUID and IID specified */ + rc=CoCreateInstance(&CLSID_DirectSoundPrivate, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==REGDB_E_CLASSNOTREG, + "CoCreateInstance(CLSID_DirectSoundPrivate,IID_IDirectSound8) " + "should have failed: %s\n",DXGetErrorString8(rc)); + + /* try with no device specified */ + rc=pDirectSoundCreate8(NULL,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultPlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with default voice playback device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoicePlayback,&dso,NULL); + ok(rc==S_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && dso) + IDirectSound8_test(dso, TRUE, NULL); + + /* try with a bad device specified */ + rc=pDirectSoundCreate8(&DSDEVID_DefaultVoiceCapture,&dso,NULL); + ok(rc==DSERR_NODRIVER,"DirectSoundCreate8(DSDEVID_DefaultVoiceCapture) " + "should have failed: %s\n",DXGetErrorString8(rc)); +} + +static HRESULT test_dsound8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + int ref; + + /* DSOUND: Error: Invalid interface buffer */ + rc=pDirectSoundCreate8(lpGuid,0,NULL); + ok(rc==DSERR_INVALIDPARAM,"DirectSoundCreate8() should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* Create the DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Try the enumerated device */ + IDirectSound8_test(dso, TRUE, lpGuid); + + /* Try the COM class factory method of creation with enumerated device */ + rc=CoCreateInstance(&CLSID_DirectSound8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectSound8, (void**)&dso); + ok(rc==S_OK,"CoCreateInstance(CLSID_DirectSound) failed: %s\n", + DXGetErrorString8(rc)); + if (dso) + IDirectSound8_test(dso, FALSE, lpGuid); + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + LPDIRECTSOUND8 dso1=NULL; + + /* Create a second DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso1,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + /* Release the second DirectSound8 object */ + ref=IDirectSound8_Release(dso1); + ok(ref==0,"IDirectSound8_Release() has %d references, " + "should have 0\n",ref); + ok(dso!=dso1,"DirectSound8 objects should be unique: " + "dso=%p,dso1=%p\n",dso,dso1); + } + + /* Release the first DirectSound8 object */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + /* Create a DirectSound8 object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK,"DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK) { + LPDIRECTSOUNDBUFFER secondary; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,1); + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRL3D; + bufdesc.dwBufferBytes=align(wfx.nAvgBytesPerSec*BUFFER_LEN/1000, + wfx.nBlockAlign); + bufdesc.lpwfxFormat=&wfx; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK && secondary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a secondary " + "buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK && secondary!=NULL) { + LPDIRECTSOUND3DBUFFER buffer3d; + LPDIRECTSOUNDBUFFER8 buffer8; + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSound3DBuffer, + (void **)&buffer3d); + ok(rc==DS_OK && buffer3d!=NULL, + "IDirectSound8_QueryInterface() failed: %s\n", + DXGetErrorString8(rc)); + if (rc==DS_OK && buffer3d!=NULL) { + ref=IDirectSound3DBuffer_AddRef(buffer3d); + ok(ref==2,"IDirectSound3DBuffer_AddRef() has %d references, " + "should have 2\n",ref); + } + rc=IDirectSound8_QueryInterface(secondary, + &IID_IDirectSoundBuffer8, + (void **)&buffer8); + if (rc==DS_OK && buffer8!=NULL) { + ref=IDirectSoundBuffer8_AddRef(buffer8); + ok(ref==3,"IDirectSoundBuffer8_AddRef() has %d references, " + "should have 3\n",ref); + } + ref=IDirectSoundBuffer_AddRef(secondary); + ok(ref==4,"IDirectSoundBuffer_AddRef() has %d references, " + "should have 4\n",ref); + } + /* release with buffer */ + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n", + ref); + if (ref!=0) + return DSERR_GENERIC; + } else + return rc; + + return DS_OK; +} + +static HRESULT test_primary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,second=NULL,third=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx; + int ref; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,0,NULL); + ok(rc==DSERR_INVALIDPARAM, + "IDirectSound8_CreateSoundBuffer should have returned " + "DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,0,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have returned " + "DSERR_INVALIDPARAM, returned: rc=%s,dsbo=%p\n", + DXGetErrorString8(rc),primary); + + /* DSOUND: Error: Invalid buffer description pointer */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,0,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%s," + "dsbo=%p\n",DXGetErrorString8(rc),primary); + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + + /* DSOUND: Error: Invalid size */ + /* DSOUND: Error: Invalid buffer description */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM && primary==0, + "IDirectSound8_CreateSoundBuffer() should have failed: rc=%s," + "primary=%p\n",DXGetErrorString8(rc),primary); + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* Testing the primary buffer */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + bufdesc.lpwfxFormat = &wfx; + init_format(&wfx,WAVE_FORMAT_PCM,11025,8,2); + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DSERR_INVALIDPARAM,"IDirectSound8_CreateSoundBuffer() should have " + "returned DSERR_INVALIDPARAM, returned: %s\n", DXGetErrorString8(rc)); + if (rc==DS_OK && primary!=NULL) + IDirectSoundBuffer_Release(primary); + + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRLVOLUME; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok((rc==DS_OK && primary!=NULL) || (rc==DSERR_CONTROLUNAVAIL), + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer: " + "%s\n",DXGetErrorString8(rc)); + if (rc==DSERR_CONTROLUNAVAIL) + trace(" No Primary\n"); + else if (rc==DS_OK && primary!=NULL) { + LONG vol; + + /* Try to create a second primary buffer */ + /* DSOUND: Error: The primary buffer already exists. + * Any changes made to the buffer description will be ignored. */ + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&second,NULL); + ok(rc==DS_OK && second==primary, + "IDirectSound8_CreateSoundBuffer() should have returned original " + "primary buffer: %s\n",DXGetErrorString8(rc)); + ref=IDirectSoundBuffer_Release(second); + ok(ref==1,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 1\n",ref); + + /* Try to duplicate a primary buffer */ + /* DSOUND: Error: Can't duplicate primary buffers */ + rc=IDirectSound8_DuplicateSoundBuffer(dso,primary,&third); + /* rc=0x88780032 */ + ok(rc!=DS_OK,"IDirectSound8_DuplicateSoundBuffer() primary buffer " + "should have failed %s\n",DXGetErrorString8(rc)); + + rc=IDirectSoundBuffer_GetVolume(primary,&vol); + ok(rc==DS_OK,"IDirectSoundBuffer_GetVolume() failed: %s\n", + DXGetErrorString8(rc)); + + if (winetest_interactive) { + trace("Playing a 5 seconds reference tone at the current volume.\n"); + if (rc==DS_OK) + trace("(the current volume is %ld according to DirectSound)\n", + vol); + trace("All subsequent tones should be identical to this one.\n"); + trace("Listen for stutter, changes in pitch, volume, etc.\n"); + } + test_buffer8(dso,primary,1,FALSE,0,FALSE,0,winetest_interactive && + !(dscaps.dwFlags & DSCAPS_EMULDRIVER),5.0,0,0,0,0); + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + + /* Set the CooperativeLevel back to normal */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_NORMAL */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_NORMAL); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + +EXIT: + ref=IDirectSound8_Release(dso); + ok(ref==0,"IDirectSound8_Release() has %d references, should have 0\n",ref); + if (ref!=0) + return DSERR_GENERIC; + + return rc; +} + +/* + * Test the primary buffer at different formats while keeping the + * secondary buffer at a constant format. + */ +static HRESULT test_primary_secondary8(LPGUID lpGuid) +{ + HRESULT rc; + LPDIRECTSOUND8 dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + DSCAPS dscaps; + WAVEFORMATEX wfx, wfx2; + int ref; + unsigned int f; + + /* Create the DirectSound object */ + rc=pDirectSoundCreate8(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, + "DirectSoundCreate8() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + return rc; + + /* Get the device capabilities */ + ZeroMemory(&dscaps, sizeof(dscaps)); + dscaps.dwSize=sizeof(dscaps); + rc=IDirectSound8_GetCaps(dso,&dscaps); + ok(rc==DS_OK,"IDirectSound8_GetCaps() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* We must call SetCooperativeLevel before creating primary buffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound8_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound8_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER; + rc=IDirectSound8_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK && primary!=NULL, + "IDirectSound8_CreateSoundBuffer() failed to create a primary buffer " + "%s\n",DXGetErrorString8(rc)); + + if (rc==DS_OK && primary!=NULL) { + for (f=0;fdwFileVersionMS >> 16, + pFixedVersionInfo->dwFileVersionMS & 0xffff, + pFixedVersionInfo->dwFileVersionLS >> 16, + pFixedVersionInfo->dwFileVersionLS & 0xffff); + } else + sprintf(version, "not available"); + } else + sprintf(version, "failed"); + + HeapFree(GetProcessHeap(), 0, data); + } else + sprintf(version, "failed"); + } else + sprintf(version, "not available"); + + return version; +} + +START_TEST(dsound8) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibraryA("dsound.dll"); + if (!hDsound) { + trace("dsound.dll not found\n"); + return; + } + + trace("DLL Version: %s\n", get_file_version("dsound.dll")); + + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, "DirectSoundCreate8"); + if (!pDirectSoundCreate8) { + trace("dsound8 test skipped\n"); + return; + } + + IDirectSound8_tests(); + dsound8_tests(); + + CoUninitialize(); +} diff --git a/reactos/lib/dsound/tests/dsound_test.h b/reactos/lib/dsound/tests/dsound_test.h index 7509ac89e29..9c84de44871 100644 --- a/reactos/lib/dsound/tests/dsound_test.h +++ b/reactos/lib/dsound/tests/dsound_test.h @@ -1,63 +1,64 @@ -/* - * Unit tests for dsound functions - * - * Copyright (c) 2004 Francois Gouget - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -static const unsigned int formats[][4]={ - { 8000, 8, 1, 0 }, - { 8000, 8, 2, 0 }, - { 8000, 16, 1, 0 }, - { 8000, 16, 2, 0 }, - {11025, 8, 1, WAVE_FORMAT_1M08 }, - {11025, 8, 2, WAVE_FORMAT_1S08 }, - {11025, 16, 1, WAVE_FORMAT_1M16 }, - {11025, 16, 2, WAVE_FORMAT_1S16 }, - {22050, 8, 1, WAVE_FORMAT_2M08 }, - {22050, 8, 2, WAVE_FORMAT_2S08 }, - {22050, 16, 1, WAVE_FORMAT_2M16 }, - {22050, 16, 2, WAVE_FORMAT_2S16 }, - {44100, 8, 1, WAVE_FORMAT_4M08 }, - {44100, 8, 2, WAVE_FORMAT_4S08 }, - {44100, 16, 1, WAVE_FORMAT_4M16 }, - {44100, 16, 2, WAVE_FORMAT_4S16 }, - {48000, 8, 1, WAVE_FORMAT_48M08 }, - {48000, 8, 2, WAVE_FORMAT_48S08 }, - {48000, 16, 1, WAVE_FORMAT_48M16 }, - {48000, 16, 2, WAVE_FORMAT_48S16 }, - {96000, 8, 1, WAVE_FORMAT_96M08 }, - {96000, 8, 2, WAVE_FORMAT_96S08 }, - {96000, 16, 1, WAVE_FORMAT_96M16 }, - {96000, 16, 2, WAVE_FORMAT_96S16 } -}; -#define NB_FORMATS (sizeof(formats)/sizeof(*formats)) - -/* The time slice determines how often we will service the buffer */ -#define TIME_SLICE 31 -#define BUFFER_LEN 400 - - -extern char* wave_generate_la(WAVEFORMATEX*,double,DWORD*); -extern HWND get_hwnd(void); -extern void init_format(WAVEFORMATEX*,int,int,int,int); -extern void test_buffer(LPDIRECTSOUND,LPDIRECTSOUNDBUFFER, - BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL, - LPDIRECTSOUND3DLISTENER,BOOL,BOOL); -extern void test_buffer8(LPDIRECTSOUND8,LPDIRECTSOUNDBUFFER, - BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL, - LPDIRECTSOUND3DLISTENER,BOOL,BOOL); -extern const char * getDSBCAPS(DWORD xmask); +/* + * Unit tests for dsound functions + * + * Copyright (c) 2004 Francois Gouget + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +static const unsigned int formats[][4]={ + { 8000, 8, 1, 0 }, + { 8000, 8, 2, 0 }, + { 8000, 16, 1, 0 }, + { 8000, 16, 2, 0 }, + {11025, 8, 1, WAVE_FORMAT_1M08 }, + {11025, 8, 2, WAVE_FORMAT_1S08 }, + {11025, 16, 1, WAVE_FORMAT_1M16 }, + {11025, 16, 2, WAVE_FORMAT_1S16 }, + {22050, 8, 1, WAVE_FORMAT_2M08 }, + {22050, 8, 2, WAVE_FORMAT_2S08 }, + {22050, 16, 1, WAVE_FORMAT_2M16 }, + {22050, 16, 2, WAVE_FORMAT_2S16 }, + {44100, 8, 1, WAVE_FORMAT_4M08 }, + {44100, 8, 2, WAVE_FORMAT_4S08 }, + {44100, 16, 1, WAVE_FORMAT_4M16 }, + {44100, 16, 2, WAVE_FORMAT_4S16 }, + {48000, 8, 1, WAVE_FORMAT_48M08 }, + {48000, 8, 2, WAVE_FORMAT_48S08 }, + {48000, 16, 1, WAVE_FORMAT_48M16 }, + {48000, 16, 2, WAVE_FORMAT_48S16 }, + {96000, 8, 1, WAVE_FORMAT_96M08 }, + {96000, 8, 2, WAVE_FORMAT_96S08 }, + {96000, 16, 1, WAVE_FORMAT_96M16 }, + {96000, 16, 2, WAVE_FORMAT_96S16 } +}; +#define NB_FORMATS (sizeof(formats)/sizeof(*formats)) + +/* The time slice determines how often we will service the buffer */ +#define TIME_SLICE 31 +#define BUFFER_LEN 400 + +extern char* wave_generate_la(WAVEFORMATEX*,double,DWORD*); +extern HWND get_hwnd(void); +extern void init_format(WAVEFORMATEX*,int,int,int,int); +extern void test_buffer(LPDIRECTSOUND,LPDIRECTSOUNDBUFFER, + BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL, + LPDIRECTSOUND3DLISTENER,BOOL,BOOL,BOOL,DWORD); +extern void test_buffer8(LPDIRECTSOUND8,LPDIRECTSOUNDBUFFER, + BOOL,BOOL,LONG,BOOL,LONG,BOOL,double,BOOL, + LPDIRECTSOUND3DLISTENER,BOOL,BOOL); +extern const char * getDSBCAPS(DWORD xmask); +extern int align(int length, int align); +extern const char * get_file_version(const char * file_name); diff --git a/reactos/lib/dsound/tests/propset.c b/reactos/lib/dsound/tests/propset.c index fe7225e43f2..0ca4e00f1ca 100644 --- a/reactos/lib/dsound/tests/propset.c +++ b/reactos/lib/dsound/tests/propset.c @@ -1,413 +1,734 @@ -/* - * Unit tests for CLSID_DirectSoundPrivate property set functions - * (used by dxdiag) - * - * Copyright (c) 2003 Robert Reif - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSSTRUCT -#define NONAMELESSUNION -#include - -#include -#include - -#include "wine/test.h" -#include "windef.h" -#include "wingdi.h" -#include "dsound.h" -#include "initguid.h" -#include "dsconf.h" -#include "dxerr8.h" - -#include "dsound_test.h" - -#ifndef DSBCAPS_CTRLDEFAULT -#define DSBCAPS_CTRLDEFAULT \ - DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME -#endif - -DEFINE_GUID(DSPROPSETID_VoiceManager, \ - 0x62A69BAE,0xDF9D,0x11D1,0x99,0xA6,0x00,0xC0,0x4F,0xC9,0x9D,0x46); -DEFINE_GUID(DSPROPSETID_EAX20_ListenerProperties, \ - 0x306a6a8,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); -DEFINE_GUID(DSPROPSETID_EAX20_BufferProperties, \ - 0x306a6a7,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); -DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties, \ - 0xDA0F0520,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); -DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties, \ - 0xDA0F0521,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); -DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties, \ - 0xCD5368E0,0x3450,0x11D3,0x8B,0x6E,0x00,0x10,0x5A,0x9B,0x7B,0xBC); - -typedef HRESULT (CALLBACK * MYPROC)(REFCLSID, REFIID, LPVOID *); - -BOOL CALLBACK callback(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA data, - LPVOID context) -{ - trace("found device:\n"); - trace("\tType: %s\n", - data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : - data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : - data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); - trace("\tDataFlow: %s\n", - data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : - data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? - "Capture" : "Unknown"); - trace("\tDeviceId: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", - data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, - data->DeviceId.Data4[0],data->DeviceId.Data4[1], - data->DeviceId.Data4[2],data->DeviceId.Data4[3], - data->DeviceId.Data4[4],data->DeviceId.Data4[5], - data->DeviceId.Data4[6],data->DeviceId.Data4[7]); - trace("\tDescription: %s\n", data->Description); - trace("\tModule: %s\n", data->Module); - trace("\tInterface: %s\n", data->Interface); - trace("\tWaveDeviceId: %ld\n", data->WaveDeviceId); - - return TRUE; -} - -static void propset_private_tests() -{ - HMODULE hDsound; - HRESULT rc; - IClassFactory * pcf; - IKsPropertySet * pps; - MYPROC fProc; - ULONG support; - - hDsound = LoadLibrary("dsound.dll"); - ok(hDsound!=0,"LoadLibrary(dsound.dll) failed\n"); - if (hDsound==0) - return; - - fProc = (MYPROC)GetProcAddress(hDsound, "DllGetClassObject"); - - /* try direct sound first */ - rc = (fProc)(&CLSID_DirectSound, &IID_IClassFactory, (void **)0); - ok(rc==DSERR_INVALIDPARAM,"DllGetClassObject(CLSID_DirectSound, " - "IID_IClassFactory) should have returned DSERR_INVALIDPARAM, " - "returned: %s\n",DXGetErrorString8(rc)); - - rc = (fProc)(&CLSID_DirectSound, &IID_IClassFactory, (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound, IID_IClassFactory) " - "failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound doesn't have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)0); - ok(rc==DSERR_INVALIDPARAM, "CreateInstance(IID_IKsPropertySet) should have " - "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); - - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " - "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); - - /* and the direct sound 8 version */ - rc = (fProc)(&CLSID_DirectSound8, &IID_IClassFactory, (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " - "failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound 8 doesn't have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " - "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); - - /* try direct sound capture next */ - rc = (fProc)(&CLSID_DirectSoundCapture, &IID_IClassFactory, - (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " - "failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound capture doesn't have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " - "returned E_NOINTERFACE,returned: %s\n",DXGetErrorString8(rc)); - - /* and the direct sound capture 8 version */ - rc = (fProc)(&CLSID_DirectSoundCapture8, &IID_IClassFactory, - (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture8, " - "IID_IClassFactory) failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound capture 8 doesn't have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " - "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); - - /* try direct sound full duplex next */ - rc = (fProc)(&CLSID_DirectSoundFullDuplex, &IID_IClassFactory, - (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundFullDuplex, " - "IID_IClassFactory) failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound full duplex doesn't have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " - "returned NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); - - /* try direct sound private last */ - rc = (fProc)(&CLSID_DirectSoundPrivate, &IID_IClassFactory, - (void **)(&pcf)); - ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundPrivate, " - "IID_IClassFactory) failed: %s\n",DXGetErrorString8(rc)); - if (pcf==0) - goto error; - - /* direct sound private does have an IKsPropertySet */ - rc = pcf->lpVtbl->CreateInstance(pcf, NULL, &IID_IKsPropertySet, - (void **)(&pps)); - ok(rc==DS_OK, "CreateInstance(IID_IKsPropertySet) failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto error; - - rc = pps->lpVtbl->QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, - &support); - ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " - "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION) failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto error; - - ok(support & KSPROPERTY_SUPPORT_GET, - "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " - "support = 0x%lx\n",support); - ok(!(support & KSPROPERTY_SUPPORT_SET), - "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " - "support = 0x%lx\n",support); - - rc = pps->lpVtbl->QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, &support); - ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " - "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING) failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto error; - - ok(support & KSPROPERTY_SUPPORT_GET, - "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: " - "support = 0x%lx\n",support); - ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " - "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: support = " - "0x%lx\n",support); - - rc = pps->lpVtbl->QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, - &support); - ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " - "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE) failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto error; - - ok(support & KSPROPERTY_SUPPORT_GET, - "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: " - "support = 0x%lx\n",support); - ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " - "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: support = 0x%lx\n",support); - - if (support & KSPROPERTY_SUPPORT_GET) { - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_DATA data; - ULONG bytes; - - data.Callback = callback; - data.Context = 0; - - rc = pps->lpVtbl->Get(pps, &DSPROPSETID_DirectSoundDevice, - DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, - NULL, 0, &data, sizeof(data), &bytes); - ok(rc==DS_OK, "Couldn't enumerate: 0x%lx\n",rc); - } - -error: - FreeLibrary(hDsound); -} - -static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, - LPCSTR lpcstrModule, LPVOID lpContext) -{ - HRESULT rc; - LPDIRECTSOUND dso=NULL; - LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; - DSBUFFERDESC bufdesc; - WAVEFORMATEX wfx; - int ref; - - trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); - - rc=DirectSoundCreate(lpGuid,&dso,NULL); - ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED, - "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); - if (rc!=DS_OK) { - if (rc==DSERR_NODRIVER) - trace(" No Driver\n"); - else if (rc == DSERR_ALLOCATED) - trace(" Already In Use\n"); - goto EXIT; - } - - /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ - /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ - rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); - ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", - DXGetErrorString8(rc)); - if (rc!=DS_OK) - goto EXIT; - - /* Testing 3D buffers */ - primary=NULL; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_LOCHARDWARE|DSBCAPS_CTRL3D; - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); - ok(rc==DS_OK&&primary!=NULL,"IDirectSound_CreateSoundBuffer() failed to " - "create a hardware 3D primary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK&&primary!=NULL) { - ZeroMemory(&wfx, sizeof(wfx)); - wfx.wFormatTag=WAVE_FORMAT_PCM; - wfx.nChannels=1; - wfx.wBitsPerSample=16; - wfx.nSamplesPerSec=44100; - wfx.nBlockAlign=wfx.nChannels*wfx.wBitsPerSample/8; - wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign; - ZeroMemory(&bufdesc, sizeof(bufdesc)); - bufdesc.dwSize=sizeof(bufdesc); - bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2; - bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec; - bufdesc.lpwfxFormat=&wfx; - trace(" Testing a secondary buffer at %ldx%dx%d\n", - wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); - rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); - ok(rc==DS_OK&&secondary!=NULL,"IDirectSound_CreateSoundBuffer() " - "failed to create a secondary buffer: %s\n",DXGetErrorString8(rc)); - if (rc==DS_OK&&secondary!=NULL) { - IKsPropertySet * pPropertySet=NULL; - rc=IDirectSoundBuffer_QueryInterface(secondary, - &IID_IKsPropertySet, - (void **)&pPropertySet); - /* it's not an error for this to fail */ - if(rc==DS_OK) { - ULONG ulTypeSupport; - trace(" Supports property sets\n"); - /* it's not an error for these to fail */ - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_VoiceManager, - 0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_VoiceManager supported\n"); - else - trace(" DSPROPSETID_VoiceManager not supported\n"); - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_EAX20_ListenerProperties,0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_EAX20_ListenerProperties " - "supported\n"); - else - trace(" DSPROPSETID_EAX20_ListenerProperties not " - "supported\n"); - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_EAX20_BufferProperties,0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_EAX20_BufferProperties supported\n"); - else - trace(" DSPROPSETID_EAX20_BufferProperties not " - "supported\n"); - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_I3DL2_ListenerProperties,0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_I3DL2_ListenerProperties " - "supported\n"); - else - trace(" DSPROPSETID_I3DL2_ListenerProperties not " - "supported\n"); - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_I3DL2_BufferProperties,0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_I3DL2_BufferProperties supported\n"); - else - trace(" DSPROPSETID_I3DL2_BufferProperties not " - "supported\n"); - rc=IKsPropertySet_QuerySupport(pPropertySet, - &DSPROPSETID_ZOOMFX_BufferProperties,0,&ulTypeSupport); - if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| - KSPROPERTY_SUPPORT_SET))) - trace(" DSPROPSETID_ZOOMFX_BufferProperties " - "supported\n"); - else - trace(" DSPROPSETID_ZOOMFX_BufferProperties not " - "supported\n"); - ref=IKsPropertySet_Release(pPropertySet); - /* try a few common ones */ - ok(ref==0,"IKsPropertySet_Release() secondary has %d " - "references, should have 0\n",ref); - } else - trace(" Doesn't support property sets\n"); - - ref=IDirectSoundBuffer_Release(secondary); - ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " - "references, should have 0\n",ref); - } - - ref=IDirectSoundBuffer_Release(primary); - ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " - "should have 0\n",ref); - } - -EXIT: - if (dso!=NULL) { - ref=IDirectSound_Release(dso); - ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", - ref); - } - return 1; -} - -static void propset_buffer_tests() -{ - HRESULT rc; - rc=DirectSoundEnumerateA(&dsenum_callback,NULL); - ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); -} - -START_TEST(propset) -{ - propset_private_tests(); - propset_buffer_tests(); -} +/* + * Unit tests for CLSID_DirectSoundPrivate property set functions + * (used by dxdiag) + * + * Copyright (c) 2003 Robert Reif + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSSTRUCT +#define NONAMELESSUNION +#define COBJMACROS +#include + +#include "wine/test.h" +#include "dsound.h" +#include "initguid.h" +#include "dsconf.h" +#include "dxerr8.h" + +#include "dsound_test.h" + +#ifndef DSBCAPS_CTRLDEFAULT +#define DSBCAPS_CTRLDEFAULT \ + DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME +#endif + +DEFINE_GUID(DSPROPSETID_VoiceManager, \ + 0x62A69BAE,0xDF9D,0x11D1,0x99,0xA6,0x00,0xC0,0x4F,0xC9,0x9D,0x46); +DEFINE_GUID(DSPROPSETID_EAX20_ListenerProperties, \ + 0x306a6a8,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_EAX20_BufferProperties, \ + 0x306a6a7,0xb224,0x11d2,0x99,0xe5,0x0,0x0,0xe8,0xd8,0xc7,0x22); +DEFINE_GUID(DSPROPSETID_I3DL2_ListenerProperties, \ + 0xDA0F0520,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_I3DL2_BufferProperties, \ + 0xDA0F0521,0x300A,0x11D3,0x8A,0x2B,0x00,0x60,0x97,0x0D,0xB0,0x11); +DEFINE_GUID(DSPROPSETID_ZOOMFX_BufferProperties, \ + 0xCD5368E0,0x3450,0x11D3,0x8B,0x6E,0x00,0x10,0x5A,0x9B,0x7B,0xBC); + +typedef HRESULT (CALLBACK * MYPROC)(REFCLSID, REFIID, LPVOID *); + +static HRESULT (WINAPI *pDirectSoundCreate8)(LPCGUID,LPDIRECTSOUND8*, + LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID, + LPDIRECTSOUNDCAPTURE*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundCaptureCreate8)(LPCGUID, + LPDIRECTSOUNDCAPTURE8*,LPUNKNOWN)=NULL; +static HRESULT (WINAPI *pDirectSoundFullDuplexCreate)(LPCGUID,LPCGUID, + LPCDSCBUFFERDESC,LPCDSBUFFERDESC,HWND,DWORD,LPDIRECTSOUNDFULLDUPLEX*, + LPDIRECTSOUNDCAPTUREBUFFER8*,LPDIRECTSOUNDBUFFER8*,LPUNKNOWN)=NULL; + +BOOL CALLBACK callback(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %ld\n", data->WaveDeviceId); + + return TRUE; +} + +BOOL CALLBACK callback1(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" DescriptionA: %s\n", data->DescriptionA); + WideCharToMultiByte(CP_ACP, 0, data->DescriptionW, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + trace(" DescriptionW: %s\n", descriptionA); + trace(" ModuleA: %s\n", data->ModuleA); + WideCharToMultiByte(CP_ACP, 0, data->ModuleW, -1, moduleA, sizeof(moduleA), NULL, NULL); + trace(" ModuleW: %s\n", moduleA); + trace(" WaveDeviceId: %ld\n", data->WaveDeviceId); + + return TRUE; +} + +BOOL CALLBACK callbackA(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A_DATA data, + LPVOID context) +{ + trace(" found device:\n"); + trace(" Type: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace(" DataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace(" DeviceId: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + trace(" Description: %s\n", data->Description); + trace(" Module: %s\n", data->Module); + trace(" Interface: %s\n", data->Interface); + trace(" WaveDeviceId: %ld\n", data->WaveDeviceId); + + return TRUE; +} + +BOOL CALLBACK callbackW(PDSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W_DATA data, + LPVOID context) +{ + char descriptionA[0x100]; + char moduleA[MAX_PATH]; + char interfaceA[MAX_PATH]; + + trace("found device:\n"); + trace("\tType: %s\n", + data->Type == DIRECTSOUNDDEVICE_TYPE_EMULATED ? "Emulated" : + data->Type == DIRECTSOUNDDEVICE_TYPE_VXD ? "VxD" : + data->Type == DIRECTSOUNDDEVICE_TYPE_WDM ? "WDM" : "Unknown"); + trace("\tDataFlow: %s\n", + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ? "Render" : + data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ? + "Capture" : "Unknown"); + trace("\tDeviceId: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", + data->DeviceId.Data1,data->DeviceId.Data2,data->DeviceId.Data3, + data->DeviceId.Data4[0],data->DeviceId.Data4[1], + data->DeviceId.Data4[2],data->DeviceId.Data4[3], + data->DeviceId.Data4[4],data->DeviceId.Data4[5], + data->DeviceId.Data4[6],data->DeviceId.Data4[7]); + WideCharToMultiByte(CP_ACP, 0, data->Description, -1, descriptionA, sizeof(descriptionA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Module, -1, moduleA, sizeof(moduleA), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, data->Interface, -1, interfaceA, sizeof(interfaceA), NULL, NULL); + trace("\tDescription: %s\n", descriptionA); + trace("\tModule: %s\n", moduleA); + trace("\tInterface: %s\n", interfaceA); + trace("\tWaveDeviceId: %ld\n", data->WaveDeviceId); + + return TRUE; +} + +static void propset_private_tests(void) +{ + HMODULE hDsound; + HRESULT rc; + IClassFactory * pcf; + IKsPropertySet * pps; + MYPROC fProc; + ULONG support; + + hDsound = LoadLibrary("dsound.dll"); + ok(hDsound!=0,"LoadLibrary(dsound.dll) failed\n"); + if (hDsound==0) + return; + + fProc = (MYPROC)GetProcAddress(hDsound, "DllGetClassObject"); + + /* try direct sound first */ + /* DSOUND: Error: Invalid interface buffer */ + rc = (fProc)(&CLSID_DirectSound, &IID_IClassFactory, (void **)0); + ok(rc==DSERR_INVALIDPARAM,"DllGetClassObject(CLSID_DirectSound, " + "IID_IClassFactory) should have returned DSERR_INVALIDPARAM, " + "returned: %s\n",DXGetErrorString8(rc)); + + rc = (fProc)(&CLSID_DirectSound, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound, IID_IClassFactory) " + "failed: %s\n",DXGetErrorString8(rc)); + if (pcf==0) + goto error; + + /* direct sound doesn't have an IKsPropertySet */ + /* DSOUND: Error: Invalid interface buffer */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)0); + ok(rc==DSERR_INVALIDPARAM, "CreateInstance(IID_IKsPropertySet) should have " + "returned DSERR_INVALIDPARAM, returned: %s\n",DXGetErrorString8(rc)); + + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); + + /* and the direct sound 8 version */ + if (pDirectSoundCreate8) { + rc = (fProc)(&CLSID_DirectSound8, &IID_IClassFactory, (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSound8, IID_IClassFactory) " + "failed: %s\n",DXGetErrorString8(rc)); + if (pcf==0) + goto error; + + /* direct sound 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); + } + + /* try direct sound capture next */ + if (pDirectSoundCaptureCreate) { + rc = (fProc)(&CLSID_DirectSoundCapture, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture, IID_IClassFactory) " + "failed: %s\n",DXGetErrorString8(rc)); + if (pcf==0) + goto error; + + /* direct sound capture doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE,returned: %s\n",DXGetErrorString8(rc)); + } + + /* and the direct sound capture 8 version */ + if (pDirectSoundCaptureCreate8) { + rc = (fProc)(&CLSID_DirectSoundCapture8, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundCapture8, " + "IID_IClassFactory) failed: %s\n",DXGetErrorString8(rc)); + if (pcf==0) + goto error; + + /* direct sound capture 8 doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned E_NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); + } + + /* try direct sound full duplex next */ + if (pDirectSoundFullDuplexCreate) { + rc = (fProc)(&CLSID_DirectSoundFullDuplex, &IID_IClassFactory, + (void **)(&pcf)); + ok(pcf!=0, "DllGetClassObject(CLSID_DirectSoundFullDuplex, " + "IID_IClassFactory) failed: %s\n",DXGetErrorString8(rc)); + if (pcf==0) + goto error; + + /* direct sound full duplex doesn't have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==E_NOINTERFACE, "CreateInstance(IID_IKsPropertySet) should have " + "returned NOINTERFACE, returned: %s\n",DXGetErrorString8(rc)); + } + + /* try direct sound private last */ + rc = (fProc)(&CLSID_DirectSoundPrivate, &IID_IClassFactory, + (void **)(&pcf)); + + /* some early versions of Direct Sound do not have this */ + if (pcf==0) + goto error; + + /* direct sound private does have an IKsPropertySet */ + rc = IClassFactory_CreateInstance(pcf, NULL, &IID_IKsPropertySet, + (void **)(&pps)); + ok(rc==DS_OK, "CreateInstance(IID_IKsPropertySet) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + goto error; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION: " + "support = 0x%lx\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1 */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + goto error; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_1: " + "support = 0x%lx\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + goto error; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_A: " + "support = 0x%lx\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W, + &support); + ok(rc==DS_OK||rc==E_INVALIDARG, + "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==E_INVALIDARG) + trace(" Not Supported\n"); + goto error; + } + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), + "Shouldn't be able to set DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_W: " + "support = 0x%lx\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING: support = " + "0x%lx\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_A: support = " + "0x%lx\n",support); + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W */ + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W, &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET), "Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_WAVEDEVICEMAPPING_W: support = " + "0x%lx\n",support); + + /* test generic DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE: support = 0x%lx\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_DATA data; + ULONG bytes; + + data.Callback = callback; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%lx\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1 ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1: support = 0x%lx\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1_DATA data; + ULONG bytes; + + data.Callback = callback1; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_1, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%lx\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A: support = 0x%lx\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A_DATA data; + ULONG bytes; + + data.Callback = callbackA; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_A, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%lx\n",rc); + } + + /* test DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W */ + trace("*** Testing DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W ***\n"); + rc = IKsPropertySet_QuerySupport(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + &support); + ok(rc==DS_OK, "QuerySupport(DSPROPSETID_DirectSoundDevice, " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W) failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto error; + + ok(support & KSPROPERTY_SUPPORT_GET, + "Couldn't get DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: " + "support = 0x%lx\n",support); + ok(!(support & KSPROPERTY_SUPPORT_SET),"Shouldn't be able to set " + "DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W: support = 0x%lx\n",support); + + if (support & KSPROPERTY_SUPPORT_GET) { + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; + ULONG bytes; + + data.Callback = callbackW; + data.Context = 0; + + rc = IKsPropertySet_Get(pps, &DSPROPSETID_DirectSoundDevice, + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W, + NULL, 0, &data, sizeof(data), &bytes); + ok(rc==DS_OK, "Couldn't enumerate: 0x%lx\n",rc); + } + +error: + FreeLibrary(hDsound); +} + +static BOOL WINAPI dsenum_callback(LPGUID lpGuid, LPCSTR lpcstrDescription, + LPCSTR lpcstrModule, LPVOID lpContext) +{ + HRESULT rc; + LPDIRECTSOUND dso=NULL; + LPDIRECTSOUNDBUFFER primary=NULL,secondary=NULL; + DSBUFFERDESC bufdesc; + WAVEFORMATEX wfx; + int ref; + + trace("*** Testing %s - %s ***\n",lpcstrDescription,lpcstrModule); + + rc=DirectSoundCreate(lpGuid,&dso,NULL); + ok(rc==DS_OK||rc==DSERR_NODRIVER||rc==DSERR_ALLOCATED||rc==E_FAIL, + "DirectSoundCreate() failed: %s\n",DXGetErrorString8(rc)); + if (rc!=DS_OK) { + if (rc==DSERR_NODRIVER) + trace(" No Driver\n"); + else if (rc == DSERR_ALLOCATED) + trace(" Already In Use\n"); + else if (rc == E_FAIL) + trace(" No Device\n"); + goto EXIT; + } + + /* We must call SetCooperativeLevel before calling CreateSoundBuffer */ + /* DSOUND: Setting DirectSound cooperative level to DSSCL_PRIORITY */ + rc=IDirectSound_SetCooperativeLevel(dso,get_hwnd(),DSSCL_PRIORITY); + ok(rc==DS_OK,"IDirectSound_SetCooperativeLevel() failed: %s\n", + DXGetErrorString8(rc)); + if (rc!=DS_OK) + goto EXIT; + + /* Testing 3D buffers */ + primary=NULL; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_LOCHARDWARE|DSBCAPS_CTRL3D; + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&primary,NULL); + ok(rc==DS_OK&&primary!=NULL,"IDirectSound_CreateSoundBuffer() failed to " + "create a hardware 3D primary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK&&primary!=NULL) { + ZeroMemory(&wfx, sizeof(wfx)); + wfx.wFormatTag=WAVE_FORMAT_PCM; + wfx.nChannels=1; + wfx.wBitsPerSample=16; + wfx.nSamplesPerSec=44100; + wfx.nBlockAlign=wfx.nChannels*wfx.wBitsPerSample/8; + wfx.nAvgBytesPerSec=wfx.nSamplesPerSec*wfx.nBlockAlign; + ZeroMemory(&bufdesc, sizeof(bufdesc)); + bufdesc.dwSize=sizeof(bufdesc); + bufdesc.dwFlags=DSBCAPS_CTRLDEFAULT|DSBCAPS_GETCURRENTPOSITION2; + bufdesc.dwBufferBytes=wfx.nAvgBytesPerSec; + bufdesc.lpwfxFormat=&wfx; + trace(" Testing a secondary buffer at %ldx%dx%d\n", + wfx.nSamplesPerSec,wfx.wBitsPerSample,wfx.nChannels); + rc=IDirectSound_CreateSoundBuffer(dso,&bufdesc,&secondary,NULL); + ok(rc==DS_OK&&secondary!=NULL,"IDirectSound_CreateSoundBuffer() " + "failed to create a secondary buffer: %s\n",DXGetErrorString8(rc)); + if (rc==DS_OK&&secondary!=NULL) { + IKsPropertySet * pPropertySet=NULL; + rc=IDirectSoundBuffer_QueryInterface(secondary, + &IID_IKsPropertySet, + (void **)&pPropertySet); + /* it's not an error for this to fail */ + if(rc==DS_OK) { + ULONG ulTypeSupport; + trace(" Supports property sets\n"); + /* it's not an error for these to fail */ + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_VoiceManager, + 0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_VoiceManager supported\n"); + else + trace(" DSPROPSETID_VoiceManager not supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_EAX20_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_EAX20_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_EAX20_BufferProperties supported\n"); + else + trace(" DSPROPSETID_EAX20_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_ListenerProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_ListenerProperties " + "supported\n"); + else + trace(" DSPROPSETID_I3DL2_ListenerProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_I3DL2_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_I3DL2_BufferProperties supported\n"); + else + trace(" DSPROPSETID_I3DL2_BufferProperties not " + "supported\n"); + rc=IKsPropertySet_QuerySupport(pPropertySet, + &DSPROPSETID_ZOOMFX_BufferProperties,0,&ulTypeSupport); + if((rc==DS_OK)&&(ulTypeSupport&(KSPROPERTY_SUPPORT_GET| + KSPROPERTY_SUPPORT_SET))) + trace(" DSPROPSETID_ZOOMFX_BufferProperties " + "supported\n"); + else + trace(" DSPROPSETID_ZOOMFX_BufferProperties not " + "supported\n"); + ref=IKsPropertySet_Release(pPropertySet); + /* try a few common ones */ + ok(ref==0,"IKsPropertySet_Release() secondary has %d " + "references, should have 0\n",ref); + } else + trace(" Doesn't support property sets\n"); + + ref=IDirectSoundBuffer_Release(secondary); + ok(ref==0,"IDirectSoundBuffer_Release() secondary has %d " + "references, should have 0\n",ref); + } + + ref=IDirectSoundBuffer_Release(primary); + ok(ref==0,"IDirectSoundBuffer_Release() primary has %d references, " + "should have 0\n",ref); + } + +EXIT: + if (dso!=NULL) { + ref=IDirectSound_Release(dso); + ok(ref==0,"IDirectSound_Release() has %d references, should have 0\n", + ref); + } + return 1; +} + +static void propset_buffer_tests(void) +{ + HRESULT rc; + rc=DirectSoundEnumerateA(&dsenum_callback,NULL); + ok(rc==DS_OK,"DirectSoundEnumerateA() failed: %s\n",DXGetErrorString8(rc)); +} + +START_TEST(propset) +{ + HMODULE hDsound; + + CoInitialize(NULL); + + hDsound = LoadLibraryA("dsound.dll"); + if (!hDsound) { + trace("dsound.dll not found\n"); + return; + } + + trace("DLL Version: %s\n", get_file_version("dsound.dll")); + + pDirectSoundCreate8 = (void*)GetProcAddress(hDsound, "DirectSoundCreate8"); + pDirectSoundCaptureCreate=(void*)GetProcAddress(hDsound,"DirectSoundCaptureCreate"); + pDirectSoundCaptureCreate8=(void*)GetProcAddress(hDsound,"DirectSoundCaptureCreate8"); + pDirectSoundFullDuplexCreate=(void*)GetProcAddress(hDsound,"DirectSoundFullDuplexCreate"); + + propset_private_tests(); + propset_buffer_tests(); + + CoUninitialize(); +} diff --git a/reactos/lib/dsound/version.rc b/reactos/lib/dsound/version.rc index bab9caeeb89..a27e80c2f44 100644 --- a/reactos/lib/dsound/version.rc +++ b/reactos/lib/dsound/version.rc @@ -1,27 +1,27 @@ -/* - * Copyright 2001 Ove Kaaven - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define WINE_OLESELFREGISTER -#define WINE_FILEDESCRIPTION_STR "Wine DirectSound" -#define WINE_FILENAME_STR "dsound.dll" -#define WINE_FILEVERSION 5,3,0,900 -#define WINE_FILEVERSION_STR "5.3.0.900" -#define WINE_PRODUCTVERSION 5,3,0,900 -#define WINE_PRODUCTVERSION_STR "5.3" - -#include "wine/wine_common_ver.rc" +/* + * Copyright 2001 Ove Kaaven + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WINE_OLESELFREGISTER +#define WINE_FILEDESCRIPTION_STR "Wine DirectSound" +#define WINE_FILENAME_STR "dsound.dll" +#define WINE_FILEVERSION 5,3,0,900 +#define WINE_FILEVERSION_STR "5.3.0.900" +#define WINE_PRODUCTVERSION 5,3,0,900 +#define WINE_PRODUCTVERSION_STR "5.3" + +#include "wine/wine_common_ver.rc"