Added sleep time calculation for the wodPlayer thread.
Changed the wodPlayer thread messaging to use its own fast 30 entries ring buffer list.
This commit is contained in:
parent
26be4c8c36
commit
c472708f69
|
@ -83,6 +83,14 @@ DEFAULT_DEBUG_CHANNEL(wave);
|
||||||
#define WINE_WM_CLOSING (WM_USER + 4)
|
#define WINE_WM_CLOSING (WM_USER + 4)
|
||||||
#define WINE_WM_HEADER (WM_USER + 5)
|
#define WINE_WM_HEADER (WM_USER + 5)
|
||||||
|
|
||||||
|
#define WINE_WM_FIRST WINE_WM_PAUSING
|
||||||
|
#define WINE_WM_LAST WINE_WM_HEADER
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int msg;
|
||||||
|
DWORD param;
|
||||||
|
} WWO_MSG;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int unixdev;
|
int unixdev;
|
||||||
volatile int state; /* one of the WINE_WS_ manifest constants */
|
volatile int state; /* one of the WINE_WS_ manifest constants */
|
||||||
|
@ -105,6 +113,12 @@ typedef struct {
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
DWORD dwThreadID;
|
DWORD dwThreadID;
|
||||||
HANDLE hEvent;
|
HANDLE hEvent;
|
||||||
|
#define WWO_RING_BUFFER_SIZE 30
|
||||||
|
WWO_MSG messages[WWO_RING_BUFFER_SIZE];
|
||||||
|
int msg_tosave;
|
||||||
|
int msg_toget;
|
||||||
|
HANDLE msg_event;
|
||||||
|
CRITICAL_SECTION msg_crst;
|
||||||
WAVEOUTCAPSA caps;
|
WAVEOUTCAPSA caps;
|
||||||
|
|
||||||
/* DirectSound stuff */
|
/* DirectSound stuff */
|
||||||
|
@ -135,7 +149,7 @@ static WINE_WAVEIN WInDev [MAX_WAVEINDRV ];
|
||||||
static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
|
static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
|
||||||
|
|
||||||
/*======================================================================*
|
/*======================================================================*
|
||||||
* Low level WAVE implemantation *
|
* Low level WAVE implementation *
|
||||||
*======================================================================*/
|
*======================================================================*/
|
||||||
|
|
||||||
LONG OSS_WaveInit(void)
|
LONG OSS_WaveInit(void)
|
||||||
|
@ -366,13 +380,13 @@ static DWORD OSS_NotifyClient(UINT wDevID, WORD wMsg, DWORD dwParam1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*======================================================================*
|
/*======================================================================*
|
||||||
* Low level WAVE OUT implemantation *
|
* Low level WAVE OUT implementation *
|
||||||
*======================================================================*/
|
*======================================================================*/
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* wodPlayer_WriteFragments [internal]
|
* wodPlayer_WriteFragments [internal]
|
||||||
*
|
*
|
||||||
* wodPlayer helper. Writes as many fragments it can to unixdev.
|
* wodPlayer helper. Writes as many fragments as it can to unixdev.
|
||||||
* Returns TRUE in case of buffer underrun.
|
* Returns TRUE in case of buffer underrun.
|
||||||
*/
|
*/
|
||||||
static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
|
@ -399,7 +413,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
wwo->dwLastFragDone && /* first fragment has been played */
|
wwo->dwLastFragDone && /* first fragment has been played */
|
||||||
info.fragments + 2 > info.fragstotal) { /* done with all waveOutWrite()' fragments */
|
info.fragments + 2 > info.fragstotal) { /* done with all waveOutWrite()' fragments */
|
||||||
/* FIXME: should do better handling here */
|
/* FIXME: should do better handling here */
|
||||||
TRACE("Oooch, buffer underrun !\n");
|
WARN("Oooch, buffer underrun !\n");
|
||||||
return TRUE; /* force resetting of waveOut device */
|
return TRUE; /* force resetting of waveOut device */
|
||||||
}
|
}
|
||||||
return FALSE; /* wait a bit */
|
return FALSE; /* wait a bit */
|
||||||
|
@ -443,7 +457,7 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
} else {
|
} else {
|
||||||
/* last one played */
|
/* last one played */
|
||||||
if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
|
if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
|
||||||
FIXME("Correctly handled case ? (ending loop buffer also starts a new loop\n");
|
FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
|
||||||
/* shall we consider the END flag for the closing loop or for
|
/* shall we consider the END flag for the closing loop or for
|
||||||
* the opening one or for both ???
|
* the opening one or for both ???
|
||||||
* code assumes for closing loop only
|
* code assumes for closing loop only
|
||||||
|
@ -482,6 +496,49 @@ static BOOL wodPlayer_WriteFragments(WINE_WAVEOUT* wwo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wodPlayer_Message(WINE_WAVEOUT *wwo, int msg, DWORD param)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&wwo->msg_crst);
|
||||||
|
if ((wwo->msg_tosave == wwo->msg_toget) /* buffer overflow ? */
|
||||||
|
&& (wwo->messages[wwo->msg_toget].msg))
|
||||||
|
{
|
||||||
|
ERR("buffer overflow !?\n");
|
||||||
|
LeaveCriticalSection(&wwo->msg_crst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wwo->messages[wwo->msg_tosave].msg = msg;
|
||||||
|
wwo->messages[wwo->msg_tosave].param = param;
|
||||||
|
wwo->msg_tosave++;
|
||||||
|
if (wwo->msg_tosave > WWO_RING_BUFFER_SIZE-1)
|
||||||
|
wwo->msg_tosave = 0;
|
||||||
|
LeaveCriticalSection(&wwo->msg_crst);
|
||||||
|
/* signal a new message */
|
||||||
|
SetEvent(wwo->msg_event);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wodPlayer_RetrieveMessage(WINE_WAVEOUT *wwo, int *msg, DWORD *param)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&wwo->msg_crst);
|
||||||
|
|
||||||
|
if (wwo->msg_toget == wwo->msg_tosave) /* buffer empty ? */
|
||||||
|
{
|
||||||
|
LeaveCriticalSection(&wwo->msg_crst);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*msg = wwo->messages[wwo->msg_toget].msg;
|
||||||
|
wwo->messages[wwo->msg_toget].msg = 0;
|
||||||
|
*param = wwo->messages[wwo->msg_toget].param;
|
||||||
|
wwo->msg_toget++;
|
||||||
|
if (wwo->msg_toget > WWO_RING_BUFFER_SIZE-1)
|
||||||
|
wwo->msg_toget = 0;
|
||||||
|
LeaveCriticalSection(&wwo->msg_crst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* wodPlayer_Notify [internal]
|
* wodPlayer_Notify [internal]
|
||||||
*
|
*
|
||||||
|
@ -556,9 +613,10 @@ static DWORD CALLBACK wodPlayer(LPVOID pmt)
|
||||||
WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)&WOutDev[uDevID];
|
WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)&WOutDev[uDevID];
|
||||||
WAVEHDR* lpWaveHdr;
|
WAVEHDR* lpWaveHdr;
|
||||||
DWORD dwSleepTime;
|
DWORD dwSleepTime;
|
||||||
MSG msg;
|
int msg;
|
||||||
|
DWORD param;
|
||||||
|
DWORD tc;
|
||||||
|
|
||||||
PeekMessageA(&msg, 0, 0, 0, 0);
|
|
||||||
wwo->state = WINE_WS_STOPPED;
|
wwo->state = WINE_WS_STOPPED;
|
||||||
|
|
||||||
wwo->dwLastFragDone = 0;
|
wwo->dwLastFragDone = 0;
|
||||||
|
@ -570,23 +628,36 @@ static DWORD CALLBACK wodPlayer(LPVOID pmt)
|
||||||
TRACE("imhere[0]\n");
|
TRACE("imhere[0]\n");
|
||||||
SetEvent(wwo->hEvent);
|
SetEvent(wwo->hEvent);
|
||||||
|
|
||||||
/* make sleep time to be # of ms to output a fragment */
|
|
||||||
dwSleepTime = (wwo->dwFragmentSize * 1000) / wwo->format.wf.nAvgBytesPerSec;
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* wait for dwSleepTime or an event in thread's queue */
|
/* wait for dwSleepTime or an event in thread's queue
|
||||||
/* FIXME: could improve wait time depending on queue state,
|
* FIXME:
|
||||||
* ie, number of queued fragments
|
* - is wait time calculation optimal ?
|
||||||
*/
|
* - these 100 ms parts should be changed, but Eric reports
|
||||||
|
* that the wodPlayer thread might lock up if we use INFINITE
|
||||||
|
* (strange !), so I better don't change that now... */
|
||||||
|
if (wwo->state != WINE_WS_PLAYING)
|
||||||
|
dwSleepTime = 100;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tc = GetTickCount();
|
||||||
|
if (tc < wwo->dwLastFragDone)
|
||||||
|
{
|
||||||
|
/* calculate sleep time depending on when the last fragment
|
||||||
|
will be played */
|
||||||
|
dwSleepTime = (wwo->dwLastFragDone - tc)*7/10;
|
||||||
|
if (dwSleepTime > 100)
|
||||||
|
dwSleepTime = 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dwSleepTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
TRACE("imhere[1]\n");
|
TRACE("imhere[1]\n");
|
||||||
MsgWaitForMultipleObjects(0, NULL, FALSE,
|
if (dwSleepTime)
|
||||||
(wwo->state == WINE_WS_PLAYING) ?
|
WaitForSingleObject(wwo->msg_event, dwSleepTime);
|
||||||
2 * dwSleepTime : /*INFINITE*/100,
|
|
||||||
QS_POSTMESSAGE);
|
|
||||||
TRACE("imhere[2] (q=%p p=%p)\n", wwo->lpQueuePtr, wwo->lpPlayPtr);
|
TRACE("imhere[2] (q=%p p=%p)\n", wwo->lpQueuePtr, wwo->lpPlayPtr);
|
||||||
wodPlayer_Notify(wwo, uDevID, FALSE);
|
while (wodPlayer_RetrieveMessage(wwo, &msg, ¶m)) {
|
||||||
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
|
switch (msg) {
|
||||||
switch (msg.message) {
|
|
||||||
case WINE_WM_PAUSING:
|
case WINE_WM_PAUSING:
|
||||||
wodPlayer_Reset(wwo, uDevID, FALSE);
|
wodPlayer_Reset(wwo, uDevID, FALSE);
|
||||||
wwo->state = WINE_WS_PAUSED;
|
wwo->state = WINE_WS_PAUSED;
|
||||||
|
@ -597,7 +668,7 @@ static DWORD CALLBACK wodPlayer(LPVOID pmt)
|
||||||
SetEvent(wwo->hEvent);
|
SetEvent(wwo->hEvent);
|
||||||
break;
|
break;
|
||||||
case WINE_WM_HEADER:
|
case WINE_WM_HEADER:
|
||||||
lpWaveHdr = (LPWAVEHDR)msg.lParam;
|
lpWaveHdr = (LPWAVEHDR)param;
|
||||||
|
|
||||||
/* insert buffer at the end of queue */
|
/* insert buffer at the end of queue */
|
||||||
{
|
{
|
||||||
|
@ -622,7 +693,7 @@ static DWORD CALLBACK wodPlayer(LPVOID pmt)
|
||||||
ExitThread(0);
|
ExitThread(0);
|
||||||
/* shouldn't go here */
|
/* shouldn't go here */
|
||||||
default:
|
default:
|
||||||
FIXME("unknown message %d\n", msg.message);
|
FIXME("unknown message %d\n", msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -729,13 +800,13 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
|
|
||||||
if (dwFlags & WAVE_DIRECTSOUND) {
|
if (dwFlags & WAVE_DIRECTSOUND) {
|
||||||
/* with DirectSound, fragments are irrelevant, but a large buffer isn't...
|
/* with DirectSound, fragments are irrelevant, but a large buffer isn't...
|
||||||
* so let's choose a full 64KB for DirectSound */
|
* so let's choose a full 64KB (32 * 2^11) for DirectSound */
|
||||||
audio_fragment = 0x0020000B;
|
audio_fragment = 0x0020000B;
|
||||||
} else {
|
} else {
|
||||||
/* shockwave player uses only 4 1k-fragments at a rate of 22050 bytes/sec
|
/* shockwave player uses only 4 1k-fragments at a rate of 22050 bytes/sec
|
||||||
* thus leading to 46ms per fragment, and a turnaround time of 185ms
|
* thus leading to 46ms per fragment, and a turnaround time of 185ms
|
||||||
*/
|
*/
|
||||||
/* 2^10=1024 bytes per fragment, 16 fragments max */
|
/* 16 fragments max, 2^10=1024 bytes per fragment */
|
||||||
audio_fragment = 0x000F000A;
|
audio_fragment = 0x000F000A;
|
||||||
}
|
}
|
||||||
sample_rate = wwo->format.wf.nSamplesPerSec;
|
sample_rate = wwo->format.wf.nSamplesPerSec;
|
||||||
|
@ -769,6 +840,12 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
|
||||||
}
|
}
|
||||||
wwo->dwFragmentSize = fragment_size;
|
wwo->dwFragmentSize = fragment_size;
|
||||||
|
|
||||||
|
wwo->msg_toget = 0;
|
||||||
|
wwo->msg_tosave = 0;
|
||||||
|
wwo->msg_event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
memset(wwo->messages, 0, sizeof(WWO_MSG)*WWO_RING_BUFFER_SIZE);
|
||||||
|
InitializeCriticalSection(&wwo->msg_crst);
|
||||||
|
|
||||||
if (!(dwFlags & WAVE_DIRECTSOUND)) {
|
if (!(dwFlags & WAVE_DIRECTSOUND)) {
|
||||||
wwo->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
wwo->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, &(wwo->dwThreadID));
|
wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, &(wwo->dwThreadID));
|
||||||
|
@ -818,7 +895,7 @@ static DWORD wodClose(WORD wDevID)
|
||||||
} else {
|
} else {
|
||||||
TRACE("imhere[3-close]\n");
|
TRACE("imhere[3-close]\n");
|
||||||
if (wwo->hEvent != INVALID_HANDLE_VALUE) {
|
if (wwo->hEvent != INVALID_HANDLE_VALUE) {
|
||||||
PostThreadMessageA(wwo->dwThreadID, WINE_WM_CLOSING, 0, 0);
|
wodPlayer_Message(wwo, WINE_WM_CLOSING, 0);
|
||||||
WaitForSingleObject(wwo->hEvent, INFINITE);
|
WaitForSingleObject(wwo->hEvent, INFINITE);
|
||||||
CloseHandle(wwo->hEvent);
|
CloseHandle(wwo->hEvent);
|
||||||
}
|
}
|
||||||
|
@ -863,7 +940,7 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
|
||||||
lpWaveHdr->lpNext = 0;
|
lpWaveHdr->lpNext = 0;
|
||||||
|
|
||||||
TRACE("imhere[3-HEADER]\n");
|
TRACE("imhere[3-HEADER]\n");
|
||||||
PostThreadMessageA(WOutDev[wDevID].dwThreadID, WINE_WM_HEADER, 0, (DWORD)lpWaveHdr);
|
wodPlayer_Message(&WOutDev[wDevID], WINE_WM_HEADER, (DWORD)lpWaveHdr);
|
||||||
|
|
||||||
return MMSYSERR_NOERROR;
|
return MMSYSERR_NOERROR;
|
||||||
}
|
}
|
||||||
|
@ -922,7 +999,7 @@ static DWORD wodPause(WORD wDevID)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("imhere[3-PAUSING]\n");
|
TRACE("imhere[3-PAUSING]\n");
|
||||||
PostThreadMessageA(WOutDev[wDevID].dwThreadID, WINE_WM_PAUSING, 0, 0);
|
wodPlayer_Message(&WOutDev[wDevID], WINE_WM_PAUSING, 0);
|
||||||
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
||||||
|
|
||||||
return MMSYSERR_NOERROR;
|
return MMSYSERR_NOERROR;
|
||||||
|
@ -942,7 +1019,7 @@ static DWORD wodRestart(WORD wDevID)
|
||||||
|
|
||||||
if (WOutDev[wDevID].state == WINE_WS_PAUSED) {
|
if (WOutDev[wDevID].state == WINE_WS_PAUSED) {
|
||||||
TRACE("imhere[3-RESTARTING]\n");
|
TRACE("imhere[3-RESTARTING]\n");
|
||||||
PostThreadMessageA(WOutDev[wDevID].dwThreadID, WINE_WM_RESTARTING, 0, 0);
|
wodPlayer_Message(&WOutDev[wDevID], WINE_WM_RESTARTING, 0);
|
||||||
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -970,7 +1047,7 @@ static DWORD wodReset(WORD wDevID)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("imhere[3-RESET]\n");
|
TRACE("imhere[3-RESET]\n");
|
||||||
PostThreadMessageA(WOutDev[wDevID].dwThreadID, WINE_WM_RESETTING, 0, 0);
|
wodPlayer_Message(&WOutDev[wDevID], WINE_WM_RESETTING, 0);
|
||||||
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
WaitForSingleObject(WOutDev[wDevID].hEvent, INFINITE);
|
||||||
|
|
||||||
return MMSYSERR_NOERROR;
|
return MMSYSERR_NOERROR;
|
||||||
|
@ -1558,7 +1635,7 @@ static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*======================================================================*
|
/*======================================================================*
|
||||||
* Low level WAVE IN implemantation *
|
* Low level WAVE IN implementation *
|
||||||
*======================================================================*/
|
*======================================================================*/
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
@ -1640,7 +1717,7 @@ static DWORD CALLBACK widRecorder(LPVOID pmt)
|
||||||
MsgWaitForMultipleObjects(0, NULL, FALSE, dwSleepTime, QS_POSTMESSAGE);
|
MsgWaitForMultipleObjects(0, NULL, FALSE, dwSleepTime, QS_POSTMESSAGE);
|
||||||
TRACE("imhere[2] (q=%p)\n", wwi->lpQueuePtr);
|
TRACE("imhere[2] (q=%p)\n", wwi->lpQueuePtr);
|
||||||
|
|
||||||
while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) {
|
while (PeekMessageA(&msg, 0, WINE_WM_FIRST, WINE_WM_LAST, PM_REMOVE)) {
|
||||||
switch (msg.message) {
|
switch (msg.message) {
|
||||||
case WINE_WM_PAUSING:
|
case WINE_WM_PAUSING:
|
||||||
wwi->state = WINE_WS_PAUSED;
|
wwi->state = WINE_WS_PAUSED;
|
||||||
|
|
Loading…
Reference in New Issue