Fixes for various underrun-related problems. Also added a mechanism
for the sound driver to request that a Stop should close and reopen the device.
This commit is contained in:
parent
0a01fbdacb
commit
62510ddbf6
|
@ -1032,6 +1032,35 @@ static void DSOUND_PrimaryClose(IDirectSoundBufferImpl *dsb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HRESULT DSOUND_PrimaryPlay(IDirectSoundBufferImpl *dsb)
|
||||||
|
{
|
||||||
|
HRESULT err = DS_OK;
|
||||||
|
if (dsb->hwbuf)
|
||||||
|
err = IDsDriverBuffer_Play(dsb->hwbuf, 0, 0, DSBPLAY_LOOPING);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT DSOUND_PrimaryStop(IDirectSoundBufferImpl *dsb)
|
||||||
|
{
|
||||||
|
HRESULT err = DS_OK;
|
||||||
|
if (dsb->hwbuf) {
|
||||||
|
err = IDsDriverBuffer_Stop(dsb->hwbuf);
|
||||||
|
if (err == DSERR_BUFFERLOST) {
|
||||||
|
/* Wine-only: the driver wants us to reopen the device */
|
||||||
|
/* FIXME: check for errors */
|
||||||
|
IDsDriverBuffer_Release(primarybuf->hwbuf);
|
||||||
|
waveOutClose(dsb->dsound->hwo);
|
||||||
|
dsb->dsound->hwo = 0;
|
||||||
|
waveOutOpen(&(dsb->dsound->hwo), dsb->dsound->drvdesc.dnDevNode,
|
||||||
|
&(primarybuf->wfx), 0, 0, CALLBACK_NULL | WAVE_DIRECTSOUND);
|
||||||
|
err = IDsDriver_CreateSoundBuffer(dsb->dsound->driver,&(dsb->wfx),dsb->dsbd.dwFlags,0,
|
||||||
|
&(dsb->buflen),&(dsb->buffer),
|
||||||
|
(LPVOID)&(dsb->hwbuf));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* This sets this format for the <em>Primary Buffer Only</em> */
|
/* This sets this format for the <em>Primary Buffer Only</em> */
|
||||||
/* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
|
/* See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 120 */
|
||||||
static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
|
static HRESULT WINAPI IDirectSoundBufferImpl_SetFormat(
|
||||||
|
@ -1304,7 +1333,7 @@ static DWORD WINAPI IDirectSoundBufferImpl_Release(LPDIRECTSOUNDBUFFER iface) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
|
static DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
|
||||||
DWORD state, DWORD pplay, DWORD pmix, DWORD bmix)
|
DWORD state, DWORD pplay, DWORD pwrite, DWORD pmix, DWORD bmix)
|
||||||
{
|
{
|
||||||
DWORD bplay;
|
DWORD bplay;
|
||||||
|
|
||||||
|
@ -1325,7 +1354,9 @@ static DWORD DSOUND_CalcPlayPosition(IDirectSoundBufferImpl *This,
|
||||||
if (pmix < pplay) pmix += primarybuf->buflen; /* wraparound */
|
if (pmix < pplay) pmix += primarybuf->buflen; /* wraparound */
|
||||||
pmix -= pplay;
|
pmix -= pplay;
|
||||||
/* detect buffer underrun */
|
/* detect buffer underrun */
|
||||||
if ((pmix > ((DS_SND_QUEUE + 1) * primarybuf->dsound->fraglen + primarybuf->writelead))) {
|
if (pwrite < pplay) pwrite += primarybuf->buflen; /* wraparound */
|
||||||
|
pwrite -= pplay;
|
||||||
|
if (pmix > (DS_SND_QUEUE * primarybuf->dsound->fraglen + pwrite + primarybuf->writelead)) {
|
||||||
TRACE("detected an underrun: primary queue was %ld\n",pmix);
|
TRACE("detected an underrun: primary queue was %ld\n",pmix);
|
||||||
pmix = 0;
|
pmix = 0;
|
||||||
}
|
}
|
||||||
|
@ -1383,11 +1414,11 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
|
||||||
*playpos = This->buf_mixpos;
|
*playpos = This->buf_mixpos;
|
||||||
}
|
}
|
||||||
else if (playpos) {
|
else if (playpos) {
|
||||||
DWORD pplay, lplay, splay, pstate;
|
DWORD pplay, pwrite, lplay, splay, pstate;
|
||||||
/* let's get this exact; first, recursively call GetPosition on the primary */
|
/* let's get this exact; first, recursively call GetPosition on the primary */
|
||||||
EnterCriticalSection(&(primarybuf->lock));
|
EnterCriticalSection(&(primarybuf->lock));
|
||||||
if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || primarybuf->hwbuf || !DS_EMULDRIVER) {
|
if ((This->dsbd.dwFlags & DSBCAPS_GETCURRENTPOSITION2) || primarybuf->hwbuf || !DS_EMULDRIVER) {
|
||||||
IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER)primarybuf, &pplay, NULL);
|
IDirectSoundBufferImpl_GetCurrentPosition((LPDIRECTSOUNDBUFFER)primarybuf, &pplay, &pwrite);
|
||||||
/* detect HEL mode underrun */
|
/* detect HEL mode underrun */
|
||||||
pstate = primarybuf->state;
|
pstate = primarybuf->state;
|
||||||
if (!(primarybuf->hwbuf || primarybuf->dsound->pwqueue)) {
|
if (!(primarybuf->hwbuf || primarybuf->dsound->pwqueue)) {
|
||||||
|
@ -1403,7 +1434,7 @@ static HRESULT WINAPI IDirectSoundBufferImpl_GetCurrentPosition(
|
||||||
lplay = This->primary_mixpos;
|
lplay = This->primary_mixpos;
|
||||||
splay = This->buf_mixpos;
|
splay = This->buf_mixpos;
|
||||||
/* calculate play position using this */
|
/* calculate play position using this */
|
||||||
*playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, lplay, splay);
|
*playpos = DSOUND_CalcPlayPosition(This, pstate, pplay, pwrite, lplay, splay);
|
||||||
} else {
|
} else {
|
||||||
/* (unless the app isn't using GETCURRENTPOSITION2) */
|
/* (unless the app isn't using GETCURRENTPOSITION2) */
|
||||||
/* don't know exactly how this should be handled...
|
/* don't know exactly how this should be handled...
|
||||||
|
@ -2081,6 +2112,7 @@ static HRESULT WINAPI IDirectSoundImpl_DuplicateSoundBuffer(
|
||||||
IDirectSoundBuffer_AddRef(pdsb);
|
IDirectSoundBuffer_AddRef(pdsb);
|
||||||
memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
|
memcpy(*ippdsb, ipdsb, sizeof(IDirectSoundBufferImpl));
|
||||||
(*ippdsb)->ref = 1;
|
(*ippdsb)->ref = 1;
|
||||||
|
(*ippdsb)->state = STATE_STOPPED;
|
||||||
(*ippdsb)->playpos = 0;
|
(*ippdsb)->playpos = 0;
|
||||||
(*ippdsb)->buf_mixpos = 0;
|
(*ippdsb)->buf_mixpos = 0;
|
||||||
(*ippdsb)->dsound = This;
|
(*ippdsb)->dsound = This;
|
||||||
|
@ -2710,7 +2742,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD wri
|
||||||
DWORD len, slen;
|
DWORD len, slen;
|
||||||
/* determine this buffer's write position */
|
/* determine this buffer's write position */
|
||||||
DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, dsb->state & primarybuf->state, writepos,
|
DWORD buf_writepos = DSOUND_CalcPlayPosition(dsb, dsb->state & primarybuf->state, writepos,
|
||||||
dsb->primary_mixpos, dsb->buf_mixpos);
|
writepos, dsb->primary_mixpos, dsb->buf_mixpos);
|
||||||
/* determine how much already-mixed data exist */
|
/* determine how much already-mixed data exist */
|
||||||
DWORD buf_done =
|
DWORD buf_done =
|
||||||
((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
|
((dsb->buf_mixpos < buf_writepos) ? dsb->buflen : 0) +
|
||||||
|
@ -2734,9 +2766,13 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD playpos, DWORD wri
|
||||||
|
|
||||||
/* check whether CalcPlayPosition detected a mixing underrun */
|
/* check whether CalcPlayPosition detected a mixing underrun */
|
||||||
if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) {
|
if ((buf_done == 0) && (dsb->primary_mixpos != writepos)) {
|
||||||
/* it did, try to recover */
|
/* 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);
|
ERR("underrun on sound buffer %p\n", dsb);
|
||||||
TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos);
|
TRACE("recovering from underrun: primary_mixpos=%ld\n", writepos);
|
||||||
|
}
|
||||||
dsb->primary_mixpos = writepos;
|
dsb->primary_mixpos = writepos;
|
||||||
primary_done = 0;
|
primary_done = 0;
|
||||||
}
|
}
|
||||||
|
@ -2949,7 +2985,7 @@ static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw
|
||||||
TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq);
|
TRACE("reached end of mixed data (inq=%ld, maxq=%ld)\n", inq, maxq);
|
||||||
inq = 0;
|
inq = 0;
|
||||||
/* stop the playback now, to allow buffers to refill */
|
/* stop the playback now, to allow buffers to refill */
|
||||||
IDsDriverBuffer_Stop(primarybuf->hwbuf);
|
DSOUND_PrimaryStop(primarybuf);
|
||||||
if (primarybuf->state == STATE_PLAYING) {
|
if (primarybuf->state == STATE_PLAYING) {
|
||||||
primarybuf->state = STATE_STARTING;
|
primarybuf->state = STATE_STARTING;
|
||||||
}
|
}
|
||||||
|
@ -2988,14 +3024,14 @@ static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw
|
||||||
if (frag) {
|
if (frag) {
|
||||||
/* buffers have been filled, restart playback */
|
/* buffers have been filled, restart playback */
|
||||||
if (primarybuf->state == STATE_STARTING) {
|
if (primarybuf->state == STATE_STARTING) {
|
||||||
IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
|
DSOUND_PrimaryPlay(primarybuf);
|
||||||
primarybuf->state = STATE_PLAYING;
|
primarybuf->state = STATE_PLAYING;
|
||||||
TRACE("starting playback\n");
|
TRACE("starting playback\n");
|
||||||
}
|
}
|
||||||
else if (primarybuf->state == STATE_STOPPED) {
|
else if (primarybuf->state == STATE_STOPPED) {
|
||||||
/* the primarybuf is supposed to play if there's something to play
|
/* the primarybuf is supposed to play if there's something to play
|
||||||
* even if it is reported as stopped, so don't let this confuse you */
|
* even if it is reported as stopped, so don't let this confuse you */
|
||||||
IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
|
DSOUND_PrimaryPlay(primarybuf);
|
||||||
primarybuf->state = STATE_STOPPING;
|
primarybuf->state = STATE_STOPPING;
|
||||||
TRACE("starting playback\n");
|
TRACE("starting playback\n");
|
||||||
}
|
}
|
||||||
|
@ -3004,11 +3040,11 @@ static void CALLBACK DSOUND_timer(UINT timerID, UINT msg, DWORD dwUser, DWORD dw
|
||||||
} else {
|
} else {
|
||||||
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
|
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
|
||||||
if (primarybuf->state == STATE_STARTING) {
|
if (primarybuf->state == STATE_STARTING) {
|
||||||
IDsDriverBuffer_Play(primarybuf->hwbuf, 0, 0, DSBPLAY_LOOPING);
|
DSOUND_PrimaryPlay(primarybuf);
|
||||||
primarybuf->state = STATE_PLAYING;
|
primarybuf->state = STATE_PLAYING;
|
||||||
}
|
}
|
||||||
else if (primarybuf->state == STATE_STOPPING) {
|
else if (primarybuf->state == STATE_STOPPING) {
|
||||||
IDsDriverBuffer_Stop(primarybuf->hwbuf);
|
DSOUND_PrimaryStop(primarybuf);
|
||||||
primarybuf->state = STATE_STOPPED;
|
primarybuf->state = STATE_STOPPED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue