some other OSS fixes

Eric Pouech eric.pouech at wanadoo.fr
Sat Jan 12 08:52:19 CST 2002


As Ori Pessach noticed, there were still bugs in OSS driver
Pyjama Sam now works correctly

A+

-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: oss_audio
ChangeLog: fixed the wodReset implementation, internal messages priority, full duplex code, wait algorithm for feeding the OSS buffer
GenDate: 2002/01/12 14:32:23 UTC
ModifiedFiles: dlls/winmm/wineoss/audio.c
AddedFiles: 
===================================================================
RCS file: /home/cvs/cvsroot/wine/wine/dlls/winmm/wineoss/audio.c,v
retrieving revision 1.49
diff -u -u -r1.49 audio.c
--- dlls/winmm/wineoss/audio.c	21 Dec 2001 20:28:43 -0000	1.49
+++ dlls/winmm/wineoss/audio.c	10 Jan 2002 19:57:21 -0000
@@ -9,7 +9,7 @@
 /*
  * FIXME:
  *	pause in waveOut does not work correctly in loop mode
- *      experimental full duples mode
+ *      experimental full duplex mode
  *      only one sound card is currently supported
  */
 
@@ -42,8 +42,6 @@
 /* Allow 1% deviation for sample rates (some ES137x cards) */
 #define NEAR_MATCH(rate1,rate2) (((100*((int)(rate1)-(int)(rate2)))/(rate1))==0)
 
-#define REFILL_BUFFER_WHEN 3/4 /* fill the buffer when it's 3/4 empty */
-
 #ifdef HAVE_OSS
 
 #define SOUND_DEV "/dev/dsp"
@@ -92,6 +90,7 @@
  * this ring will be used by the input (resp output) record (resp playback) routine
  */
 typedef struct {
+    /* FIXME: this could be made a dynamically growing array (if needed) */
 #define OSS_RING_BUFFER_SIZE	30
     OSS_MSG			messages[OSS_RING_BUFFER_SIZE];
     int				msg_tosave;
@@ -111,9 +110,6 @@
     /* OSS information */
     DWORD			dwFragmentSize;		/* size of OSS buffer fragment */
     DWORD                       dwBufferSize;           /* size of whole OSS buffer in bytes */
-    WORD                        uWaitForFragments;      /* The number of OSS buffer fragments we would like to be free
-							 * before trying to write to the DSP
-							 */
     LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
     LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
     DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
@@ -166,8 +162,8 @@
     "WINE_WM_RESETTING",
     "WINE_WM_HEADER",
     "WINE_WM_UPDATE",
-    "WINE_WM_CLOSING",
     "WINE_WM_BREAKLOOP",
+    "WINE_WM_CLOSING",
 };
 
 /*======================================================================*
@@ -178,8 +174,9 @@
 static unsigned OSS_OpenCount /* = 0 */;  /* number of times fd has been opened */
 static unsigned OSS_OpenAccess /* = 0 */; /* access used for opening... used to handle compat */
 static int      OSS_OpenFD;
-static BOOL     OSS_FullDuplex;           /* set to non-zero if the device supports full duplex */
+static DWORD    OSS_OwnerThreadID /* = 0 */;
 #endif
