From 1e3ad2f9ce9dcb95c76ab1e16a317d50657bba09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 8 Jan 2008 07:09:25 -0800 Subject: Use a more reliable thread loop for DSound, instead of a Win32 timer Also use a simpler method for calculating the read/write location --- Alc/dsound.c | 132 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 64 insertions(+), 68 deletions(-) (limited to 'Alc') diff --git a/Alc/dsound.c b/Alc/dsound.c index ddedaf21..d2708f0a 100644 --- a/Alc/dsound.c +++ b/Alc/dsound.c @@ -36,71 +36,74 @@ typedef struct { LPDIRECTSOUND lpDS; LPDIRECTSOUNDBUFFER DSpbuffer; LPDIRECTSOUNDBUFFER DSsbuffer; - MMRESULT ulDSTimerID; - DWORD OldWriteCursor; + + int killNow; + ALvoid *thread; } DSoundData; static ALCchar *DeviceList[16]; -static void CALLBACK DirectSoundProc(UINT uID,UINT uReserved,DWORD_PTR dwUser,DWORD_PTR dwReserved1,DWORD_PTR dwReserved2) -{ - ALCdevice *pDevice = (ALCdevice *)dwUser; - DSoundData *pData = pDevice->ExtraData; - DWORD PlayCursor,WriteCursor; - BYTE *WritePtr1,*WritePtr2; - DWORD WriteCnt1,WriteCnt2; - WAVEFORMATEX OutputType; - DWORD BytesPlayed; - DWORD BufSize; - HRESULT DSRes; - (void)uID; - (void)uReserved; - (void)dwReserved1; - (void)dwReserved2; +static ALuint DSoundProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + DSoundData *pData = (DSoundData*)pDevice->ExtraData; + DWORD LastCursor = 0; + DWORD PlayCursor; + VOID *WritePtr; + DWORD WriteCnt; + DWORD avail; + HRESULT err; + + while(!pData->killNow) + { + // Get current play and write cursors + IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); + avail = (PlayCursor-LastCursor) % (pDevice->UpdateFreq*pDevice->FrameSize); - BufSize = pDevice->UpdateFreq * 2 * pDevice->FrameSize; + if(avail == 0) + { + Sleep(1); + continue; + } - // Get current play and write cursors - IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer,&PlayCursor,&WriteCursor); - if (!pData->OldWriteCursor) pData->OldWriteCursor=WriteCursor-PlayCursor; + // Lock output buffer + WriteCnt = 0; + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr, &WriteCnt, NULL, NULL, 0); - // Get the output format and figure the number of bytes played (block aligned) - IDirectSoundBuffer_GetFormat(pData->DSsbuffer,&OutputType,sizeof(WAVEFORMATEX),NULL); - BytesPlayed=((((WriteCursorOldWriteCursor)?(BufSize+WriteCursor-pData->OldWriteCursor):(WriteCursor-pData->OldWriteCursor))/OutputType.nBlockAlign)*OutputType.nBlockAlign); + // If the buffer is lost, restore it, play and lock + if(err == DSERR_BUFFERLOST) + { + err = IDirectSoundBuffer_Restore(pData->DSsbuffer); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, (LPVOID*)&WritePtr, &WriteCnt, NULL, NULL, 0); + } - // Lock output buffer started at 40msec in front of the old write cursor (15msec in front of the actual write cursor) - DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); + // Successfully locked the output buffer + if(SUCCEEDED(err)) + { + // If we have an active context, mix data directly into output buffer otherwise fill with silence + SuspendContext(NULL); + aluMixData(pDevice->Context, WritePtr, WriteCnt, pDevice->Format); + ProcessContext(NULL); - // If the buffer is lost, restore it, play and lock - if (DSRes==DSERR_BUFFERLOST) - { - IDirectSoundBuffer_Restore(pData->DSsbuffer); - IDirectSoundBuffer_Play(pData->DSsbuffer,0,0,DSBPLAY_LOOPING); - DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); - } + // Unlock output buffer only when successfully locked + IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr, WriteCnt, NULL, 0); + } + else + AL_PRINT("Buffer lock error: %#lx\n", err); - // Successfully locked the output buffer - if (DSRes==DS_OK) - { - // If we have an active context, mix data directly into output buffer otherwise fill with silence - SuspendContext(NULL); - if (WritePtr1) - aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); - if (WritePtr2) - aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); - ProcessContext(NULL); - - // Unlock output buffer only when successfully locked - IDirectSoundBuffer_Unlock(pData->DSsbuffer,WritePtr1,WriteCnt1,WritePtr2,WriteCnt2); + // Update old write cursor location + LastCursor += WriteCnt; + LastCursor %= pDevice->UpdateFreq*pDevice->FrameSize; } - // Update old write cursor location - pData->OldWriteCursor=((pData->OldWriteCursor+BytesPlayed)%BufSize); + return 0; } - static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) { DSBUFFERDESC DSBDescription; @@ -169,7 +172,7 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); DSBDescription.dwSize=sizeof(DSBUFFERDESC); DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2; - DSBDescription.dwBufferBytes=device->UpdateFreq * 2 * device->FrameSize; + DSBDescription.dwBufferBytes=device->UpdateFreq * device->FrameSize; DSBDescription.lpwfxFormat=&OutputType; hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); } @@ -177,6 +180,13 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam if(SUCCEEDED(hr)) hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + device->MaxNoOfSources = 256; + device->ExtraData = pData; + + pData->thread = StartThread(DSoundProc, device); + if(!pData->thread) + hr = E_FAIL; + if(FAILED(hr)) { if (pData->DSsbuffer) @@ -190,10 +200,6 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam return ALC_FALSE; } - pData->ulDSTimerID = timeSetEvent(25, 0, (LPTIMECALLBACK)DirectSoundProc, (DWORD)device, (UINT)TIME_CALLBACK_FUNCTION|TIME_PERIODIC); - device->MaxNoOfSources = 256; - - device->ExtraData = pData; return ALC_TRUE; } @@ -201,26 +207,16 @@ static void DSoundClosePlayback(ALCdevice *device) { DSoundData *pData = device->ExtraData; - // Stop and release the DS timer - if (pData->ulDSTimerID) - timeKillEvent(pData->ulDSTimerID); + pData->killNow = 1; + StopThread(pData->thread); - // Wait ... just in case any timer events happen - Sleep(100); - - SuspendContext(NULL); - - if (pData->DSsbuffer) - IDirectSoundBuffer_Release(pData->DSsbuffer); - if (pData->DSpbuffer) - IDirectSoundBuffer_Release(pData->DSpbuffer); + IDirectSoundBuffer_Release(pData->DSsbuffer); + IDirectSoundBuffer_Release(pData->DSpbuffer); IDirectSound_Release(pData->lpDS); //Deinit COM CoUninitialize(); - ProcessContext(NULL); - free(pData); device->ExtraData = NULL; } -- cgit v1.2.3