winealsa: Fix pausing when the hardware does not support it.

Jan Zerebecki jan.wine at zerebecki.de
Sun Apr 2 20:52:11 CDT 2006


If this patch is rejected from inclusion, please tell me why, as i would have to
ask anyway.

From: Jan Zerebecki <jan.wine at zerebecki.de>
Changelog:
winealsa: Fix pausing when the hardware does not support it.
Except the little alsa specific part, this is copied from wineoss.
---

 dlls/winmm/winealsa/audio.c |   97 +++++++++++++++++++++++++++++--------------
 1 files changed, 65 insertions(+), 32 deletions(-)

diff --git a/dlls/winmm/winealsa/audio.c b/dlls/winmm/winealsa/audio.c
index d0f095f..e422fba 100644
--- a/dlls/winmm/winealsa/audio.c
+++ b/dlls/winmm/winealsa/audio.c
@@ -2062,11 +2062,8 @@ static DWORD wodPlayer_NotifyCompletions
  *
  * wodPlayer helper. Resets current output stream.
  */
-static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo)
+static	void	wodPlayer_Reset(WINE_WAVEDEV* wwo, BOOL reset)
 {
-    enum win_wm_message	msg;
-    DWORD		        param;
-    HANDLE		        ev;
     int                         err;
     TRACE("(%p)\n", wwo);
 
@@ -2086,33 +2083,62 @@ static	void	wodPlayer_Reset(WINE_WAVEDEV
     if ( (err = snd_pcm_prepare(wwo->pcm)) < 0 )
         ERR("pcm prepare failed: %s\n", snd_strerror(err));
 
-    /* remove any buffer */
-    wodPlayer_NotifyCompletions(wwo, TRUE);
-
-    wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
-    wwo->state = WINE_WS_STOPPED;
-    wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
-    /* Clear partial wavehdr */
-    wwo->dwPartialOffset = 0;
-
-    /* remove any existing message in the ring */
-    EnterCriticalSection(&wwo->msgRing.msg_crst);
-    /* return all pending headers in queue */
-    while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
-    {
-        if (msg != WINE_WM_HEADER)
+    if (reset) {
+        enum win_wm_message	msg;
+        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;
+        /* Clear partial wavehdr */
+        wwo->dwPartialOffset = 0;
+
+        /* remove any existing message in the ring */
+        EnterCriticalSection(&wwo->msgRing.msg_crst);
+        /* return all pending headers in queue */
+        while (ALSA_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
         {
-            FIXME("shouldn't have headers left\n");
-            SetEvent(ev);
-            continue;
+            if (msg != WINE_WM_HEADER)
+            {
+                FIXME("shouldn't have headers left\n");
+                SetEvent(ev);
+                continue;
+            }
+            ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
+            ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
+
+                wodNotifyClient(wwo, WOM_DONE, param, 0);
         }
-        ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
-        ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
+        RESET_OMR(&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;
 
-        wodNotifyClient(wwo, WOM_DONE, param, 0);
+            /* 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;
+            }
+            /* 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->state = WINE_WS_PAUSED;
     }
-    RESET_OMR(&wwo->msgRing);
-    LeaveCriticalSection(&wwo->msgRing.msg_crst);
 }
 
 /**************************************************************************
@@ -2133,11 +2159,18 @@ static void wodPlayer_ProcessMessages(WI
 	case WINE_WM_PAUSING:
 	    if ( snd_pcm_state(wwo->pcm) == SND_PCM_STATE_RUNNING )
 	     {
-		err = snd_pcm_pause(wwo->pcm, 1);
-		if ( err < 0 )
-		    ERR("pcm_pause failed: %s\n", snd_strerror(err));
+                if ( snd_pcm_hw_params_can_pause(wwo->hw_params) )
+		{
+		    err = snd_pcm_pause(wwo->pcm, 1);
+		    if ( err < 0 )
+			ERR("pcm_pause failed: %s\n", snd_strerror(err));
+		    wwo->state = WINE_WS_PAUSED;
+		}
+		else
+		{
+		    wodPlayer_Reset(wwo,FALSE);
+		}
 	     }
-	    wwo->state = WINE_WS_PAUSED;
 	    SetEvent(ev);
 	    break;
 	case WINE_WM_RESTARTING:
@@ -2168,7 +2201,7 @@ static void wodPlayer_ProcessMessages(WI
 		wwo->state = WINE_WS_PLAYING;
 	    break;
 	case WINE_WM_RESETTING:
-	    wodPlayer_Reset(wwo);
+	    wodPlayer_Reset(wwo,TRUE);
 	    SetEvent(ev);
 	    break;
         case WINE_WM_UPDATE:



More information about the wine-patches mailing list