--- vendor/wine/dlls/dsound/current/buffer.c 2004-12-31 14:53:28 UTC (rev 12510)
+++ vendor/wine/dlls/dsound/current/buffer.c 2004-12-31 14:53:50 UTC (rev 12511)
@@ -0,0 +1,1567 @@
+/* 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#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;i<howmuch;i++)
+ TRACE("notify at %ld to 0x%08lx\n",
+ notify[i].dwOffset,(DWORD)notify[i].hEventNotify);
+ }
+
+ if (This->dsb->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<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
+
+ WARN("control unavailable\n");
+ return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_AcquireResources(
+ LPDIRECTSOUNDBUFFER8 iface,DWORD dwFlags,DWORD dwEffectsCount,LPDWORD pdwResultCodes
+) {
+ IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+ DWORD u;
+
+ FIXME("(%p,%08lu,%lu,%p): stub\n",This,dwFlags,dwEffectsCount,pdwResultCodes);
+
+ if (pdwResultCodes)
+ for (u=0; u<dwEffectsCount; u++) pdwResultCodes[u] = DSFXR_UNKNOWN;
+
+ WARN("control unavailable\n");
+ return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetObjectInPath(
+ LPDIRECTSOUNDBUFFER8 iface,REFGUID rguidObject,DWORD dwIndex,REFGUID rguidInterface,LPVOID* ppObject
+) {
+ IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+
+ FIXME("(%p,%s,%lu,%s,%p): stub\n",This,debugstr_guid(rguidObject),dwIndex,debugstr_guid(rguidInterface),ppObject);
+
+ WARN("control unavailable\n");
+ return DSERR_CONTROLUNAVAIL;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_Initialize(
+ LPDIRECTSOUNDBUFFER8 iface,LPDIRECTSOUND dsound,LPCDSBUFFERDESC dbsd
+) {
+ IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+ FIXME("(%p,%p,%p):stub\n",This,dsound,dbsd);
+ DPRINTF("Re-Init!!!\n");
+ WARN("already initialized\n");
+ return DSERR_ALREADYINITIALIZED;
+}
+
+static HRESULT WINAPI IDirectSoundBufferImpl_GetCaps(
+ LPDIRECTSOUNDBUFFER8 iface,LPDSBCAPS caps
+) {
+ IDirectSoundBufferImpl *This = (IDirectSoundBufferImpl *)iface;
+ TRACE("(%p)->(%p)\n",This,caps);
+
+ if (caps == NULL) {
+ WARN("invalid parameter: caps == NULL\n");
+ return DSERR_INVALIDPARAM;
+ }
+
+ if (caps->dwSize < sizeof(*caps)) {
+ WARN("invalid parameter: caps->dwSize = %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;
[truncated at 1000 lines; 10802 more skipped]