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@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);