Supports multiple threads using ASIO by adding CoInitialize(0) and CoUninitialize() calls.

This commit is contained in:
philburk 2008-06-28 18:27:34 +00:00
commit 78ce8cedd5

View file

@ -965,13 +965,20 @@ PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
return result; return result;
} }
/* Unload whatever we loaded in LoadAsioDriver().
Also balance the call to CoInitialize(0).
*/
static void UnloadAsioDriver( void )
{
ASIOExit();
CoUninitialize();
}
/* /*
load the asio driver named by <driverName> and return statistics about load the asio driver named by <driverName> and return statistics about
the driver in info. If no error occurred, the driver will remain open the driver in info. If no error occurred, the driver will remain open
and must be closed by the called by calling ASIOExit() - if an error and must be closed by the called by calling UnloadAsioDriver() - if an error
is returned the driver will already be closed. is returned the driver will already be unloaded.
*/ */
static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName, static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
PaAsioDriverInfo *driverInfo, void *systemSpecific ) PaAsioDriverInfo *driverInfo, void *systemSpecific )
@ -980,12 +987,23 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c
ASIOError asioError; ASIOError asioError;
int asioIsInitialized = 0; int asioIsInitialized = 0;
/* @todo note that the V18 version always called CoInitialize() here to ensure /*
that COM was initialized before loading the driver. ASIO uses CoCreateInstance() to load a driver. That requires that
probably the docs need to require clients to initialize COM in new threads? CoInitialize(0) be called for every thread that loads a driver.
It is OK to call CoInitialize(0) multiple times form one thread as long
as it is balanced by a call to CoUninitialize(). See UnloadAsioDriver().
The V18 version called CoInitialize() starting on 2/19/02.
That was removed from PA V19 for unknown reasons.
Phil Burk added it back on 6/27/08 so that JSyn would work.
*/ */
CoInitialize( 0 );
if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) ) if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) )
{ {
/* If this returns an error then it might be because CoInitialize(0) was removed.
It should be called right before this.
*/
result = paUnanticipatedHostError; result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" ); PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
goto error; goto error;
@ -1031,8 +1049,10 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c
error: error:
if( asioIsInitialized ) if( asioIsInitialized )
ASIOExit(); {
ASIOExit();
}
CoUninitialize();
return result; return result;
} }
@ -1275,7 +1295,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
if( !asioDeviceInfo->asioChannelInfos ) if( !asioDeviceInfo->asioChannelInfos )
{ {
result = paInsufficientMemory; result = paInsufficientMemory;
goto error; goto error_unload;
} }
int a; int a;
@ -1288,7 +1308,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
{ {
result = paUnanticipatedHostError; result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error; goto error_unload;
} }
} }
@ -1301,13 +1321,13 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
{ {
result = paUnanticipatedHostError; result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error; goto error_unload;
} }
} }
/* unload the driver */ /* unload the driver */
ASIOExit(); UnloadAsioDriver();
(*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
++(*hostApi)->info.deviceCount; ++(*hostApi)->info.deviceCount;
@ -1344,6 +1364,9 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
return result; return result;
error_unload:
UnloadAsioDriver();
error: error:
if( asioHostApi ) if( asioHostApi )
{ {
@ -1516,7 +1539,7 @@ done:
/* close the device if it wasn't already open */ /* close the device if it wasn't already open */
if( asioHostApi->openAsioDeviceIndex == paNoDevice ) if( asioHostApi->openAsioDeviceIndex == paNoDevice )
{ {
ASIOExit(); /* not sure if we should check for errors here */ UnloadAsioDriver(); /* not sure if we should check for errors here */
} }
if( result == paNoError ) if( result == paNoError )
@ -1865,7 +1888,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if( result == paNoError ) if( result == paNoError )
asioIsInitialized = 1; asioIsInitialized = 1;
else{ else{
PA_DEBUG(("OpenStream ERROR1\n")); PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
goto error; goto error;
} }
@ -2577,8 +2600,9 @@ error:
ASIODisposeBuffers(); ASIODisposeBuffers();
if( asioIsInitialized ) if( asioIsInitialized )
ASIOExit(); {
UnloadAsioDriver();
}
return result; return result;
} }
@ -2629,7 +2653,7 @@ static PaError CloseStream( PaStream* s )
PaUtil_FreeMemory( stream ); PaUtil_FreeMemory( stream );
ASIODisposeBuffers(); ASIODisposeBuffers();
ASIOExit(); UnloadAsioDriver();
return result; return result;
} }
@ -3382,7 +3406,7 @@ static PaError ReadStream( PaStream *s ,
data block is processed although it may be incomplete. */ data block is processed although it may be incomplete. */
/* If the available amount of data frames is insufficient. */ /* If the available amount of data frames is insufficient. */
if( PaUtil_GetRingBufferReadAvailable(pRb) < lFramesPerBlock ) if( PaUtil_GetRingBufferReadAvailable(pRb) < (long) lFramesPerBlock )
{ {
/* Make sure, the event isn't already set! */ /* Make sure, the event isn't already set! */
/* ResetEvent( blockingState->readFramesReadyEvent ); */ /* ResetEvent( blockingState->readFramesReadyEvent ); */
@ -3557,7 +3581,7 @@ static PaError WriteStream( PaStream *s ,
data block is processed although it may be incomplete. */ data block is processed although it may be incomplete. */
/* If the available amount of buffers is insufficient. */ /* If the available amount of buffers is insufficient. */
if( PaUtil_GetRingBufferWriteAvailable(pRb) < lFramesPerBlock ) if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) lFramesPerBlock )
{ {
/* Make sure, the event isn't already set! */ /* Make sure, the event isn't already set! */
/* ResetEvent( blockingState->writeBuffersReadyEvent ); */ /* ResetEvent( blockingState->writeBuffersReadyEvent ); */
@ -3716,10 +3740,9 @@ PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
/* @todo note that the V18 version always called CoInitialize() here to ensure /* See notes about CoInitialize(0) in LoadAsioDriver(). */
that COM was initialized before loading the driver. CoInitialize(0);
probably the docs need to require clients to initialize COM in new threads?
*/
if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) ) if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
{ {
result = paUnanticipatedHostError; result = paUnanticipatedHostError;
@ -3768,13 +3791,17 @@ PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErr
goto error; goto error;
} }
CoUninitialize();
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
return result; return result;
error: error:
if( asioIsInitialized ) if( asioIsInitialized )
ASIOExit(); {
ASIOExit();
}
CoUninitialize();
return result; return result;
} }
@ -3885,7 +3912,7 @@ static int BlockingIoPaCallback(const void *inputBuffer ,
pRb = &blockingState->writeRingBuffer; pRb = &blockingState->writeRingBuffer;
/* If the blocking i/o buffer contains enough output data, */ /* If the blocking i/o buffer contains enough output data, */
if( PaUtil_GetRingBufferReadAvailable(pRb) >= framesPerBuffer ) if( PaUtil_GetRingBufferReadAvailable(pRb) >= (long) framesPerBuffer )
{ {
/* Extract the requested data from the ring buffer. */ /* Extract the requested data from the ring buffer. */
PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer ); PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer );
@ -3899,7 +3926,7 @@ static int BlockingIoPaCallback(const void *inputBuffer ,
(*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer ); (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer );
/* If playback is to be stopped */ /* If playback is to be stopped */
if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < framesPerBuffer ) if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < (long) framesPerBuffer )
{ {
/* Extract all the remaining data from the ring buffer, /* Extract all the remaining data from the ring buffer,
whether it is a complete data block or not. */ whether it is a complete data block or not. */
@ -3908,7 +3935,7 @@ static int BlockingIoPaCallback(const void *inputBuffer ,
} }
/* Set blocking i/o event? */ /* Set blocking i/o event? */
if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= blockingState->writeBuffersRequested ) if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= (long) blockingState->writeBuffersRequested )
{ {
/* Reset buffer request. */ /* Reset buffer request. */
blockingState->writeBuffersRequestedFlag = FALSE; blockingState->writeBuffersRequestedFlag = FALSE;
@ -3934,7 +3961,7 @@ static int BlockingIoPaCallback(const void *inputBuffer ,
pRb = &blockingState->readRingBuffer; pRb = &blockingState->readRingBuffer;
/* If the blocking i/o buffer contains not enough input buffers */ /* If the blocking i/o buffer contains not enough input buffers */
if( PaUtil_GetRingBufferWriteAvailable(pRb) < framesPerBuffer ) if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) framesPerBuffer )
{ {
/* Signalize a read-buffer overflow. */ /* Signalize a read-buffer overflow. */
blockingState->inputOverflowFlag = TRUE; blockingState->inputOverflowFlag = TRUE;
@ -3947,7 +3974,7 @@ static int BlockingIoPaCallback(const void *inputBuffer ,
PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer ); PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer );
/* Set blocking i/o event? */ /* Set blocking i/o event? */
if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= blockingState->readFramesRequested ) if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= (long) blockingState->readFramesRequested )
{ {
/* Reset buffer request. */ /* Reset buffer request. */
blockingState->readFramesRequestedFlag = FALSE; blockingState->readFramesRequestedFlag = FALSE;