+static BOOL     OSS_FullDuplex;           /* set to non-zero if the device supports full duplex */
 
 /******************************************************************
  *		OSS_OpenDevice
@@ -191,6 +188,7 @@
 static int	OSS_OpenDevice(unsigned req_access)
 {
 #ifdef USE_FULLDUPLEX
+    /* FIXME: race */
     if (OSS_OpenCount == 0)
     {
 	if (access(SOUND_DEV, 0) != 0 || 
@@ -203,12 +201,22 @@
 	if (req_access == O_RDWR && OSS_FullDuplex)
 	    ioctl(OSS_OpenFD, SNDCTL_DSP_SETDUPLEX, 0);
 	OSS_OpenAccess = req_access;
+        OSS_OwnerThreadID = GetCurrentThreadId();
     }
-    else if (OSS_OpenAccess != req_access)
+    else 
     {
-	WARN("Mismatch in access...\n");
-	return -1;
+        if (OSS_OpenAccess != req_access)
+        {
+            WARN("Mismatch in access...\n");
+            return -1;
+        }
+        if (GetCurrentThreadId() == OSS_OwnerThreadID)
+        {
+            WARN("Another thread is trying to access audio...\n");
+            return -1;
+        }
     }
+
     OSS_OpenCount++;
     return OSS_OpenFD;
 #else
@@ -477,31 +485,47 @@
  */
 static int OSS_AddRingMessage(OSS_MSG_RING* omr, enum win_wm_message msg, DWORD param, BOOL wait)
 {
-    HANDLE	hEvent;
+    HANDLE	hEvent = INVALID_HANDLE_VALUE;
 
     EnterCriticalSection(&omr->msg_crst);
-    if ((omr->msg_tosave == omr->msg_toget) /* buffer overflow ? */
-	&& (omr->messages[omr->msg_toget].msg))
+    if ((omr->msg_toget == ((omr->msg_tosave + 1) % OSS_RING_BUFFER_SIZE))) /* buffer overflow ? */
     {
 	ERR("buffer overflow !?\n");
         LeaveCriticalSection(&omr->msg_crst);
 	return 0;
     }
+    if (wait)
+    {
+        hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+        if (hEvent == INVALID_HANDLE_VALUE)
+        {
+            ERR("can't create event !?\n");
+            LeaveCriticalSection(&omr->msg_crst);
+            return 0;
+        }
+        if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->msg_toget].msg != WINE_WM_HEADER)
+            FIXME("two fast messages in the queue!!!!\n");
 
-    hEvent = wait ? CreateEventA(NULL, FALSE, FALSE, NULL) : INVALID_HANDLE_VALUE;
+        /* fast messages have to be added at the start of the queue */
+        omr->msg_toget = (omr->msg_toget + OSS_RING_BUFFER_SIZE - 1) % OSS_RING_BUFFER_SIZE;
 
-    omr->messages[omr->msg_tosave].msg = msg;
-    omr->messages[omr->msg_tosave].param = param;
-    omr->messages[omr->msg_tosave].hEvent = hEvent;
-
-    omr->msg_tosave++;
-    if (omr->msg_tosave > OSS_RING_BUFFER_SIZE-1)
-	omr->msg_tosave = 0;
+        omr->messages[omr->msg_toget].msg = msg;
+        omr->messages[omr->msg_toget].param = param;
+        omr->messages[omr->msg_toget].hEvent = hEvent;
+    }
+    else
+    { 
+        omr->messages[omr->msg_tosave].msg = msg;
+        omr->messages[omr->msg_tosave].param = param;
+        omr->messages[omr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;
+        omr->msg_tosave = (omr->msg_tosave + 1) % OSS_RING_BUFFER_SIZE;
+    }
     LeaveCriticalSection(&omr->msg_crst);
     /* signal a new message */
     SetEvent(omr->msg_event);
     if (wait)
     {
+        /* wait for playback/record thread to have processed the message */
         WaitForSingleObject(hEvent, INFINITE);
         CloseHandle(hEvent);
     }
@@ -528,9 +552,7 @@
     omr->messages[omr->msg_toget].msg = 0;
     *param = omr->messages[omr->msg_toget].param;
     *hEvent = omr->messages[omr->msg_toget].hEvent;
-    omr->msg_toget++;
-    if (omr->msg_toget > OSS_RING_BUFFER_SIZE-1)
-	omr->msg_toget = 0;
+    omr->msg_toget = (omr->msg_toget + 1) % OSS_RING_BUFFER_SIZE;
     LeaveCriticalSection(&omr->msg_crst);
     return 1;
 }
@@ -646,17 +668,13 @@
 
 /**************************************************************************
  * 			     wodPlayer_DSPWait			[internal]
- * Returns the number of milliseconds to wait for the DSP buffer to clear.
- * This is based on the number of fragments we want to be clear before
- * writing and the number of free fragments we already have.
+ * Returns the number of milliseconds to wait for the DSP buffer to write 
+ * one fragment.
  */
-static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo, DWORD availInQ)
+static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo)
 {
-    DWORD       uFreeFragments = availInQ / wwo->dwFragmentSize;
-
-    return (uFreeFragments >= wwo->uWaitForFragments) 
-        ? 1 : (wwo->dwFragmentSize * 1000 / wwo->format.wf.nAvgBytesPerSec) * 
-              (wwo->uWaitForFragments - uFreeFragments);
+    /* time for one fragment to be played */
+    return wwo->dwFragmentSize * 1000 / wwo->format.wf.nAvgBytesPerSec;
 }
 
 /**************************************************************************
@@ -754,7 +772,6 @@
 static	void	wodPlayer_Reset(WINE_WAVEOUT* wwo, BOOL reset)
 {
     wodUpdatePlayedTotal(wwo, NULL);
-
     /* updates current notify list */
     wodPlayer_NotifyCompletions(wwo, FALSE);
 
