Commit 6e907563 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Alexandre Julliard

winealsa.drv/dsound: Handle underruns better.

parent 09874bf7
......@@ -826,8 +826,32 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
mixplaypos2 = DSOUND_bufpos_to_mixpos(device, playpos);
/* wipe out just-played sound data */
if (playpos < device->playpos) {
/* calc maximum prebuff */
prebuff_max = (device->prebuf * device->fraglen);
if (!device->hwbuf && playpos + prebuff_max >= device->helfrags * device->fraglen)
prebuff_max += device->buflen - device->helfrags * device->fraglen;
/* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
writelead = DSOUND_BufPtrDiff(device->buflen, writepos, playpos);
/* check for underrun. underrun occurs when the write position passes the mix position
* also wipe out just-played sound data */
if((prebuff_left > prebuff_max) || (device->state == STATE_STOPPED) || (device->state == STATE_STARTING)){
if (device->state == STATE_STOPPING || device->state == STATE_PLAYING)
WARN("Probable buffer underrun\n");
else TRACE("Buffer starting or buffer underrun\n");
/* recover mixing for all buffers */
recover = TRUE;
/* reset mix position to write position */
device->mixpos = writepos;
ZeroMemory(device->mix_buffer, device->mix_buffer_len);
ZeroMemory(device->buffer, device->buflen);
} else if (playpos < device->playpos) {
buf1 = device->buffer + device->playpos;
buf2 = device->buffer;
size1 = device->buflen - device->playpos;
......@@ -861,34 +885,12 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
}
device->playpos = playpos;
/* calc maximum prebuff */
prebuff_max = (device->prebuf * device->fraglen);
if (!device->hwbuf && playpos + prebuff_max >= device->helfrags * device->fraglen)
prebuff_max += device->buflen - device->helfrags * device->fraglen;
/* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
writelead = DSOUND_BufPtrDiff(device->buflen, writepos, playpos);
/* find the maximum we can prebuffer from current write position */
maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0;
TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n",
prebuff_left, device->prebuf, device->fraglen, prebuff_max, writelead);
/* check for underrun. underrun occurs when the write position passes the mix position */
if((prebuff_left > prebuff_max) || (device->state == STATE_STOPPED) || (device->state == STATE_STARTING)){
if (device->state == STATE_STOPPING || device->state == STATE_PLAYING)
WARN("Probable buffer underrun\n");
else TRACE("Buffer starting or buffer underrun\n");
/* recover mixing for all buffers */
recover = TRUE;
/* reset mix position to write position */
device->mixpos = writepos;
}
/* Do we risk an 'underrun' if we don't advance pointer? */
if (writelead/device->fraglen <= ds_snd_queue_min || recover)
mustlock = TRUE;
......
......@@ -329,6 +329,8 @@ static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
TRACE("Hit mmap_pos, locking data!\n");
snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
}
else
WARN("mmap_pos (%lu) != writepos (%lu) not locking data!\n", This->mmap_pos, writepos);
LeaveCriticalSection(&This->pcm_crst);
/* **** */
......@@ -551,7 +553,9 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
if (used < 0)
{
This->mmap_pos += -used;
snd_pcm_forward(This->pcm, -used);
This->mmap_pos %= This->mmap_buflen_frames;
used = 0;
}
......
......@@ -575,7 +575,6 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
unsigned int period_time = 20000;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
snd_pcm_uframes_t boundary;
int flags;
int err=0;
int dir=0;
......@@ -758,13 +757,11 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
snd_pcm_sw_params_current(pcm, sw_params);
snd_pcm_sw_params_get_boundary(sw_params, &boundary);
EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold");
EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size");
EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min");
EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold");
EXIT_ON_ERROR( snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary), MMSYSERR_ERROR, "unable to set stop threshold");
EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
#undef EXIT_ON_ERROR
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment