HANDLE completedBuffersPlayedEvent;
bool streamFinishedCallbackCalled;
+ int isStopped;
volatile int isActive;
volatile bool zeroOutput; /* all future calls to the callback will output silence */
return paDeviceUnavailable;
}
+ assert( theAsioStream == 0 );
+
if( inputParameters && outputParameters )
{
/* full duplex ASIO stream must use the same device for input and output */
{
/* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */
streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */
- userData = &theAsioStream; /* The callback user data will be the PA ASIO stream. */
+ userData = &stream; /* The callback user data will be the PA ASIO stream. */
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&asioHostApi->blockingStreamInterface, streamCallback, userData );
}
stream->inputChannelCount = inputChannelCount;
stream->outputChannelCount = outputChannelCount;
stream->postOutput = driverInfo->postOutput;
+ stream->isStopped = 1;
stream->isActive = 0;
-
+
asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
+ theAsioStream = stream;
*s = (PaStream*)stream;
return result;
ASIODisposeBuffers();
UnloadAsioDriver();
+ theAsioStream = 0;
+
return result;
}
if( result == paNoError )
{
- theAsioStream = stream;
+ assert( theAsioStream == stream ); /* theAsioStream should be set correctly in OpenStream */
+
+ /* initialize these variables before the callback has a chance to be invoked */
+ stream->isStopped = 0;
+ stream->isActive = 1;
+ stream->streamFinishedCallbackCalled = false;
+
asioError = ASIOStart();
- if( asioError == ASE_OK )
- {
- stream->isActive = 1;
- stream->streamFinishedCallbackCalled = false;
- }
- else
+ if( asioError != ASE_OK )
{
- theAsioStream = 0;
+ stream->isStopped = 1;
+ stream->isActive = 0;
+
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
}
return result;
}
+static void EnsureCallbackHasCompleted( PaAsioStream *stream )
+{
+ // make sure that the callback is not still in-flight after ASIOStop()
+ // returns. This has been observed to happen on the Hoontech DSP24 for
+ // example.
+ int count = 2000; // only wait for 2 seconds, rather than hanging.
+ while( stream->reenterCount != -1 && count > 0 )
+ {
+ Sleep(1);
+ --count;
+ }
+}
static PaError StopStream( PaStream *s )
{
length is longer than the asio buffer size then that should
be taken into account.
*/
- if( WaitForSingleObject( theAsioStream->completedBuffersPlayedEvent,
+ if( WaitForSingleObject( stream->completedBuffersPlayedEvent,
(DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
== WAIT_TIMEOUT )
{
}
asioError = ASIOStop();
- if( asioError != ASE_OK )
+ if( asioError == ASE_OK )
+ {
+ EnsureCallbackHasCompleted( stream );
+ }
+ else
{
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
}
- theAsioStream = 0;
+ stream->isStopped = 1;
stream->isActive = 0;
if( !stream->streamFinishedCallbackCalled )
return result;
}
-
static PaError AbortStream( PaStream *s )
{
PaError result = paNoError;
stream->zeroOutput = true;
asioError = ASIOStop();
- if( asioError != ASE_OK )
+ if( asioError == ASE_OK )
{
- result = paUnanticipatedHostError;
- PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ EnsureCallbackHasCompleted( stream );
}
else
{
- // make sure that the callback is not still in-flight when ASIOStop()
- // returns. This has been observed to happen on the Hoontech DSP24 for
- // example.
- int count = 2000; // only wait for 2 seconds, rather than hanging.
- while( theAsioStream->reenterCount != -1 && count > 0 )
- {
- Sleep(1);
- --count;
- }
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
}
- /* it is questionable whether we should zero theAsioStream if ASIOStop()
- returns an error, because the callback could still be active. We assume
- not - this is based on the fact that ASIOStop is unlikely to fail
- if the callback is running - it's more likely to fail because the
- callback is not running. */
-
- theAsioStream = 0;
+ stream->isStopped = 1;
stream->isActive = 0;
if( !stream->streamFinishedCallbackCalled )
static PaError IsStreamStopped( PaStream *s )
{
- //PaAsioStream *stream = (PaAsioStream*)s;
- (void) s; /* unused parameter */
- return theAsioStream == 0;
+ PaAsioStream *stream = (PaAsioStream*)s;
+
+ return stream->isStopped;
}
void *userData )
{
PaError result = paNoError; /* Initial return value. */
- PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */ /* This is a pointer to "theAsioStream", see OpenStream(). */
+ PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */
PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */
/* Get a pointer to the stream's blocking i/o buffer processor. */