DSOUND: buffer underrun & sound chunks left out (RESEND)
Ove Kaaven
ovek at arcticnet.no
Mon Mar 17 04:56:08 CST 2003
man, 2003-03-17 kl. 10:06 skrev Jerry Ji:
> This patch fix two problem:
> 1. the improper play position return by DSOUND_PrimaryGetPosition -
> beffer underrun,
I guess this should be considered a bug in wineoss (or maybe your kernel
drivers), but it's not a dsound bug and should not be fixed by reducing
the readout precision of drivers that actually work properly. I don't
think your buffer.c patch is very correct either, it would cause
spurious noise under some circumstances.
> 2. and the notify mechanics we used - sound data skipped.
>
> Please refer to the comment for the first problem.
>
> DSOUND_CheckEvent(IDirectSoundBufferImpl *dsb, int len) original use
> current play position and the count of data TO BE played to check if a
> notify should be generated. That's to say, an application may be
> notified before the data at the desired offset really played. Since the
> application got the notify that the data in it's demand region is
> useless (played), it might call IDirectSoundBufferImpl_Lock to lock this
> region, which contains useful data, IDirectSoundBufferImpl_Lock will
> handle the conflict by cancelling the region by default.
Here's my fix for the problem in WineX, and it's supposed to be able to
handle the OFFSETSTOP case. I think it should apply to Wine without too
much trouble.
Log:
Ove Kaaven <ovek at transgaming.com>
Somewhat more reliable dsound position notifications.
Index: mixer.c
===================================================================
RCS file: /cvsroot/winex/wine/dlls/dsound/mixer.c,v
retrieving revision 1.8
retrieving revision 1.10
diff -u -r1.8 -r1.10
--- mixer.c 1 Oct 2002 13:51:32 -0000 1.8
+++ mixer.c 14 Feb 2003 22:04:28 -0000 1.10
@@ -345,17 +345,6 @@
if (len == 0) {
/* This should only happen if we aren't looping and temp < 4 */
-
- /* We skip the remainder, so check for possible events */
- DSOUND_CheckEvent(dsb, dsb->buflen - dsb->buf_mixpos);
- /* Stop */
- dsb->state = STATE_STOPPED;
- dsb->playpos = 0;
- dsb->last_playpos = 0;
- dsb->buf_mixpos = 0;
- dsb->leadin = FALSE;
- /* Check for DSBPN_OFFSETSTOP */
- DSOUND_CheckEvent(dsb, 0);
return 0;
}
@@ -397,9 +386,6 @@
}
/* free(buf); */
- if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY)
- DSOUND_CheckEvent(dsb, ilen);
-
if (dsb->leadin && (dsb->startpos > dsb->buf_mixpos) && (dsb->startpos <= dsb->buf_mixpos + ilen)) {
/* HACK... leadin should be reset when the PLAY position reaches the startpos,
* not the MIX position... but if the sound buffer is bigger than our prebuffering
@@ -411,14 +397,7 @@
dsb->buf_mixpos += ilen;
if (dsb->buf_mixpos >= dsb->buflen) {
- if (!(dsb->playflags & DSBPLAY_LOOPING)) {
- dsb->state = STATE_STOPPED;
- dsb->playpos = 0;
- dsb->last_playpos = 0;
- dsb->buf_mixpos = 0;
- dsb->leadin = FALSE;
- DSOUND_CheckEvent(dsb, 0); /* For DSBPN_OFFSETSTOP */
- } else {
+ if (dsb->playflags & DSBPLAY_LOOPING) {
/* wrap */
while (dsb->buf_mixpos >= dsb->buflen)
dsb->buf_mixpos -= dsb->buflen;
@@ -573,6 +552,10 @@
DWORD adv_done =
((dsb->dsound->mixpos < writepos) ? dsb->dsound->buflen : 0) +
dsb->dsound->mixpos - writepos;
+ DWORD played =
+ ((buf_writepos < dsb->playpos) ? dsb->buflen : 0) +
+ buf_writepos - dsb->playpos;
+ DWORD buf_left = dsb->buflen - buf_writepos;
int still_behind;
TRACE("buf_writepos=%ld, primary_writepos=%ld\n", buf_writepos, writepos);
@@ -581,6 +564,12 @@
mixlen);
TRACE("looping=%ld, startpos=%ld, leadin=%ld\n", dsb->playflags, dsb->startpos, dsb->leadin);
+ /* check for notification positions */
+ if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
+ dsb->state != STATE_STARTING) {
+ DSOUND_CheckEvent(dsb, played);
+ }
+
/* save write position for non-GETCURRENTPOSITION2... */
dsb->playpos = buf_writepos;
@@ -653,7 +642,8 @@
/* smaller than a fragment, wait until it gets larger
* before we take the mixing overhead */
TRACE("mixlen not worth it, deferring mixing\n");
- return 0;
+ still_behind = 1;
+ goto post_mix;
}
/* ok, we know how much to mix, let's go */
@@ -675,6 +665,19 @@
}
TRACE("new primary_mixpos=%ld, primary_advbase=%ld\n", dsb->primary_mixpos, dsb->dsound->mixpos);
TRACE("mixed data len=%ld, still_behind=%d\n", mixlen-len, still_behind);
+
+post_mix:
+ /* check if buffer should be considered complete */
+ if (buf_left < dsb->writelead &&
+ !(dsb->playflags & DSBPLAY_LOOPING)) {
+ dsb->state = STATE_STOPPED;
+ dsb->playpos = 0;
+ dsb->last_playpos = 0;
+ dsb->buf_mixpos = 0;
+ dsb->leadin = FALSE;
+ DSOUND_CheckEvent(dsb, buf_left);
+ }
+
/* return how far we think the primary buffer can
* advance its underrun detector...*/
if (still_behind) return 0;
@@ -707,6 +710,7 @@
if (dsb->state == STATE_STOPPING) {
DSOUND_MixCancel(dsb, writepos, TRUE);
dsb->state = STATE_STOPPED;
+ DSOUND_CheckEvent(dsb, 0);
} else {
if ((dsb->state == STATE_STARTING) || recover) {
dsb->primary_mixpos = writepos;
More information about the wine-patches
mailing list