From 6e90756307bfd5aa6ce2207f9419dabd26f46ec6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 4 Sep 2008 12:07:37 +0200 Subject: [PATCH] winealsa.drv/dsound: Handle underruns better. --- dlls/dsound/mixer.c | 50 +++++++++++++++++++----------------- dlls/winealsa.drv/dsoutput.c | 4 +++ dlls/winealsa.drv/waveout.c | 3 --- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 7fe94239f12..3c13e8f1060 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -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; diff --git a/dlls/winealsa.drv/dsoutput.c b/dlls/winealsa.drv/dsoutput.c index 4043ccf036a..15cff5f1fbf 100644 --- a/dlls/winealsa.drv/dsoutput.c +++ b/dlls/winealsa.drv/dsoutput.c @@ -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; } diff --git a/dlls/winealsa.drv/waveout.c b/dlls/winealsa.drv/waveout.c index 9dae6f405ac..8149a4afb1d 100644 --- a/dlls/winealsa.drv/waveout.c +++ b/dlls/winealsa.drv/waveout.c @@ -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