wineoss patch

Ove Kaaven ovehk at ping.uio.no
Sat Sep 28 13:21:14 CDT 2002


I can imagine Eric has a better patch for the following problem:
OSS/Commercial does not allow an open device to continue operation after a
SNDCTL_DSP_RESET, the device must be reopened (which is what their API
docs recommend). The following patch is what we have in WineX to get
around the issue, but it will only compile on ReWind and Wine if the
#define FULL_DUPLEX is enabled. But perhaps it's good enough if Eric
doesn't have a better one. And I have some fullduplex patches that I can
only submit after this issue is resolved.

Log:
Ove Kaaven <ovek at transgaming.com>
Workaround for OSS/Commercial braindeadness.

Index: dlls/winmm/wineoss/audio.c
===================================================================
RCS file: /cvsroot/rewind/rewind/dlls/winmm/wineoss/audio.c,v
retrieving revision 1.61
diff -u -r1.61 audio.c
--- dlls/winmm/wineoss/audio.c	24 Sep 2002 14:27:49 -0000	1.61
+++ dlls/winmm/wineoss/audio.c	28 Sep 2002 18:07:31 -0000
@@ -349,6 +349,77 @@
 }
 
 /******************************************************************
+ *		OSS_ResetDevice
+ *
+ *
+ */
+static BOOL	OSS_ResetDevice(unsigned wDevID, int fd, unsigned req_access)
+{
+    OSS_DEVICE* ossdev;
+    int val, nfd;
+
+    if (wDevID >= MAX_WAVEDRV) return FALSE;
+    ossdev = &OSS_Devices[wDevID];
+#ifdef USE_FULLDUPLEX
+    if (fd != ossdev->fd) FIXME("What the heck????\n");
+    req_access = ossdev->open_access;
+#endif
+    TRACE("resetting device (fd=%d)\n", fd);
+    if (ioctl(fd, SNDCTL_DSP_RESET, 0) == -1) {
+	perror("ioctl SNDCTL_DSP_RESET");
+	return FALSE;
+    }
+    /* OSS/Commercial is so braindead it pours smoke out of its ears */
+    /* gotta reopen it */
+    close(fd);
+    nfd = open(ossdev->dev_name, req_access, 0);
+    if (WOutDev[wDevID].unixdev == fd) {
+        WOutDev[wDevID].unixdev = nfd;
+        WOutDev[wDevID].bNeedPost = TRUE;
+    }
+    if (WInDev[wDevID].unixdev == fd) WInDev[wDevID].unixdev = nfd;
+#ifdef USE_FULLDUPLEX
+    ossdev->fd = nfd;
+#endif
+    if ((fd = nfd) == -1)
+    {
+	ERR("Couldn't reopen %s (%s)\n", ossdev->dev_name, strerror(errno));
+	return FALSE;
+    }
+    TRACE("new fd=%d\n", fd);
+    fcntl(fd, F_SETFD, 1); /* set close on exec flag */
+    /* turn full duplex on if it has been requested */
+    if (req_access == O_RDWR && ossdev->full_duplex)
+	ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
+
+    if (ossdev->audio_fragment) ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossdev->audio_fragment);
+
+    /* First size and stereo then samplerate */
+    if (ossdev->format)
+    {
+        val = ossdev->format;
+        ioctl(fd, SNDCTL_DSP_SETFMT, &val);
+        if (val != ossdev->format)
+            ERR("Can't set format to %d (%d)\n", ossdev->format, val);
+    }
+    if (ossdev->stereo)
+    {
+        val = ossdev->stereo;
+        ioctl(fd, SNDCTL_DSP_STEREO, &val);
+        if (val != ossdev->stereo)
+            ERR("Can't set stereo to %u (%d)\n", ossdev->stereo, val);
+    }
+    if (ossdev->sample_rate)
+    {
+        val = ossdev->sample_rate;
+        ioctl(fd, SNDCTL_DSP_SPEED, &ossdev->sample_rate);
+        if (!NEAR_MATCH(val, ossdev->sample_rate))
+            ERR("Can't set sample_rate to %u (%d)\n", ossdev->sample_rate, val);
+    }
+    return TRUE;
+}
+
+/******************************************************************
  *		OSS_WaveOutInit
  *
  *
@@ -940,15 +1011,15 @@
  *
  * wodPlayer helper. Resets current output stream.
  */
-static	void	wodPlayer_Reset(WINE_WAVEOUT* wwo, BOOL reset)
+static	void	wodPlayer_Reset(WORD uDevID, WINE_WAVEOUT* wwo, BOOL reset)
 {
     wodUpdatePlayedTotal(wwo, NULL);
     /* updates current notify list */
     wodPlayer_NotifyCompletions(wwo, FALSE);
 
     /* flush all possible output */
-    if (ioctl(wwo->unixdev, SNDCTL_DSP_RESET, 0) == -1) {
-	perror("ioctl SNDCTL_DSP_RESET");
+    /* FIXME: bad for fullduplex */
+    if (!OSS_ResetDevice(uDevID, wwo->unixdev, O_WRONLY)) {
 	wwo->hThread = 0;
 	wwo->state = WINE_WS_STOPPED;
 	ExitThread(-1);
@@ -1015,7 +1086,7 @@
 /**************************************************************************
  * 		      wodPlayer_ProcessMessages			[internal]
  */
-static void wodPlayer_ProcessMessages(WINE_WAVEOUT* wwo)
+static void wodPlayer_ProcessMessages(WORD uDevID, WINE_WAVEOUT* wwo)
 {
     LPWAVEHDR           lpWaveHdr;
     enum win_wm_message	msg;
@@ -1026,7 +1097,7 @@
 	TRACE("Received %s %lx\n", wodPlayerCmdString[msg - WM_USER - 1], param);
 	switch (msg) {
 	case WINE_WM_PAUSING:
-	    wodPlayer_Reset(wwo, FALSE);
+	    wodPlayer_Reset(uDevID, wwo, FALSE);
 	    SetEvent(ev);
 	    break;
 	case WINE_WM_RESTARTING:
@@ -1051,7 +1122,7 @@
 		wwo->state = WINE_WS_PLAYING;
 	    break;
 	case WINE_WM_RESETTING:
-	    wodPlayer_Reset(wwo, TRUE);
+	    wodPlayer_Reset(uDevID, wwo, TRUE);
 	    SetEvent(ev);
 	    break;
         case WINE_WM_UPDATE:
@@ -1152,14 +1223,14 @@
         dwSleepTime = min(dwNextFeedTime, dwNextNotifyTime);
         TRACE("waiting %lums (%lu,%lu)\n", dwSleepTime, dwNextFeedTime, dwNextNotifyTime);
 	WAIT_OMR(&wwo->msgRing, dwSleepTime);
-	wodPlayer_ProcessMessages(wwo);
+	wodPlayer_ProcessMessages(uDevID, wwo);
 	if (wwo->state == WINE_WS_PLAYING) {
 	    dwNextFeedTime = wodPlayer_FeedDSP(wwo);
 	    dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE);
 	    if (dwNextFeedTime == INFINITE) {
 		/* FeedDSP ran out of data, but before flushing, */
 		/* check that a notification didn't give us more */
-		wodPlayer_ProcessMessages(wwo);
+		wodPlayer_ProcessMessages(uDevID, wwo);
 		if (!wwo->lpPlayPtr) {
 		    TRACE("flushing\n");
 		    ioctl(wwo->unixdev, SNDCTL_DSP_SYNC, 0);




More information about the wine-patches mailing list