use a win32 Event object (aka condition variable) to signal timer process completio to Pa_StopStream in DirectSound implementation. resolves race condition when stopping direct sounds streams.
This commit is contained in:
parent
99e0648891
commit
1349e5a344
1 changed files with 27 additions and 8 deletions
|
|
@ -253,6 +253,8 @@ typedef struct PaWinDsStream
|
|||
double secondsPerHostByte; /* Used to optimize latency calculation for outTime */
|
||||
|
||||
PaStreamCallbackFlags callbackFlags;
|
||||
|
||||
HANDLE processingCompleted;
|
||||
|
||||
/* FIXME - move all below to PaUtilStreamRepresentation */
|
||||
volatile int isStarted;
|
||||
|
|
@ -1778,6 +1780,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
stream->timerID = 0;
|
||||
|
||||
stream->processingCompleted = CreateEvent( NULL, /* bManualReset = */ TRUE, /* bInitialState = */ FALSE, NULL );
|
||||
if( stream->processingCompleted == NULL )
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get system minimum latency. */
|
||||
minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
|
||||
|
||||
|
|
@ -1917,7 +1926,12 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
error:
|
||||
if( stream )
|
||||
{
|
||||
if( stream->processingCompleted != NULL )
|
||||
CloseHandle( stream->processingCompleted );
|
||||
|
||||
PaUtil_FreeMemory( stream );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -2259,6 +2273,8 @@ static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWO
|
|||
{
|
||||
if( stream->streamRepresentation.streamFinishedCallback != 0 )
|
||||
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
|
||||
|
||||
SetEvent( stream->processingCompleted );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2272,6 +2288,8 @@ static PaError CloseStream( PaStream* s )
|
|||
PaError result = paNoError;
|
||||
PaWinDsStream *stream = (PaWinDsStream*)s;
|
||||
|
||||
CloseHandle( stream->processingCompleted );
|
||||
|
||||
// Cleanup the sound buffers
|
||||
if( stream->pDirectSoundOutputBuffer )
|
||||
{
|
||||
|
|
@ -2315,6 +2333,8 @@ static PaError StartStream( PaStream *s )
|
|||
|
||||
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
|
||||
|
||||
ResetEvent( stream->processingCompleted );
|
||||
|
||||
if( stream->bufferProcessor.inputChannelCount > 0 )
|
||||
{
|
||||
// Start the buffer playback
|
||||
|
|
@ -2382,7 +2402,7 @@ static PaError StartStream( PaStream *s )
|
|||
else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
|
||||
resolution = msecPerWakeup/4;
|
||||
stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
|
||||
(DWORD_PTR) stream, TIME_PERIODIC );
|
||||
(DWORD_PTR) stream, TIME_PERIODIC | TIME_KILL_SYNCHRONOUS );
|
||||
}
|
||||
if( stream->timerID == 0 )
|
||||
{
|
||||
|
|
@ -2408,13 +2428,12 @@ static PaError StopStream( PaStream *s )
|
|||
int timeoutMsec;
|
||||
|
||||
stream->stopProcessing = 1;
|
||||
/* Set timeout at 20% beyond maximum time we might wait. */
|
||||
timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
|
||||
while( stream->isActive && (timeoutMsec > 0) )
|
||||
{
|
||||
Sleep(10);
|
||||
timeoutMsec -= 10;
|
||||
}
|
||||
|
||||
/* Set timeout at 4 times maximum time we might wait. */
|
||||
timeoutMsec = (int) (4 * MSEC_PER_SECOND * (stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate));
|
||||
|
||||
WaitForSingleObject( stream->processingCompleted, timeoutMsec );
|
||||
|
||||
if( stream->timerID != 0 )
|
||||
{
|
||||
timeKillEvent(stream->timerID); /* Stop callback timer. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue