Eric wrote:
could the people who had issues with the latest OSS patch(es) test if this one fixes all their issues ?
This patch causes both Riven and Myst to immediately freeze for me, and no sound at all. Without the patch, the sound in Myst works pretty good (occasional brief dropouts). In Riven without the patch, only the opening sequence has sound, and that has many large dropouts. I'm using ALSA drivers in Redhat. Duane
Duane Clark wrote:
Eric wrote:
could the people who had issues with the latest OSS patch(es) test if this one fixes all their issues ?
This patch causes both Riven and Myst to immediately freeze for me, and no sound at all. Without the patch, the sound in Myst works pretty good (occasional brief dropouts). In Riven without the patch, only the opening sequence has sound, and that has many large dropouts. I'm using ALSA drivers in Redhat.
could you send me a -debugmsg +wave trace. thanks A+ -- --------------- Eric Pouech (http://perso.wanadoo.fr/eric.pouech/) "The future will be better tomorrow", Vice President Dan Quayle
Duane Clark wrote:
Eric wrote:
could the people who had issues with the latest OSS patch(es) test if this one fixes all their issues ?
This patch causes both Riven and Myst to immediately freeze for me, and no sound at all. Without the patch, the sound in Myst works pretty good (occasional brief dropouts). In Riven without the patch, only the opening sequence has sound, and that has many large dropouts. I'm using ALSA drivers in Redhat.
thanks for the traces... could you use this patch instead ? (forgot to wake up a caller somewhere :-( A+ -- --------------- Eric Pouech (http://perso.wanadoo.fr/eric.pouech/) "The future will be better tomorrow", Vice President Dan Quayle Index: dlls/winmm/wineoss/audio.c =================================================================== RCS file: /usr/share/cvs/cvsroot/wine/wine/dlls/winmm/wineoss/audio.c,v retrieving revision 1.47 diff -u -r1.47 audio.c --- dlls/winmm/wineoss/audio.c 2001/11/19 02:10:50 1.47 +++ dlls/winmm/wineoss/audio.c 2001/12/11 07:06:47 @@ -82,6 +82,7 @@ #define WINE_WM_RESETTING (WM_USER + 3) #define WINE_WM_CLOSING (WM_USER + 4) #define WINE_WM_HEADER (WM_USER + 5) +#define WINE_WM_UPDATE (WM_USER + 6) typedef struct { int msg; /* message identifier */ @@ -89,9 +90,9 @@ HANDLE hEvent; /* if message is synchronous, handle of event for synchro */ } OSS_MSG; -/* implement a in process message ring for better performance +/* implement an in-process message ring for better performance * (compared to passing thru the server) - * this ring will be used by both the input & output plauback + * this ring will be used by the input (resp output) record (resp playback) routine */ typedef struct { #define OSS_RING_BUFFER_SIZE 30 @@ -105,39 +106,32 @@ typedef struct { int unixdev; volatile int state; /* one of the WINE_WS_ manifest constants */ + WAVEOPENDESC waveDesc; + WORD wFlags; + PCMWAVEFORMAT format; + WAVEOUTCAPSA caps; + + /* OSS information */ DWORD dwFragmentSize; /* size of OSS buffer fragment */ - DWORD dwBufferSize; /* size of whole OSS buffer in bytes - * used to compute dwPlayedTotal from dwWrittenTotal and - * ioctl GETOSPACE info - */ + 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 */ - DWORD dwMillisPerFragment; /* The number of milliseconds of sound in each OSS buffer - * fragment - */ - WAVEOPENDESC waveDesc; - WORD wFlags; - PCMWAVEFORMAT format; 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 */ - /* info on current lpPlayPtr->lpWaveHdr */ - LPSTR lpPartialData; /* Data still to write on current wavehdr */ - DWORD dwPartialBytes; /* number of bytes to write to end current wavehdr */ - LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */ DWORD dwLoops; /* private copy of loop counter */ - DWORD dwPlayedTotal; /* number of bytes played since opening */ - DWORD dwWrittenTotal; /* number of bytes written since opening */ + DWORD dwPlayedTotal; /* number of bytes actually played since opening */ + DWORD dwWrittenTotal; /* number of bytes written to OSS buffer since opening */ /* synchronization stuff */ HANDLE hStartUpEvent; HANDLE hThread; DWORD dwThreadID; OSS_MSG_RING msgRing; - WAVEOUTCAPSA caps; /* DirectSound stuff */ LPBYTE mapping; @@ -174,7 +168,8 @@ "WINE_WM_RESTARTING", "WINE_WM_RESETTING", "WINE_WM_CLOSING", - "WINE_WM_HEADER" }; + "WINE_WM_HEADER", + "WINE_WM_UPDATE" }; /*======================================================================* * Low level WAVE implementation * @@ -378,56 +373,6 @@ return 0; } -/************************************************************************** - * OSS_NotifyClient [internal] - */ -static DWORD OSS_NotifyClient(UINT wDevID, WORD wMsg, DWORD dwParam1, DWORD dwParam2) -{ - TRACE("wDevID = %04X wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2); - - switch (wMsg) { - case WOM_OPEN: - case WOM_CLOSE: - case WOM_DONE: - if (wDevID >= MAX_WAVEOUTDRV) return MCIERR_INTERNAL; - - if (WOutDev[wDevID].wFlags != DCB_NULL && - !DriverCallback(WOutDev[wDevID].waveDesc.dwCallback, - WOutDev[wDevID].wFlags, - WOutDev[wDevID].waveDesc.hWave, - wMsg, - WOutDev[wDevID].waveDesc.dwInstance, - dwParam1, - dwParam2)) { - WARN("can't notify client !\n"); - return MMSYSERR_NOERROR; - } - break; - - case WIM_OPEN: - case WIM_CLOSE: - case WIM_DATA: - if (wDevID >= MAX_WAVEINDRV) return MCIERR_INTERNAL; - - if (WInDev[wDevID].wFlags != DCB_NULL && - !DriverCallback(WInDev[wDevID].waveDesc.dwCallback, - WInDev[wDevID].wFlags, - WInDev[wDevID].waveDesc.hWave, - wMsg, - WInDev[wDevID].waveDesc.dwInstance, - dwParam1, - dwParam2)) { - WARN("can't notify client !\n"); - return MMSYSERR_NOERROR; - } - break; - default: - FIXME("Unknown CB message %u\n", wMsg); - break; - } - return 0; -} - static int OSS_InitRingMessage(OSS_MSG_RING* omr) { omr->msg_toget = 0; @@ -497,24 +442,38 @@ *======================================================================*/ /************************************************************************** - * updatePlayedTotal [internal] - * - * Calculates wwo->dwPlayed total from wwo->dwWrittenTotal and the amount - * still remaining in the OSS buffer. + * wodNotifyClient [internal] */ -static DWORD updatePlayedTotal( WINE_WAVEOUT* wwo ) +static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2) { - audio_buf_info info; - - if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &info) < 0) { - ERR("ioctl failed (%s)\n", strerror(errno)); - return wwo->dwPlayedTotal; + TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2); + + switch (wMsg) { + case WOM_OPEN: + case WOM_CLOSE: + case WOM_DONE: + if (wwo->wFlags != DCB_NULL && + !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags, wwo->waveDesc.hWave, + wMsg, wwo->waveDesc.dwInstance, dwParam1, dwParam2)) { + WARN("can't notify client !\n"); + return MMSYSERR_ERROR; + } + break; + default: + FIXME("Unknown CB message %u\n", wMsg); + return MMSYSERR_INVALPARAM; } - - wwo->dwPlayedTotal=wwo->dwWrittenTotal-( wwo->dwBufferSize - info.bytes ); - return wwo->dwPlayedTotal; + return MMSYSERR_NOERROR; } +/************************************************************************** + * wodUpdatePlayedTotal [internal] + * + */ +static void wodUpdatePlayedTotal(WINE_WAVEOUT* wwo, DWORD availInQ) +{ + wwo->dwPlayedTotal = wwo->dwWrittenTotal - (wwo->dwBufferSize - availInQ); +} /************************************************************************** * wodPlayer_BeginWaveHdr [internal] @@ -523,12 +482,11 @@ * If the specified wave header is a begin loop and we're not already in * a loop, setup the loop. */ -static void wodPlayer_BeginWaveHdr( WINE_WAVEOUT* wwo, - LPWAVEHDR lpWaveHdr ) +static void wodPlayer_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr) { - wwo->lpPlayPtr=lpWaveHdr; + wwo->lpPlayPtr = lpWaveHdr; - if( !lpWaveHdr ) return; + if (!lpWaveHdr) return; if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP) { if (wwo->lpLoopPtr) { @@ -541,6 +499,7 @@ wwo->dwLoops = lpWaveHdr->dwLoops; } } + wwo->dwPartialOffset = 0; } /************************************************************************** @@ -550,8 +509,9 @@ */ static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEOUT* wwo) { - LPWAVEHDR lpWaveHdr=wwo->lpPlayPtr; + LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr; + wwo->dwPartialOffset = 0; if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) { /* We're at the end of a loop, loop if required */ if (--wwo->dwLoops > 0) { @@ -564,17 +524,17 @@ * the opening one or for both ??? * code assumes for closing loop only */ - wwo->lpLoopPtr = NULL; - wodPlayer_BeginWaveHdr( wwo, lpWaveHdr ); } else { - wwo->lpLoopPtr = NULL; - wodPlayer_BeginWaveHdr( wwo, lpWaveHdr=lpWaveHdr->lpNext ); - } + lpWaveHdr = lpWaveHdr->lpNext; + } + wwo->lpLoopPtr = NULL; + wodPlayer_BeginWaveHdr(wwo, lpWaveHdr); } } else { /* We're not in a loop. Advance to the next wave header */ - wodPlayer_BeginWaveHdr( wwo, lpWaveHdr=lpWaveHdr->lpNext ); + wodPlayer_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext); } + return lpWaveHdr; } @@ -584,11 +544,13 @@ * This is based on the number of fragments we want to be clear before * writing and the number of free fragments we already have. */ -static DWORD wodPlayer_DSPWait( WINE_WAVEOUT *wwo, WORD uFreeFragments ) +static DWORD wodPlayer_DSPWait(const WINE_WAVEOUT *wwo, DWORD availInQ) { - return (uFreeFragments>wwo->uWaitForFragments)?1: - wwo->dwMillisPerFragment* - (wwo->uWaitForFragments-uFreeFragments); + DWORD uFreeFragments = availInQ / wwo->dwFragmentSize; + + return (uFreeFragments >= wwo->uWaitForFragments) + ? 1 : (wwo->dwFragmentSize * 1000 / wwo->format.wf.nAvgBytesPerSec) * + (wwo->uWaitForFragments - uFreeFragments); } /************************************************************************** @@ -598,20 +560,15 @@ * This is based on the number of bytes remaining to be written in the * wave. */ -static DWORD wodPlayer_NotifyWait( WINE_WAVEOUT *wwo, LPWAVEHDR lpWaveHdr ) +static DWORD wodPlayer_NotifyWait(const WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr) { DWORD dwMillis; - if( lpWaveHdr->reserved<wwo->dwPlayedTotal ) { - dwMillis=1; + if (lpWaveHdr->reserved < wwo->dwPlayedTotal) { + dwMillis = 1; } else { - dwMillis=(lpWaveHdr->reserved-wwo->dwPlayedTotal) * - wwo->dwMillisPerFragment / wwo->dwFragmentSize; - TRACE( "wait for %lu bytes = %lu\n", - (lpWaveHdr->reserved-wwo->dwPlayedTotal), - dwMillis ); - if( dwMillis < 1 ) - dwMillis=1; + dwMillis = (lpWaveHdr->reserved - wwo->dwPlayedTotal) * 1000 / wwo->format.wf.nAvgBytesPerSec; + if (!dwMillis) dwMillis = 1; } return dwMillis; @@ -621,26 +578,29 @@ /************************************************************************** * wodPlayer_WriteMaxFrags [internal] * Writes the maximum number of bytes possible to the DSP and returns - * the number of bytes written. Also updates fragments in dspspace. + * the number of bytes written. */ -static DWORD wodPlayer_WriteMaxFrags( WINE_WAVEOUT *wwo, LPSTR lpData, - DWORD dwLength, - audio_buf_info* dspspace ) -{ - /* Only attempt to write to free fragments */ - int maxWrite=dspspace->fragments*dspspace->fragsize; - int toWrite=min(dwLength,maxWrite); - - int written=write(wwo->unixdev, lpData, toWrite); - - TRACE("wrote %d of %lu bytes\n", - written, dwLength ); - if( written > 0 ) { - /* Keep a count of the total bytes written to the DSP */ - wwo->dwWrittenTotal+=written; - /* reduce the number of free fragments */ - dspspace->fragments -= (written/dspspace->fragsize)+(written%dspspace->fragsize>0); +static int wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes) +{ + /* Only attempt to write to free bytes */ + DWORD dwLength = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset; + int toWrite = min(dwLength, *bytes); + int written; + + TRACE("Writing wavehdr %p.%lu[%lu]\n", + wwo->lpPlayPtr, wwo->dwPartialOffset, wwo->lpPlayPtr->dwBufferLength); + written = write(wwo->unixdev, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toWrite); + if (written <= 0) return written; + + if (written >= dwLength) { + /* If we wrote all current wavehdr, skip to the next one */ + wodPlayer_PlayPtrNext(wwo); + } else { + /* Remove the amount written */ + wwo->dwPartialOffset += written; } + *bytes -= written; + wwo->dwWrittenTotal += written; return written; } @@ -654,37 +614,30 @@ * we notify all wavehdrs and remove them all from the queue even if they * are unplayed or part of a loop. */ -static DWORD wodPlayer_NotifyCompletions( WINE_WAVEOUT* wwo, WORD uDevID, BOOL force) +static DWORD wodPlayer_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force) { LPWAVEHDR lpWaveHdr; - updatePlayedTotal(wwo); /* Start from lpQueuePtr and keep notifying until: * - we hit an unwritten wavehdr * - we hit the beginning of a running loop * - we hit a wavehdr which hasn't finished playing */ - while( (lpWaveHdr=wwo->lpQueuePtr) && - (force || - (lpWaveHdr != wwo->lpPlayPtr && - lpWaveHdr != wwo->lpLoopPtr && - lpWaveHdr->reserved <= wwo->dwPlayedTotal ))) { + while ((lpWaveHdr = wwo->lpQueuePtr) && + (force || + (lpWaveHdr != wwo->lpPlayPtr && + lpWaveHdr != wwo->lpLoopPtr && + lpWaveHdr->reserved <= wwo->dwPlayedTotal))) { wwo->lpQueuePtr = lpWaveHdr->lpNext; lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; - TRACE("Notifying client with %p\n", lpWaveHdr); - if (OSS_NotifyClient(uDevID, WOM_DONE, (DWORD)lpWaveHdr, 0) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - } + wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0); } - return ( lpWaveHdr && - lpWaveHdr != wwo->lpPlayPtr && - lpWaveHdr != wwo->lpLoopPtr ) ? - wodPlayer_NotifyWait( wwo, lpWaveHdr ) : - 0 ; + return (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != wwo->lpLoopPtr) ? + wodPlayer_NotifyWait(wwo, lpWaveHdr) : INFINITE; } /************************************************************************** @@ -692,10 +645,10 @@ * * wodPlayer helper. Resets current output stream. */ -static void wodPlayer_Reset(WINE_WAVEOUT* wwo, WORD uDevID, BOOL reset) +static void wodPlayer_Reset(WINE_WAVEOUT* wwo, BOOL reset) { /* updates current notify list */ - wodPlayer_NotifyCompletions(wwo, uDevID, FALSE); + wodPlayer_NotifyCompletions(wwo, FALSE); /* flush all possible output */ if (ioctl(wwo->unixdev, SNDCTL_DSP_RESET, 0) == -1) { @@ -706,60 +659,27 @@ } /* Clear partial wavehdr */ - wwo->dwPartialBytes=0; - wwo->lpPartialData=NULL; + wwo->dwPartialOffset = 0; if (reset) { /* empty notify list */ - wodPlayer_NotifyCompletions(wwo, uDevID, TRUE); + wodPlayer_NotifyCompletions(wwo, TRUE); wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL; wwo->state = WINE_WS_STOPPED; wwo->dwPlayedTotal = 0; - wwo->dwWrittenTotal = 0; + wwo->dwWrittenTotal = 0; } else { - /* FIXME: this is not accurate when looping, but can be do better ? */ + /* FIXME: this is not accurate when looping, but can we do better ? */ wwo->lpPlayPtr = (wwo->lpLoopPtr) ? wwo->lpLoopPtr : wwo->lpQueuePtr; wwo->state = WINE_WS_PAUSED; } } /************************************************************************** - * wodPlayer_AwaitEvent [internal] - * Wait for a command to be sent to the wodPlayer or for time to pass - * until wodPlayer needs to do something again. - */ -static void wodPlayer_AwaitEvent( WINE_WAVEOUT* wwo, - DWORD dwNextFeedTime, - DWORD dwNextNotifyTime ) -{ - DWORD dwSleepTime; - - /** Wait for the shortest time before an action is required. If there - * are no pending actions, wait forever for a command. - */ - if( dwNextFeedTime == 0 ) { - if( dwNextNotifyTime == 0 ) - dwSleepTime=INFINITE; - else - dwSleepTime=dwNextNotifyTime; - } else { - if( dwNextNotifyTime == 0 ) - dwSleepTime=dwNextFeedTime; - else - dwSleepTime=min( dwNextFeedTime, dwNextNotifyTime ); - } - TRACE( "waiting %lu millis (%lu,%lu)\n", dwSleepTime, - dwNextFeedTime,dwNextNotifyTime ); - WaitForSingleObject(wwo->msgRing.msg_event, dwSleepTime); - TRACE( "wait returned\n"); - -} - -/************************************************************************** * wodPlayer_ProcessMessages [internal] */ -static void wodPlayer_ProcessMessages( WINE_WAVEOUT* wwo, WORD uDevID ) +static void wodPlayer_ProcessMessages(WINE_WAVEOUT* wwo) { LPWAVEHDR lpWaveHdr; int msg; @@ -767,11 +687,10 @@ HANDLE ev; while (OSS_RetrieveRingMessage(&wwo->msgRing, &msg, ¶m, &ev)) { - TRACE( "Received %s %lx\n", - wodPlayerCmdString[msg-WM_USER-1], param ); + TRACE("Received %s %lx\n", wodPlayerCmdString[msg - WM_USER - 1], param); switch (msg) { case WINE_WM_PAUSING: - wodPlayer_Reset(wwo, uDevID, FALSE); + wodPlayer_Reset(wwo, FALSE); wwo->state = WINE_WS_PAUSED; SetEvent(ev); break; @@ -788,12 +707,13 @@ for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext)); *wh = lpWaveHdr; } - wodPlayer_BeginWaveHdr(wwo,lpWaveHdr); + if (!wwo->lpPlayPtr) + wodPlayer_BeginWaveHdr(wwo,lpWaveHdr); if (wwo->state == WINE_WS_STOPPED) wwo->state = WINE_WS_PLAYING; break; case WINE_WM_RESETTING: - wodPlayer_Reset(wwo, uDevID, TRUE); + wodPlayer_Reset(wwo, TRUE); SetEvent(ev); break; case WINE_WM_CLOSING: @@ -804,6 +724,18 @@ SetEvent(ev); ExitThread(0); /* shouldn't go here */ + case WINE_WM_UPDATE: + { + audio_buf_info info; + + if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &info) < 0) { + ERR("ioctl failed (%s)\n", strerror(errno)); + } else { + wodUpdatePlayedTotal(wwo, info.bytes); + } + } + SetEvent(ev); + break; default: FIXME("unknown message %d\n", msg); break; @@ -816,77 +748,45 @@ * Feed as much sound data as we can into the DSP and return the number of * milliseconds before it will be necessary to feed the DSP again. */ -static DWORD wodPlayer_FeedDSP( WINE_WAVEOUT* wwo ) +static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo) { - LPWAVEHDR lpWaveHdr=wwo->lpPlayPtr; - DWORD written=0; - DWORD bytesToWrite; audio_buf_info dspspace; + DWORD availInQ; - /* Read output space info so we know how much writing to do */ if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &dspspace) < 0) { - ERR("IOCTL can't 'SNDCTL_DSP_GETOSPACE' !\n"); + ERR("IOCTL can't 'SNDCTL_DSP_GETOSPACE' !\n"); + return INFINITE; } - - TRACE( "fragments=%d, fragsize=%d, fragstotal=%d, bytes=%d\n", - dspspace.fragments, dspspace.fragsize, - dspspace.fragstotal, dspspace.bytes ); + TRACE("fragments=%d/%d, fragsize=%d, bytes=%d\n", + dspspace.fragments, dspspace.fragstotal, dspspace.fragsize, dspspace.bytes); - /* Do nothing if the DSP isn't hungry */ - if( dspspace.fragments==0 ) { - return wodPlayer_DSPWait(wwo,dspspace.fragments); - } + availInQ = dspspace.bytes; + wodUpdatePlayedTotal(wwo, availInQ); - /* If there's a partially written wavehdr, feed more of it - * ------------------------------------------------------- - */ - bytesToWrite=wwo->dwPartialBytes; - if( bytesToWrite > 0 ) { - TRACE("partial write %lu bytes at %p\n", - wwo->dwPartialBytes, - wwo->lpPartialData ); - written=wodPlayer_WriteMaxFrags( wwo, wwo->lpPartialData, - bytesToWrite, - &dspspace ); - if( written >= bytesToWrite ) { - /* If we wrote it all, skip to the next header */ - wwo->dwPartialBytes=0; - wwo->lpPartialData=NULL; - lpWaveHdr=wodPlayer_PlayPtrNext( wwo ); - } else { - /* Remove the amount written */ - wwo->lpPartialData+=written; - wwo->dwPartialBytes-=written; - } + /* input queue empty and output buffer with less than one fragment to play */ + if (!wwo->lpPlayPtr && wwo->dwBufferSize < availInQ + 2 * wwo->dwFragmentSize) { + TRACE("Run out of wavehdr:s... flushing\n"); + ioctl(wwo->unixdev, SNDCTL_DSP_SYNC, 0); + wodUpdatePlayedTotal(wwo, wwo->dwBufferSize); + return INFINITE; } - /* Feed wavehdrs until we run out of wavehdrs or DSP space - * ------------------------------------------------------- - */ - while( lpWaveHdr && dspspace.fragments > 0 ) { - TRACE( "Writing wavehdr %p %lu bytes\n", lpWaveHdr, - lpWaveHdr->dwBufferLength ); + /* no more room... no need to try to feed */ + if (dspspace.fragments == 0) return wodPlayer_DSPWait(wwo, 0); - /* note the value that dwPlayedTotal will be when this - * wave finishes playing - */ - lpWaveHdr->reserved=wwo->dwWrittenTotal+lpWaveHdr->dwBufferLength; + /* Feed from partial wavehdr */ + if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0) { + wodPlayer_WriteMaxFrags(wwo, &availInQ); + } - written=wodPlayer_WriteMaxFrags( wwo, lpWaveHdr->lpData, - lpWaveHdr->dwBufferLength, - &dspspace ); - /* If it's all written, on to the next one, else remember the - * partial write for next FeedDSP call. - */ - if( written >= lpWaveHdr->dwBufferLength ) { - lpWaveHdr=wodPlayer_PlayPtrNext( wwo ); - } else { - wwo->dwPartialBytes=lpWaveHdr->dwBufferLength-written; - wwo->lpPartialData=lpWaveHdr->lpData+written; - } + /* 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 lpWaveHdr ? wodPlayer_DSPWait(wwo,dspspace.fragments) : 0 ; + return wodPlayer_DSPWait(wwo, availInQ); } @@ -897,20 +797,26 @@ { WORD uDevID = (DWORD)pmt; WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)&WOutDev[uDevID]; - DWORD dwNextFeedTime=0; /* Time before DSP needs feeding */ - DWORD dwNextNotifyTime=0; /* Time before next wave completion */ + DWORD dwNextFeedTime = INFINITE; /* Time before DSP needs feeding */ + DWORD dwNextNotifyTime = INFINITE; /* Time before next wave completion */ + DWORD dwSleepTime; - wwo->state=WINE_WS_STOPPED; - SetEvent( wwo->hStartUpEvent ); + wwo->state = WINE_WS_STOPPED; + SetEvent(wwo->hStartUpEvent); - for(;;) { - wodPlayer_AwaitEvent(wwo,dwNextFeedTime,dwNextNotifyTime); - wodPlayer_ProcessMessages(wwo,uDevID); - if( wwo->state== WINE_WS_PLAYING ) { - dwNextFeedTime=wodPlayer_FeedDSP(wwo); - dwNextNotifyTime=wodPlayer_NotifyCompletions(wwo,uDevID,FALSE); + for (;;) { + /** Wait for the shortest time before an action is required. If there + * are no pending actions, wait forever for a command. + */ + dwSleepTime = min(dwNextFeedTime, dwNextNotifyTime); + TRACE("waiting %lums (%lu,%lu)\n", dwSleepTime, dwNextFeedTime, dwNextNotifyTime); + WaitForSingleObject(wwo->msgRing.msg_event, dwSleepTime); + wodPlayer_ProcessMessages(wwo); + if (wwo->state == WINE_WS_PLAYING) { + dwNextFeedTime = wodPlayer_FeedDSP(wwo); + dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE); } else { - dwNextFeedTime=dwNextNotifyTime=0; + dwNextFeedTime = dwNextNotifyTime = INFINITE; } } } @@ -1039,7 +945,7 @@ if (dsp_stereo != (wwo->format.wf.nChannels > 1) ? 1 : 0) ERR("Can't set stereo to %u (%d)\n", (wwo->format.wf.nChannels > 1) ? 1 : 0, dsp_stereo); - if (!NEAR_MATCH(sample_rate,wwo->format.wf.nSamplesPerSec)) + if (!NEAR_MATCH(sample_rate, wwo->format.wf.nSamplesPerSec)) ERR("Can't set sample_rate to %lu (%d)\n", wwo->format.wf.nSamplesPerSec, sample_rate); @@ -1062,11 +968,10 @@ /* Remember fragsize and total buffer size for future use */ wwo->dwFragmentSize = info.fragsize; wwo->dwBufferSize = info.fragstotal * info.fragsize; - wwo->dwMillisPerFragment = info.fragsize * 1000 / wwo->format.wf.nAvgBytesPerSec; wwo->uWaitForFragments = info.fragstotal * REFILL_BUFFER_WHEN; - TRACE( "wait for %d fragments at %lu millis/fragment\n", - wwo->uWaitForFragments, - wwo->dwMillisPerFragment ); + wwo->dwPlayedTotal = 0; + wwo->dwWrittenTotal = 0; + TRACE("wait for %d fragments\n", wwo->uWaitForFragments); OSS_InitRingMessage(&wwo->msgRing); @@ -1091,11 +996,7 @@ wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels, wwo->format.wf.nBlockAlign); - if (OSS_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - return MMSYSERR_INVALPARAM; - } - return MMSYSERR_NOERROR; + return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L); } /************************************************************************** @@ -1130,10 +1031,7 @@ close(wwo->unixdev); wwo->unixdev = -1; wwo->dwFragmentSize = 0; - if (OSS_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - ret = MMSYSERR_INVALPARAM; - } + ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L); } return ret; } @@ -1246,10 +1144,7 @@ /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */ /* FIXME: Myst crashes with this ... hmm -MM - if (OSS_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - return MMSYSERR_INVALPARAM; - } + return wodNotifyClient(wwo, WOM_DONE, 0L, 0L); */ return MMSYSERR_NOERROR; @@ -1293,7 +1188,8 @@ if (lpTime == NULL) return MMSYSERR_INVALPARAM; wwo = &WOutDev[wDevID]; - val = updatePlayedTotal(wwo); + OSS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE); + val = wwo->dwPlayedTotal; TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n", lpTime->wType, wwo->format.wBitsPerSample, @@ -1307,7 +1203,7 @@ TRACE("TIME_BYTES=%lu\n", lpTime->u.cb); break; case TIME_SAMPLES: - lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample; + lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels; TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample); break; case TIME_SMPTE: @@ -1353,7 +1249,7 @@ return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) { - WARN("unable read mixer !\n"); + WARN("unable to read mixer !\n"); return MMSYSERR_NOTENABLED; } close(mixer); @@ -1385,7 +1281,7 @@ return MMSYSERR_NOTENABLED; } if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) { - WARN("unable set mixer !\n"); + WARN("unable to set mixer !\n"); return MMSYSERR_NOTENABLED; } else { TRACE("volume=%04x\n", (unsigned)volume); @@ -1497,14 +1393,14 @@ /* for some reason, es1371 and sblive! sometimes have junk in here. * clear it, or we get junk noise */ /* some libc implementations are buggy: their memset reads from the buffer... - * to work around it, we have the 0 the block by hand and do not call: - * memset(wwo->mapping,0,wwo->maplen); + * to work around it, we have to zero the block by hand. We don't do the expected: + * memset(wwo->mapping,0, wwo->maplen); */ { char* p1 = wwo->mapping; unsigned len = wwo->maplen; - if (len >= 16) /* so we can have at least a 4 longs to store... */ + if (len >= 16) /* so we can have at least a 4 long area to store... */ { /* the mmap:ed value is (at least) dword aligned * so, start filling the complete unsigned long:s @@ -1902,6 +1798,31 @@ *======================================================================*/ /************************************************************************** + * widNotifyClient [internal] + */ +static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2) +{ + TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2); + + switch (wMsg) { + case WIM_OPEN: + case WIM_CLOSE: + case WIM_DATA: + if (wwi->wFlags != DCB_NULL && + !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags, wwi->waveDesc.hWave, + wMsg, wwi->waveDesc.dwInstance, dwParam1, dwParam2)) { + WARN("can't notify client !\n"); + return MMSYSERR_ERROR; + } + break; + default: + FIXME("Unknown CB message %u\n", wMsg); + return MMSYSERR_INVALPARAM; + } + return MMSYSERR_NOERROR; +} + +/************************************************************************** * widGetDevCaps [internal] */ static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSA lpCaps, DWORD dwSize) @@ -1929,10 +1850,7 @@ WAVEHDR* lpWaveHdr; DWORD dwSleepTime; DWORD bytesRead; - LPVOID buffer = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - wwi->dwFragmentSize); - + LPVOID buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wwi->dwFragmentSize); LPVOID pOffset = buffer; audio_buf_info info; int xs; @@ -1997,11 +1915,7 @@ lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; - if (OSS_NotifyClient(uDevID, WIM_DATA, - (DWORD)lpWaveHdr, 0) != MMSYSERR_NOERROR) - { - WARN("can't notify client !\n"); - } + widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); lpWaveHdr = wwi->lpQueuePtr = lpNext; } } @@ -2041,11 +1955,7 @@ lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; - if (OSS_NotifyClient(uDevID, WIM_DATA, - (DWORD)lpWaveHdr, 0) != MMSYSERR_NOERROR) - { - WARN("can't notify client !\n"); - } + widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); wwi->lpQueuePtr = lpWaveHdr = lpNext; if (!lpNext && bytesRead) { @@ -2116,10 +2026,7 @@ lpWaveHdr->dwFlags &= ~WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_DONE; - if (OSS_NotifyClient(uDevID, WIM_DATA, - (DWORD)lpWaveHdr, 0) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - } + widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0); } wwi->lpQueuePtr = NULL; SetEvent(ev); @@ -2258,11 +2165,7 @@ CloseHandle(wwi->hStartUpEvent); wwi->hStartUpEvent = INVALID_HANDLE_VALUE; - if (OSS_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - return MMSYSERR_INVALPARAM; - } - return MMSYSERR_NOERROR; + return widNotifyClient(wwi, WIM_OPEN, 0L, 0L); } /************************************************************************** @@ -2289,11 +2192,7 @@ close(wwi->unixdev); wwi->unixdev = -1; wwi->dwFragmentSize = 0; - if (OSS_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { - WARN("can't notify client !\n"); - return MMSYSERR_INVALPARAM; - } - return MMSYSERR_NOERROR; + return widNotifyClient(wwi, WIM_CLOSE, 0L, 0L); } /**************************************************************************
eric pouech wrote:
thanks for the traces... could you use this patch instead ? (forgot to wake up a caller somewhere :-( A+
That one works great. Both Myst and Riven work, and for the first time in Riven all the sound works. There is slight bit of static in the sound, though part of that might be cheap sound hardware (onboard VIA 82C686A - which never gives particularly good sound). Duane
I'm not sure if this is the chip used with the via 8233(or with vt1611a with the same problem) chipset but there is a known ALSA(if I recall correctly that you are using ALSA) bug with this chipset that causes a lot of noise if the audio stream isn't 48Khz. I have this problem with my via on board sound, not sure when it will be fixed. Chris On Tue, 11 Dec 2001, Duane Clark wrote:
eric pouech wrote:
thanks for the traces... could you use this patch instead ? (forgot to wake up a caller somewhere :-( A+
That one works great. Both Myst and Riven work, and for the first time in Riven all the sound works. There is slight bit of static in the sound, though part of that might be cheap sound hardware (onboard VIA 82C686A - which never gives particularly good sound).
Duane
On Tue, Dec 11, 2001 at 08:10:05AM +0100, eric pouech wrote:
Duane Clark wrote:
Eric wrote:
could the people who had issues with the latest OSS patch(es) test if this one fixes all their issues ?
Tested it with Quicktime and sound works now flawlessly. Good work.
This patch causes both Riven and Myst to immediately freeze for me, and no sound at all. Without the patch, the sound in Myst works pretty good (occasional brief dropouts). In Riven without the patch, only the opening sequence has sound, and that has many large dropouts. I'm using ALSA drivers in Redhat.
thanks for the traces... could you use this patch instead ? (forgot to wake up a caller somewhere :-(
bye michael -- Michael Stefaniuc Tel.: +49-711-96437-199 System Administration Fax.: +49-711-96437-111 Red Hat GmbH Email: mstefani(a)redhat.de Hauptstaetterstr. 58 http://www.redhat.de/ D-70178 Stuttgart
Smod, a module player that was broken, now works. The intro movie to Sid Meier's Alpha Centauri still has sound that comes and goes though. A have a trace +wave available on http://www.lysator.liu.se/~johane/terran.txt. I hope it's sufficient. /Johan Gill, johane(a)lysator.liu.se
The intro movie to Sid Meier's Alpha Centauri still has sound that comes and goes though. A have a trace +wave available on http://www.lysator.liu.se/~johane/terran.txt. I hope it's sufficient. it uses the dsound interface, not the plain waveOut interface this will need to be looked upon separately A+ --
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/) "The future will be better tomorrow", Vice President Dan Quayle
participants (6)
-
Christopher Morgan -
Duane Clark -
Duane Clark -
eric pouech -
Johan Gill -
Michael Stefaniuc