- fixed occasional crash-bug which may be caused by a lightweight application that starts stream, checks if stream is running and if not terminates the stream: WASAPI implementation wasn't taking such behavior into account and stream termination (with structure deallocation) could happen during a thread start causing a crash on bad pointer usage
 - fixed Pa_IsStreamActive and similar not correctly reporting stopped stream if that was stopped from within a callback function (playback/capture) by returning paComplete
This commit is contained in:
dmitrykos 2010-05-12 18:08:45 +00:00
commit 083b34a10f

View file

@ -519,7 +519,8 @@ typedef struct PaWasapiStream
PA_THREAD_ID dwThreadId; PA_THREAD_ID dwThreadId;
HANDLE hThread; HANDLE hThread;
HANDLE hCloseRequest; HANDLE hCloseRequest;
HANDLE hThreadDone; HANDLE hThreadStart; //!< signalled by thread on start
HANDLE hThreadExit; //!< signalled by thread on exit
HANDLE hBlockingOpStreamRD; HANDLE hBlockingOpStreamRD;
HANDLE hBlockingOpStreamWR; HANDLE hBlockingOpStreamWR;
@ -1701,8 +1702,8 @@ static const int BestToWorst[FORMATTESTS] = { paFloat32, paInt24, paInt16 };
if (answer != paFormatIsSupported) if (answer != paFormatIsSupported)
{ {
// If mono, then driver does not support 1 channel, we use internal workaround // If mono, then driver does not support 1 channel, we use internal workaround
// of tiny software mixing functionality, e.g. we provide to user buffer for 1 channel // of tiny software mixing functionality, e.g. we provide to user buffer 1 channel
// but then mix into 2 of device buffer // but then mix into 2 for device buffer
if (params->channelCount == 1) if (params->channelCount == 1)
{ {
WAVEFORMATEXTENSIBLE stereo = { 0 }; WAVEFORMATEXTENSIBLE stereo = { 0 };
@ -2534,7 +2535,8 @@ static PaError CloseStream( PaStream* s )
SAFE_RELEASE(stream->outVol); SAFE_RELEASE(stream->outVol);
SAFE_CLOSE(stream->hThread); SAFE_CLOSE(stream->hThread);
SAFE_CLOSE(stream->hThreadDone); SAFE_CLOSE(stream->hThreadStart);
SAFE_CLOSE(stream->hThreadExit);
SAFE_CLOSE(stream->hCloseRequest); SAFE_CLOSE(stream->hCloseRequest);
SAFE_CLOSE(stream->hBlockingOpStreamRD); SAFE_CLOSE(stream->hBlockingOpStreamRD);
SAFE_CLOSE(stream->hBlockingOpStreamWR); SAFE_CLOSE(stream->hBlockingOpStreamWR);
@ -2567,8 +2569,9 @@ static PaError StartStream( PaStream *s )
// Create thread // Create thread
if (!stream->bBlocking) if (!stream->bBlocking)
{ {
// Create thread done event // Create thread events
stream->hThreadDone = CreateEvent(NULL, TRUE, FALSE, NULL); stream->hThreadStart = CreateEvent(NULL, TRUE, FALSE, NULL);
stream->hThreadExit = CreateEvent(NULL, TRUE, FALSE, NULL);
if ((stream->in.client && stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) || if ((stream->in.client && stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) ||
(stream->out.client && stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) (stream->out.client && stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
@ -2581,6 +2584,10 @@ static PaError StartStream( PaStream *s )
if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL) if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
return paUnanticipatedHostError; return paUnanticipatedHostError;
} }
// Wait for thread to start
if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
return paUnanticipatedHostError;
} }
else else
{ {
@ -2641,7 +2648,7 @@ static void _FinishStream(PaWasapiStream *stream)
// Issue command to thread to stop processing and wait for thread exit // Issue command to thread to stop processing and wait for thread exit
if (!stream->bBlocking) if (!stream->bBlocking)
{ {
SignalObjectAndWait(stream->hCloseRequest, stream->hThreadDone, INFINITE, FALSE); SignalObjectAndWait(stream->hCloseRequest, stream->hThreadExit, INFINITE, FALSE);
} }
else else
// Blocking mode does not own thread // Blocking mode does not own thread
@ -2658,7 +2665,8 @@ static void _FinishStream(PaWasapiStream *stream)
// Close thread handles to allow restart // Close thread handles to allow restart
SAFE_CLOSE(stream->hThread); SAFE_CLOSE(stream->hThread);
SAFE_CLOSE(stream->hThreadDone); SAFE_CLOSE(stream->hThreadStart);
SAFE_CLOSE(stream->hThreadExit);
SAFE_CLOSE(stream->hCloseRequest); SAFE_CLOSE(stream->hCloseRequest);
SAFE_CLOSE(stream->hBlockingOpStreamRD); SAFE_CLOSE(stream->hBlockingOpStreamRD);
SAFE_CLOSE(stream->hBlockingOpStreamWR); SAFE_CLOSE(stream->hBlockingOpStreamWR);
@ -3332,6 +3340,10 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
if (!event[S_INPUT] || !event[S_OUTPUT]) if (!event[S_INPUT] || !event[S_OUTPUT])
{ {
PRINT(("WASAPI Thread: failed creating one or two event handles\n")); PRINT(("WASAPI Thread: failed creating one or two event handles\n"));
// Prevent deadlocking in Pa_StreamStart
SetEvent(stream->hThreadStart);
// Exit
goto thread_end; goto thread_end;
} }
@ -3372,6 +3384,9 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
// Signal: stream running // Signal: stream running
stream->running = TRUE; stream->running = TRUE;
// Notify: thread started
SetEvent(stream->hThreadStart);
// Processing Loop // Processing Loop
for (;;) for (;;)
{ {
@ -3418,8 +3433,11 @@ thread_end:
CloseHandle(event[S_INPUT]); CloseHandle(event[S_INPUT]);
CloseHandle(event[S_OUTPUT]); CloseHandle(event[S_OUTPUT]);
// Notify thread is exiting // Notify: thread exited
SetEvent(stream->hThreadDone); SetEvent(stream->hThreadExit);
// Notify: not running
stream->running = FALSE;
return 0; return 0;
} }
@ -3482,6 +3500,9 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
// Signal: stream running // Signal: stream running
stream->running = TRUE; stream->running = TRUE;
// Notify: thread started
SetEvent(stream->hThreadStart);
// Processing Loop // Processing Loop
while (WaitForSingleObject(stream->hCloseRequest, sleep_ms) == WAIT_TIMEOUT) while (WaitForSingleObject(stream->hCloseRequest, sleep_ms) == WAIT_TIMEOUT)
{ {
@ -3529,8 +3550,11 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
// Process stop // Process stop
_OnStreamStop(stream); _OnStreamStop(stream);
// Notify thread is exiting // Notify: thread exited
SetEvent(stream->hThreadDone); SetEvent(stream->hThreadExit);
// Notify: not running
stream->running = FALSE;
return 0; return 0;
} }