waveOut fix

Andreas Mohr amohr at codeweavers.com
Fri Feb 9 13:28:21 CST 2001


Hi all,

somebody mentioned that a program called BrainWave Generator (www.bwgen.com)
went into looping after some 3 or 4 seconds.

This happened because we were decrementing the dwLoops counter of the
*external* struct (sounds familiar ? ;-) instead of doing that to our own
copy.

bwgen submits about 5 WAVEHDRs with WHDR_BEGINLOOP and WHDR_ENDLOOP set
for each one, and dwLoops is set to 1 (is this dainbread or rather
very smart ?? I can't decide).

So Wine looped every buffer once (i.e. played once),
and when bwgen received the "played" callback event, it resubmitted the
same WAVEHDR with changed buffer data.
Unfortunately this meant that this code part here underflowed:

                /* WAVEHDR written, go to next one */
                if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {
                    if (--wwo->lpLoopPtr->dwLoops > 0) {
                        wwo->lpPlayPtr = wwo->lpLoopPtr;
                    } else {

, as dwLoops was 0 as Wine had already decremented it from 1 to 0 last time.

Thus we ended up with nearly eternal (0xffff) looping.

And as I verified that Windows doesn't touch dwLoops, we won't do that either,
so we keep an internal copy.

ChangeLog:
Don't touch WAVEHDRs dwLoops variable.

Andreas Mohr
-------------- next part --------------
Determining best CVS host...
Using CVSROOT :pserver:cvs at wine.codeweavers.com:/home/cvs/wine
Index: dlls/winmm/wineoss/audio.c
===================================================================
RCS file: /home/cvs/wine/wine/dlls/winmm/wineoss/audio.c,v
retrieving revision 1.36
diff -u -r1.36 audio.c
--- dlls/winmm/wineoss/audio.c	2001/01/18 20:29:41	1.36
+++ dlls/winmm/wineoss/audio.c	2001/02/10 00:57:58
@@ -100,6 +100,7 @@
     LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
     LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
     LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
+    DWORD			dwLoops;		/* private copy of loop counter */
     
     DWORD			dwLastFragDone;		/* time in ms, when last played fragment will be actually played */
     DWORD			dwPlayedTotal;		/* number of bytes played since opening */
@@ -356,7 +357,7 @@
 static DWORD OSS_NotifyClient(UINT wDevID, WORD wMsg, DWORD dwParam1, 
 			      DWORD dwParam2)
 {
-    TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
+    TRACE("wDevID = %04X wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
     
     switch (wMsg) {
     case WOM_OPEN:
@@ -447,7 +448,11 @@
 		if (wwo->lpLoopPtr) {
 		    WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
 		} else {
+		    TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
 		    wwo->lpLoopPtr = lpWaveHdr;
+		    /* Windows does not touch WAVEHDR.dwLoops,
+		     * so we need to make an internal copy */
+		    wwo->dwLoops = lpWaveHdr->dwLoops;
 		}
 	    }
 	}
@@ -474,7 +479,7 @@
 
 		/* WAVEHDR written, go to next one */
 		if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {
-		    if (--wwo->lpLoopPtr->dwLoops > 0) {
+		    if (--wwo->dwLoops > 0) {
 			wwo->lpPlayPtr = wwo->lpLoopPtr;
 		    } else {
 			/* last one played */


More information about the wine-patches mailing list