wasapi:
- 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:
parent
6421f964d7
commit
083b34a10f
1 changed files with 36 additions and 12 deletions
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue