From: philburk Date: Sat, 28 Jun 2008 18:27:34 +0000 (+0000) Subject: Supports multiple threads using ASIO by adding CoInitialize(0) and CoUninitialize... X-Git-Tag: svn/1415~29 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=78ce8cedd59963fe9f0d25b8b12dd06ea7376da8;p=portaudio Supports multiple threads using ASIO by adding CoInitialize(0) and CoUninitialize() calls. --- diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index db6c0e4..400de10 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -965,13 +965,20 @@ PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, 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 and return statistics about 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 - is returned the driver will already be closed. + and must be closed by the called by calling UnloadAsioDriver() - if an error + is returned the driver will already be unloaded. */ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName, PaAsioDriverInfo *driverInfo, void *systemSpecific ) @@ -980,12 +987,23 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c ASIOError asioError; int asioIsInitialized = 0; - /* @todo note that the V18 version always called CoInitialize() here to ensure - that COM was initialized before loading the driver. - probably the docs need to require clients to initialize COM in new threads? + /* + ASIO uses CoCreateInstance() to load a driver. That requires that + 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(driverName) ) ) { + /* If this returns an error then it might be because CoInitialize(0) was removed. + It should be called right before this. + */ result = paUnanticipatedHostError; PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" ); goto error; @@ -1031,8 +1049,10 @@ static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const c error: if( asioIsInitialized ) - ASIOExit(); - + { + ASIOExit(); + } + CoUninitialize(); return result; } @@ -1275,7 +1295,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex if( !asioDeviceInfo->asioChannelInfos ) { result = paInsufficientMemory; - goto error; + goto error_unload; } int a; @@ -1288,7 +1308,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); - goto error; + goto error_unload; } } @@ -1301,13 +1321,13 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex { result = paUnanticipatedHostError; PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); - goto error; + goto error_unload; } } /* unload the driver */ - ASIOExit(); + UnloadAsioDriver(); (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; ++(*hostApi)->info.deviceCount; @@ -1344,6 +1364,9 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex return result; +error_unload: + UnloadAsioDriver(); + error: if( asioHostApi ) { @@ -1516,7 +1539,7 @@ done: /* close the device if it wasn't already open */ 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 ) @@ -1865,7 +1888,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, if( result == paNoError ) asioIsInitialized = 1; else{ - PA_DEBUG(("OpenStream ERROR1\n")); + PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result)); goto error; } @@ -2577,8 +2600,9 @@ error: ASIODisposeBuffers(); if( asioIsInitialized ) - ASIOExit(); - + { + UnloadAsioDriver(); + } return result; } @@ -2629,7 +2653,7 @@ static PaError CloseStream( PaStream* s ) PaUtil_FreeMemory( stream ); ASIODisposeBuffers(); - ASIOExit(); + UnloadAsioDriver(); return result; } @@ -3382,7 +3406,7 @@ static PaError ReadStream( PaStream *s , data block is processed although it may be incomplete. */ /* 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! */ /* ResetEvent( blockingState->readFramesReadyEvent ); */ @@ -3557,7 +3581,7 @@ static PaError WriteStream( PaStream *s , data block is processed although it may be incomplete. */ /* 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! */ /* ResetEvent( blockingState->writeBuffersReadyEvent ); */ @@ -3716,10 +3740,9 @@ PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ) asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice]; - /* @todo note that the V18 version always called CoInitialize() here to ensure - that COM was initialized before loading the driver. - probably the docs need to require clients to initialize COM in new threads? - */ + /* See notes about CoInitialize(0) in LoadAsioDriver(). */ + CoInitialize(0); + if( !asioHostApi->asioDrivers->loadDriver( const_cast(asioDeviceInfo->commonDeviceInfo.name) ) ) { result = paUnanticipatedHostError; @@ -3768,13 +3791,17 @@ PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErr goto error; } + CoUninitialize(); PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) )); return result; error: if( asioIsInitialized ) - ASIOExit(); + { + ASIOExit(); + } + CoUninitialize(); return result; } @@ -3885,7 +3912,7 @@ static int BlockingIoPaCallback(const void *inputBuffer , pRb = &blockingState->writeRingBuffer; /* 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. */ PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer ); @@ -3899,7 +3926,7 @@ static int BlockingIoPaCallback(const void *inputBuffer , (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer ); /* 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, whether it is a complete data block or not. */ @@ -3908,7 +3935,7 @@ static int BlockingIoPaCallback(const void *inputBuffer , } /* 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. */ blockingState->writeBuffersRequestedFlag = FALSE; @@ -3934,7 +3961,7 @@ static int BlockingIoPaCallback(const void *inputBuffer , pRb = &blockingState->readRingBuffer; /* 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. */ blockingState->inputOverflowFlag = TRUE; @@ -3947,7 +3974,7 @@ static int BlockingIoPaCallback(const void *inputBuffer , PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer ); /* 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. */ blockingState->readFramesRequestedFlag = FALSE;