diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 497fa156066..2feb9358ed3 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -55,6 +55,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dsound); #define DS_HEL_BUFLEN 0x8000 /* HEL: The buffer length of the emulated buffer */ #define DS_SND_QUEUE_MAX 10 /* max number of fragments to prebuffer, each fragment is approximately 10 ms long */ +#define DS_SND_QUEUE_MIN 6 /* If the minimum of prebuffered fragments go below this, forcibly take all locks to prevent underruns */ DirectSoundDevice* DSOUND_renderer[MAXWAVEDRIVERS]; GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; @@ -90,6 +91,7 @@ HRESULT mmErr(UINT err) int ds_emuldriver = 0; int ds_hel_buflen = DS_HEL_BUFLEN; int ds_snd_queue_max = DS_SND_QUEUE_MAX; +int ds_snd_queue_min = DS_SND_QUEUE_MIN; int ds_hw_accel = DS_HW_ACCEL_FULL; int ds_default_playback = 0; int ds_default_capture = 0; @@ -152,6 +154,9 @@ void setup_dsound_options(void) if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH )) ds_snd_queue_max = atoi(buffer); + if (!get_config_key( hkey, appkey, "SndQueueMin", buffer, MAX_PATH )) + ds_snd_queue_min = atoi(buffer); + if (!get_config_key( hkey, appkey, "HardwareAcceleration", buffer, MAX_PATH )) { if (strcmp(buffer, "Full") == 0) ds_hw_accel = DS_HW_ACCEL_FULL; @@ -184,6 +189,8 @@ void setup_dsound_options(void) WARN("ds_hel_buflen = %d (default=%d)\n",ds_hel_buflen ,DS_HEL_BUFLEN); if (ds_snd_queue_max != DS_SND_QUEUE_MAX) WARN("ds_snd_queue_max = %d (default=%d)\n",ds_snd_queue_max ,DS_SND_QUEUE_MAX); + if (ds_snd_queue_min != DS_SND_QUEUE_MIN) + WARN("ds_snd_queue_min = %d (default=%d)\n",ds_snd_queue_min ,DS_SND_QUEUE_MIN); if (ds_hw_accel != DS_HW_ACCEL_FULL) WARN("ds_hw_accel = %s (default=Full)\n", ds_hw_accel==DS_HW_ACCEL_FULL ? "Full" : diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 91ac107c92b..61ff4a09e3e 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -32,6 +32,7 @@ extern int ds_emuldriver; extern int ds_hel_buflen; extern int ds_snd_queue_max; +extern int ds_snd_queue_min; extern int ds_hw_accel; extern int ds_default_playback; extern int ds_default_capture; diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 6390584e21c..c9ede688de9 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -667,10 +667,10 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi * For a DirectSoundDevice, go through all the currently playing buffers and * mix them in to the device buffer. * - * playpos = the current play position in the primary buffer * writepos = the current safe-to-write position in the primary buffer * mixlen = the maximum amount to mix into the primary buffer * (beyond the current writepos) + * mustlock = Do we have to fight for lock because we otherwise risk an underrun? * recover = true if the sound device may have been reset and the write * position in the device buffer changed * all_stopped = reports back if all buffers have stopped @@ -678,12 +678,12 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi * Returns: the length beyond the writepos that was mixed to. */ -static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, - DWORD mixlen, BOOL recover, BOOL *all_stopped) +static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL mustlock, BOOL recover, BOOL *all_stopped) { INT i, len; DWORD minlen = 0; IDirectSoundBufferImpl *dsb; + BOOL gotall = TRUE; /* unless we find a running buffer, all have stopped */ *all_stopped = TRUE; @@ -696,8 +696,11 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos if (dsb->buflen && dsb->state && !dsb->hwbuf) { TRACE("Checking %p, mixlen=%d\n", dsb, mixlen); - RtlAcquireResourceShared(&dsb->lock, TRUE); - + if (!RtlAcquireResourceShared(&dsb->lock, mustlock)) + { + gotall = FALSE; + continue; + } /* if buffer is stopping it is stopped now */ if (dsb->state == STATE_STOPPING) { dsb->state = STATE_STOPPED; @@ -733,7 +736,7 @@ static DWORD DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos } TRACE("Mixed at least %d from all buffers\n", minlen); - + if (!gotall) return 0; return minlen; } @@ -816,6 +819,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) DWORD playpos, writepos, writelead, maxq, frag, prebuff_max, prebuff_left, size1, size2; LPVOID buf1, buf2; BOOL lock = (device->hwbuf && !(device->drvdesc.dwFlags & DSDDESC_DONTNEEDPRIMARYLOCK)); + BOOL mustlock = FALSE; int nfiller; /* the sound of silence */ @@ -890,11 +894,15 @@ static void DSOUND_PerformMix(DirectSoundDevice *device) 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; + if (lock) IDsDriverBuffer_Lock(device->hwbuf, &buf1, &size1, &buf2, &size2, writepos, maxq, 0); /* do the mixing */ - frag = DSOUND_MixToPrimary(device, writepos, maxq, recover, &all_stopped); + frag = DSOUND_MixToPrimary(device, writepos, maxq, mustlock, recover, &all_stopped); /* update the mix position, taking wrap-around into acount */ device->mixpos = writepos + frag;