@@ -767,7 +784,11 @@
     }
 
     if (reset) {
-	/* empty notify list */
+        enum win_wm_message	msg;
+        DWORD		        param;
+        HANDLE		        ev;
+
+	/* remove any buffer */
 	wodPlayer_NotifyCompletions(wwo, TRUE);
 
 	wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
@@ -775,6 +796,25 @@
 	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 (OSS_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
+        {
+            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);
+        }
+        ResetEvent(wwo->msgRing.msg_event);
+        LeaveCriticalSection(&wwo->msgRing.msg_crst);
     } else {
         if (wwo->lpLoopPtr) {
             /* complicated case, not handled yet (could imply modifying the loop counter */
@@ -890,21 +930,23 @@
     }
 
     /* no more room... no need to try to feed */
-    if (dspspace.fragments == 0) return wodPlayer_DSPWait(wwo, 0);
-
-    /* Feed from partial wavehdr */
-    if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) {
-        wodPlayer_WriteMaxFrags(wwo, &availInQ);
-    }
+    if (dspspace.fragments != 0) {
+        /* Feed from partial wavehdr */
+        if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) {
+            wodPlayer_WriteMaxFrags(wwo, &availInQ);
+        }
 
-    /* Feed wavehdrs until we run out of wavehdrs or DSP space */
-    if (wwo->dwPartialOffset == 0) while (wwo->lpPlayPtr && availInQ > 0) {
-	/* note the value that dwPlayedTotal will return when this wave finishes playing */
-	wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength;
-	wodPlayer_WriteMaxFrags(wwo, &availInQ);
+        /* Feed wavehdrs until we run out of wavehdrs or DSP space */
+        if (wwo->dwPartialOffset == 0) {
+            while (wwo->lpPlayPtr && availInQ > 0) {
+                /* note the value that dwPlayedTotal will return when this wave finishes playing */
+                wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength;
+                wodPlayer_WriteMaxFrags(wwo, &availInQ);
+            }
+        }
     }
 
-    return wodPlayer_DSPWait(wwo, availInQ);
+    return wodPlayer_DSPWait(wwo);
 }
 
 
@@ -1080,10 +1122,8 @@
     /* Remember fragsize and total buffer size for future use */
     wwo->dwFragmentSize = info.fragsize;
     wwo->dwBufferSize = info.fragstotal * info.fragsize;
-    wwo->uWaitForFragments = info.fragstotal * REFILL_BUFFER_WHEN;
     wwo->dwPlayedTotal = 0;
     wwo->dwWrittenTotal = 0;
-    TRACE("wait for %d fragments\n", wwo->uWaitForFragments);
 
     OSS_InitRingMessage(&wwo->msgRing);
 
@@ -1131,7 +1171,6 @@
 	WARN("buffers still playing !\n");
 	ret = WAVERR_STILLPLAYING;
     } else {
-	TRACE("imhere[3-close]\n");
 	if (wwo->hThread != INVALID_HANDLE_VALUE) {
 	    OSS_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE);
 	}
@@ -1174,7 +1213,6 @@
     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
     lpWaveHdr->lpNext = 0;
 
-    TRACE("imhere[3-HEADER]\n");
     OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE);
 
     return MMSYSERR_NOERROR;
@@ -1233,7 +1271,6 @@
 	return MMSYSERR_BADDEVICEID;
     }
     
-    TRACE("imhere[3-PAUSING]\n");
     OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE);
     
     return MMSYSERR_NOERROR;
@@ -1252,7 +1289,6 @@
     }
     
     if (WOutDev[wDevID].state == WINE_WS_PAUSED) {
-	TRACE("imhere[3-RESTARTING]\n");
 	OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE);
     }
     
@@ -1276,7 +1312,6 @@
 	return MMSYSERR_BADDEVICEID;
     }
     
-    TRACE("imhere[3-RESET]\n");
     OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
     
     return MMSYSERR_NOERROR;
@@ -1424,7 +1459,7 @@
 {
     DWORD	ret = 1;
     /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
-    int audio = OSS_OpenDevice(O_WRONLY);
+    int audio = OSS_OpenDevice(OSS_FullDuplex ? O_RDWR : O_WRONLY);
     
     if (audio == -1) {
 	if (errno != EBUSY)
@@ -2357,7 +2392,7 @@
 	return WAVERR_STILLPLAYING;
 
     lpWaveHdr->dwFlags |= WHDR_PREPARED;
-    lpWaveHdr->dwFlags &= ~(WHDR_INQUEUE|WHDR_DONE);
+    lpWaveHdr->dwFlags &= ~WHDR_DONE;
     lpWaveHdr->dwBytesRecorded = 0;
     TRACE("header prepared !\n");
     return MMSYSERR_NOERROR;
@@ -2374,7 +2409,7 @@
     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
 	return WAVERR_STILLPLAYING;
 
-    lpWaveHdr->dwFlags &= ~(WHDR_PREPARED|WHDR_INQUEUE);
+    lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
     lpWaveHdr->dwFlags |= WHDR_DONE;
     
     return MMSYSERR_NOERROR;


More information about the wine-patches mailing list