[winealsa] Mind buffer loops when pausing

Chris Bandy cbandy at jbandy.com
Wed Mar 7 09:13:51 CST 2007


This patch should fix the incorrect handling of WaveHdr loops when
pausing.  Like the non-loop case written before, this sums the buffer
lengths between dwPlayedTotal and dwWrittenTotal to calculate the new
dwPartialOffset.  Instead of blindly moving from one buffer to the next,
however, this traverses the list using BeginWaveHdr and PlayPtrNext.
This has added benefit of correctly initializing all pointers and
counters for playback.

It looks correct on paper, but I don't seem to have any applications
that even attempt to pause.  Can anyone suggest an application to test
this with?  All feedback welcome.

Note: this branch in the function is a 'software' pause.  To test you
may need to override the check for ALSA's hardware pause at line 418
(snd_pcm_hw_params_can_pause)


-- Chris

-------------- next part --------------
diff --git a/dlls/winealsa.drv/waveout.c b/dlls/winealsa.drv/waveout.c
index 6a8a435..4ac50c6 100644
--- a/dlls/winealsa.drv/waveout.c
+++ b/dlls/winealsa.drv/waveout.c
@@ -319,9 +319,9 @@ static DWORD wodPlayer_NotifyCompletions(WINE_WAVEDEV* wwo, BOOL force)
  *
  * wodPlayer helper. Resets current output stream.
  */
-static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
+static void wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
 {
-    int                         err;
+    int err;
     TRACE("(%p)\n", wwo);
 
     /* flush all possible output */
@@ -329,7 +329,7 @@ static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
 
     wodUpdatePlayedTotal(wwo, NULL);
     /* updates current notify list */
-    wodPlayer_NotifyCompletions(wwo, FALSE);
+    wodPlayer_NotifyCompletions(wwo, reset);
 
     if ( (err = snd_pcm_drop(wwo->pcm)) < 0) {
 	FIXME("flush: %s\n", snd_strerror(err));
@@ -345,9 +345,6 @@ static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
         DWORD		        param;
         HANDLE		        ev;
 
-        /* remove any buffer */
-        wodPlayer_NotifyCompletions(wwo, TRUE);
-
         wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
         wwo->state = WINE_WS_STOPPED;
         wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
@@ -368,32 +365,34 @@ static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
             ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
             ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
 
-                wodNotifyClient(wwo, WOM_DONE, param, 0);
+            wodNotifyClient(wwo, WOM_DONE, param, 0);
         }
         ALSA_ResetRingMessage(&wwo->msgRing);
         LeaveCriticalSection(&wwo->msgRing.msg_crst);
     } else {
-        if (wwo->lpLoopPtr) {
-            /* complicated case, not handled yet (could imply modifying the loop counter */
-            FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
-            wwo->lpPlayPtr = wwo->lpLoopPtr;
-            wwo->dwPartialOffset = 0;
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
-        } else {
-            LPWAVEHDR   ptr;
-            DWORD       sz = wwo->dwPartialOffset;
+        DWORD diff = wwo->dwWrittenTotal - wwo->dwPlayedTotal;
+        DWORD sz;
+
+        /* no pointers or counters need to change */
+        if (diff <= wwo->dwPartialOffset)
+            wwo->dwPartialOffset -= diff;
+        else {
+            wwo->lpLoopPtr = NULL;
+            wodPlayer_BeginWaveHdr(wwo, wwo->lpQueuePtr);
 
-            /* reset all the data as if we had written only up to lpPlayedTotal bytes */
-            /* compute the max size playable from lpQueuePtr */
-            for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext) {
-                sz += ptr->dwBufferLength;
+            diff -= wwo->dwPartialOffset;
+            sz = wwo->lpPlayPtr->dwBufferLength;
+
+            while (sz < diff) {
+                wodPlayer_PlayPtrNext(wwo);
+                sz += wwo->lpPlayPtr->dwBufferLength;
             }
-            /* because the reset lpPlayPtr will be lpQueuePtr */
-            if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("grin\n");
-            wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
-            wwo->dwWrittenTotal = wwo->dwPlayedTotal;
-            wwo->lpPlayPtr = wwo->lpQueuePtr;
+
+            wwo->dwPartialOffset = sz - diff;
+            wodPlayer_BeginWaveHdr(wwo, wwo->lpQueuePtr);
         }
+
+        wwo->dwWrittenTotal = wwo->dwPlayedTotal;
         wwo->state = WINE_WS_PAUSED;
     }
 }



More information about the wine-devel mailing list