could the people who had issues with the latest OSS patch(es) test
if this one fixes all their issues ?
--
---------------
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);
}
/**************************************************************************