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) ...@@ -826,8 +826,32 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos); mixplaypos = DSOUND_bufpos_to_mixpos(device, device->playpos);
mixplaypos2 = DSOUND_bufpos_to_mixpos(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; buf1 = device->buffer + device->playpos;
buf2 = device->buffer; buf2 = device->buffer;
size1 = device->buflen - device->playpos; size1 = device->buflen - device->playpos;
...@@ -861,34 +885,12 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) ...@@ -861,34 +885,12 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
} }
device->playpos = playpos; 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 */ /* find the maximum we can prebuffer from current write position */
maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0; maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0;
TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n", TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n",
prebuff_left, device->prebuf, device->fraglen, prebuff_max, writelead); 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? */ /* Do we risk an 'underrun' if we don't advance pointer? */
if (writelead/device->fraglen <= ds_snd_queue_min || recover) if (writelead/device->fraglen <= ds_snd_queue_min || recover)
mustlock = TRUE; mustlock = TRUE;
......
...@@ -329,6 +329,8 @@ static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface, ...@@ -329,6 +329,8 @@ static HRESULT WINAPI IDsDriverBufferImpl_Lock(PIDSDRIVERBUFFER iface,
TRACE("Hit mmap_pos, locking data!\n"); TRACE("Hit mmap_pos, locking data!\n");
snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin); 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); LeaveCriticalSection(&This->pcm_crst);
/* **** */ /* **** */
...@@ -551,7 +553,9 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface, ...@@ -551,7 +553,9 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
if (used < 0) if (used < 0)
{ {
This->mmap_pos += -used;
snd_pcm_forward(This->pcm, -used); snd_pcm_forward(This->pcm, -used);
This->mmap_pos %= This->mmap_buflen_frames;
used = 0; used = 0;
} }
......
...@@ -575,7 +575,6 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -575,7 +575,6 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
unsigned int period_time = 20000; unsigned int period_time = 20000;
snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size;
snd_pcm_uframes_t boundary;
int flags; int flags;
int err=0; int err=0;
int dir=0; int dir=0;
...@@ -758,13 +757,11 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -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); err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
snd_pcm_sw_params_current(pcm, sw_params); 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_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_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_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_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"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
#undef EXIT_ON_ERROR #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