From f680bc760bce103406a81053c4d56cd501e95002 Mon Sep 17 00:00:00 2001 From: Gary Scavone Date: Thu, 31 May 2012 17:23:37 +0000 Subject: [PATCH] Updates regarding leaks in ALSA, bitwise format flags in OS-X, and changes to stopStream / drain flag to avoid hung state in ASIO, DS, OS-X, and Jack APIs. --- RtAudio.cpp | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/RtAudio.cpp b/RtAudio.cpp index d4f3819..656be06 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -106,6 +106,10 @@ void RtAudio :: getCompiledApi( std::vector &apis ) throw() void RtAudio :: openRtApi( RtAudio::Api api ) { + if (rtapi_) + delete rtapi_; + rtapi_ = 0; + #if defined(__UNIX_JACK__) if ( api == UNIX_JACK ) rtapi_ = new RtApiJack(); @@ -1080,7 +1084,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // We'll try higher bit rates first and then work our way down. std::vector< std::pair > physicalFormats; - formatFlags = description.mFormatFlags | kLinearPCMFormatFlagIsFloat & ~kLinearPCMFormatFlagIsSignedInteger; + formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger; physicalFormats.push_back( std::pair( 32, formatFlags ) ); formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat; physicalFormats.push_back( std::pair( 32, formatFlags ) ); @@ -1507,14 +1511,16 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, handle->xrun[1] = false; } - handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], - stream_.bufferSize, streamTime, status, info->userData ); - if ( handle->drainCounter == 2 ) { + int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], + stream_.bufferSize, streamTime, status, info->userData ); + if ( cbReturnValue == 2 ) { MUTEX_UNLOCK( &stream_.mutex ); + handle->drainCounter = 2; abortStream(); return SUCCESS; } - else if ( handle->drainCounter == 1 ) + else if ( cbReturnValue == 1 ) + handle->drainCounter = 1; handle->internalDrain = true; } @@ -1901,6 +1907,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) } if ( device >= nDevices ) { + jack_client_close( client ); errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); } @@ -2471,15 +2478,17 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } - handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], - stream_.bufferSize, streamTime, status, info->userData ); - if ( handle->drainCounter == 2 ) { + int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], + stream_.bufferSize, streamTime, status, info->userData ); + if ( cbReturnValue == 2 ) { MUTEX_UNLOCK( &stream_.mutex ); ThreadHandle id; + handle->drainCounter = 2; pthread_create( &id, NULL, jackStopStream, info ); return SUCCESS; } - else if ( handle->drainCounter == 1 ) + else if ( cbReturnValue == 1 ) + handle->drainCounter = 1; handle->internalDrain = true; } @@ -3300,18 +3309,20 @@ bool RtApiAsio :: callbackEvent( long bufferIndex ) status |= RTAUDIO_INPUT_OVERFLOW; asioXRun = false; } - handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], + int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, info->userData ); - if ( handle->drainCounter == 2 ) { + if ( cbReturnValue == 2 ) { // MUTEX_UNLOCK( &stream_.mutex ); // abortStream(); unsigned threadId; stopThreadCalled = true; + handle->drainCounter = 2; stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream, &stream_.callbackInfo, 0, &threadId ); return SUCCESS; } - else if ( handle->drainCounter == 1 ) + else if ( cbReturnValue == 1 ) + handle->drainCounter = 1; handle->internalDrain = true; } @@ -4634,14 +4645,16 @@ void RtApiDs :: callbackEvent() status |= RTAUDIO_INPUT_OVERFLOW; handle->xrun[1] = false; } - handle->drainCounter = callback( stream_.userBuffer[0], stream_.userBuffer[1], - stream_.bufferSize, streamTime, status, info->userData ); - if ( handle->drainCounter == 2 ) { + int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], + stream_.bufferSize, streamTime, status, info->userData ); + if ( cbReturnValue == 2 ) { // MUTEX_UNLOCK( &stream_.mutex ); + handle->drainCounter = 2; abortStream(); return; } - else if ( handle->drainCounter == 1 ) + else if ( cbReturnValue == 1 ) + handle->drainCounter = 1; handle->internalDrain = true; } @@ -4908,7 +4921,7 @@ void RtApiDs :: callbackEvent() } } else { // mode == INPUT - while ( safeReadPointer < endRead ) { + while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) { // See comments for playback. double millis = (endRead - safeReadPointer) * 1000.0; millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate); @@ -5268,6 +5281,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device ) // Thus, use the saved results. if ( stream_.state != STREAM_CLOSED && ( stream_.device[0] == device || stream_.device[1] == device ) ) { + snd_ctl_close( chandle ); if ( device >= devices_.size() ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened."; error( RtError::WARNING ); @@ -5672,6 +5686,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } // If we get here, no supported format was found. + snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio."; errorText_ = errorStream_.str(); return FAILURE; @@ -5769,6 +5784,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // If attempting to setup a duplex stream, the bufferSize parameter // MUST be the same in both directions! if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) { + snd_pcm_close( phandle ); errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ")."; errorText_ = errorStream_.str(); return FAILURE; @@ -5855,6 +5871,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne apiInfo = (AlsaHandle *) stream_.apiHandle; } apiInfo->handles[mode] = phandle; + phandle = 0; // Allocate necessary internal buffers. unsigned long bufferBytes; @@ -5962,6 +5979,8 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.apiHandle = 0; } + if ( phandle) snd_pcm_close( phandle ); + for ( int i=0; i<2; i++ ) { if ( stream_.userBuffer[i] ) { free( stream_.userBuffer[i] ); -- 2.30.2