could the people who had issues with the latest OSS patch(es) test if this one fixes all their issues ? TIA 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/10 20:15:30 @@ -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,28 @@ /************************************************************************** * 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\n", wwo->lpPlayPtr, wwo->dwPartialOffset); + written = write(wwo->unixdev, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toWrite); + if (written <= 0) return written; + + if (written >= dwLength) { + /* If we wrote it all, skip to the next header */ + wodPlayer_PlayPtrNext(wwo); + } else { + /* Remove the amount written */ + wwo->dwPartialOffset += written; } + *bytes -= written; + wwo->dwWrittenTotal += written; return written; } @@ -654,37 +613,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 +644,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,17 +658,16 @@ } /* 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 ? */ wwo->lpPlayPtr = (wwo->lpLoopPtr) ? wwo->lpLoopPtr : wwo->lpQueuePtr; @@ -725,41 +676,9 @@ } /************************************************************************** - * 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 +686,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 +706,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 +723,17 @@ 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); + } + } + break; default: FIXME("unknown message %d\n", msg); break; @@ -816,77 +746,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/%d, fragsize=%d, bytes=%d\n", + dspspace.fragments, dspspace.fragstotal, dspspace.fragsize, dspspace.bytes); - TRACE( "fragments=%d, fragsize=%d, fragstotal=%d, bytes=%d\n", - dspspace.fragments, dspspace.fragsize, - dspspace.fragstotal, dspspace.bytes ); + availInQ = dspspace.bytes; + wodUpdatePlayedTotal(wwo, availInQ); - /* Do nothing if the DSP isn't hungry */ - if( dspspace.fragments==0 ) { - return wodPlayer_DSPWait(wwo,dspspace.fragments); - } - - /* 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 +795,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 +943,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 +966,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 +994,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 +1029,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 +1142,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 +1186,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 +1201,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: @@ -1498,7 +1392,7 @@ * 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); + * memset(wwo->mapping,0, wwo->maplen); */ { char* p1 = wwo->mapping; @@ -1902,6 +1796,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 +1848,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 +1913,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 +1953,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 +2024,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 +2163,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 +2190,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); } /**************************************************************************
participants (1)
-
eric pouech