From 906e5ba67f7c253655b7f1a29b832bb7852e1126 Mon Sep 17 00:00:00 2001 From: Gary Scavone Date: Mon, 15 Apr 2013 15:30:29 +0000 Subject: Various updates for pulse audio, preparation for release 4.0.12, error callback addition (GS). --- RtAudio.cpp | 233 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 73 deletions(-) (limited to 'RtAudio.cpp') diff --git a/RtAudio.cpp b/RtAudio.cpp index 70414a6..3563151 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -38,7 +38,7 @@ */ /************************************************************************/ -// RtAudio: Version 4.0.11 +// RtAudio: Version 4.0.12 #include "RtAudio.h" #include @@ -189,11 +189,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, - RtAudio::StreamOptions *options ) + RtAudio::StreamOptions *options, + RtAudioErrorCallback errorCallback ) { return rtapi_->openStream( outputParameters, inputParameters, format, sampleRate, bufferFrames, callback, - userData, options ); + userData, options, errorCallback ); } // *************************************************** // @@ -224,31 +225,37 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, - RtAudio::StreamOptions *options ) + RtAudio::StreamOptions *options, + RtAudioErrorCallback errorCallback ) { if ( stream_.state != STREAM_CLOSED ) { errorText_ = "RtApi::openStream: a stream is already open!"; error( RtError::INVALID_USE ); + return; } if ( oParams && oParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one."; error( RtError::INVALID_USE ); + return; } if ( iParams && iParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one."; error( RtError::INVALID_USE ); + return; } if ( oParams == NULL && iParams == NULL ) { errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!"; error( RtError::INVALID_USE ); + return; } if ( formatBytes(format) == 0 ) { errorText_ = "RtApi::openStream: 'format' parameter value is undefined."; error( RtError::INVALID_USE ); + return; } unsigned int nDevices = getDeviceCount(); @@ -258,6 +265,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( oParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: output device parameter value is invalid."; error( RtError::INVALID_USE ); + return; } } @@ -267,6 +275,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( iParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: input device parameter value is invalid."; error( RtError::INVALID_USE ); + return; } } @@ -277,7 +286,10 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options ); - if ( result == false ) error( RtError::SYSTEM_ERROR ); + if ( result == false ) { + error( RtError::SYSTEM_ERROR ); + return; + } } if ( iChannels > 0 ) { @@ -287,11 +299,13 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( result == false ) { if ( oChannels > 0 ) closeStream(); error( RtError::SYSTEM_ERROR ); + return; } } stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.userData = userData; + stream_.callbackInfo.errorCallback = (void *) errorCallback; if ( options ) options->numberOfBuffers = stream_.nBuffers; stream_.state = STREAM_STOPPED; @@ -315,10 +329,10 @@ void RtApi :: closeStream( void ) return; } -bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, - unsigned int firstChannel, unsigned int sampleRate, - RtAudioFormat format, unsigned int *bufferSize, - RtAudio::StreamOptions *options ) +bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/, + unsigned int /*firstChannel*/, unsigned int /*sampleRate*/, + RtAudioFormat /*format*/, unsigned int * /*bufferSize*/, + RtAudio::StreamOptions * /*options*/ ) { // MUST be implemented in subclasses! return FAILURE; @@ -423,8 +437,6 @@ struct CoreHandle { :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } }; -ThreadHandle threadId; - RtApiCore:: RtApiCore() { #if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER ) @@ -543,11 +555,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) if ( nDevices == 0 ) { errorText_ = "RtApiCore::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); + return info; } if ( device >= nDevices ) { errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } AudioDeviceID deviceList[ nDevices ]; @@ -736,13 +750,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device ) return info; } -OSStatus callbackHandler( AudioDeviceID inDevice, - const AudioTimeStamp* inNow, - const AudioBufferList* inInputData, - const AudioTimeStamp* inInputTime, - AudioBufferList* outOutputData, - const AudioTimeStamp* inOutputTime, - void* infoPointer ) +static OSStatus callbackHandler( AudioDeviceID inDevice, + const AudioTimeStamp* /*inNow*/, + const AudioBufferList* inInputData, + const AudioTimeStamp* /*inInputTime*/, + AudioBufferList* outOutputData, + const AudioTimeStamp* /*inOutputTime*/, + void* infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; @@ -753,10 +767,10 @@ OSStatus callbackHandler( AudioDeviceID inDevice, return kAudioHardwareNoError; } -OSStatus xrunListener( AudioObjectID inDevice, - UInt32 nAddresses, - const AudioObjectPropertyAddress properties[], - void* handlePointer ) +static OSStatus xrunListener( AudioObjectID /*inDevice*/, + UInt32 nAddresses, + const AudioObjectPropertyAddress properties[], + void* handlePointer ) { CoreHandle *handle = (CoreHandle *) handlePointer; for ( UInt32 i=0; iobject; @@ -1484,6 +1499,7 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { + ThreadHandle threadId; stream_.state = STREAM_STOPPING; if ( handle->internalDrain == true ) @@ -1821,8 +1837,7 @@ struct JackHandle { :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; } }; -ThreadHandle threadId; -void jackSilentError( const char * ) {}; +static void jackSilentError( const char * ) {}; RtApiJack :: RtApiJack() { @@ -1911,6 +1926,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) jack_client_close( client ); errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } // Get the current jack server sample rate. @@ -1961,7 +1977,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) return info; } -int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) +static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; @@ -1975,7 +1991,7 @@ int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) // server signals that it is shutting down. It is necessary to handle // it this way because the jackShutdown() function must return before // the jack_deactivate() function (in closeStream()) will return. -extern "C" void *jackCloseStream( void *ptr ) +static void *jackCloseStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; @@ -1984,7 +2000,7 @@ extern "C" void *jackCloseStream( void *ptr ) pthread_exit( NULL ); } -void jackShutdown( void *infoPointer ) +static void jackShutdown( void *infoPointer ) { CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiJack *object = (RtApiJack *) info->object; @@ -1996,11 +2012,12 @@ void jackShutdown( void *infoPointer ) // other problem occurred and we should close the stream. if ( object->isStreamRunning() == false ) return; + ThreadHandle threadId; pthread_create( &threadId, NULL, jackCloseStream, info ); std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl; } -int jackXrun( void *infoPointer ) +static int jackXrun( void *infoPointer ) { JackHandle *handle = (JackHandle *) infoPointer; @@ -2418,7 +2435,7 @@ void RtApiJack :: abortStream( void ) // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the jack_deactivate() // function will return. -extern "C" void *jackStopStream( void *ptr ) +static void *jackStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiJack *object = (RtApiJack *) info->object; @@ -2446,6 +2463,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) // Check if we were draining the stream and signal is finished. if ( handle->drainCounter > 3 ) { + ThreadHandle threadId; stream_.state = STREAM_STOPPING; if ( handle->internalDrain == true ) @@ -2565,11 +2583,11 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) #include "asiodrivers.h" #include -AsioDrivers drivers; -ASIOCallbacks asioCallbacks; -ASIODriverInfo driverInfo; -CallbackInfo *asioCallbackInfo; -bool asioXRun; +static AsioDrivers drivers; +static ASIOCallbacks asioCallbacks; +static ASIODriverInfo driverInfo; +static CallbackInfo *asioCallbackInfo; +static bool asioXRun; struct AsioHandle { int drainCounter; // Tracks callback counts when draining @@ -2583,8 +2601,8 @@ struct AsioHandle { // Function declarations (definitions at end of section) static const char* getAsioErrorString( ASIOError result ); -void sampleRateChanged( ASIOSampleRate sRate ); -long asioMessages( long selector, long value, void* message, double* opt ); +static void sampleRateChanged( ASIOSampleRate sRate ); +static long asioMessages( long selector, long value, void* message, double* opt ); RtApiAsio :: RtApiAsio() { @@ -2627,11 +2645,13 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) if ( nDevices == 0 ) { errorText_ = "RtApiAsio::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); + return info; } if ( device >= nDevices ) { errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } // If a stream is already open, we cannot probe other devices. Thus, use the saved results. @@ -2730,7 +2750,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device ) return info; } -void bufferSwitch( long index, ASIOBool processNow ) +static void bufferSwitch( long index, ASIOBool processNow ) { RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object; object->callbackEvent( index ); @@ -3230,7 +3250,7 @@ void RtApiAsio :: abortStream() // aborted. It is necessary to handle it this way because the // callbackEvent() function must return before the ASIOStop() // function will return. -extern "C" unsigned __stdcall asioStopStream( void *ptr ) +static unsigned __stdcall asioStopStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAsio *object = (RtApiAsio *) info->object; @@ -3393,7 +3413,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex ) return SUCCESS; } -void sampleRateChanged( ASIOSampleRate sRate ) +static void sampleRateChanged( ASIOSampleRate sRate ) { // The ASIO documentation says that this usually only happens during // external sync. Audio processing is not stopped by the driver, @@ -3413,7 +3433,7 @@ void sampleRateChanged( ASIOSampleRate sRate ) std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl; } -long asioMessages( long selector, long value, void* message, double* opt ) +static long asioMessages( long selector, long value, void* message, double* opt ) { long ret = 0; @@ -3491,7 +3511,7 @@ static const char* getAsioErrorString( ASIOError result ) const char*message; }; - static Messages m[] = + static const Messages m[] = { { ASE_NotPresent, "Hardware input or output is not present or available." }, { ASE_HWMalfunction, "Hardware is malfunctioning." }, @@ -3572,7 +3592,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, static const char* getErrorString( int code ); -extern "C" unsigned __stdcall callbackHandler( void *ptr ); +static unsigned __stdcall callbackHandler( void *ptr ); struct DsDevice { LPGUID id[2]; @@ -3584,7 +3604,10 @@ struct DsDevice { : found(false) { validId[0] = false; validId[1] = false; } }; -std::vector< DsDevice > dsDevices; +struct DsProbeData { + bool isInput; + std::vector* dsDevices; +}; RtApiDs :: RtApiDs() { @@ -3622,8 +3645,10 @@ unsigned int RtApiDs :: getDeviceCount( void ) dsDevices[i].found = false; // Query DirectSound devices. - bool isInput = false; - HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput ); + struct DsProbeData probeInfo; + probeInfo.isInput = false; + probeInfo.dsDevices = &dsDevices; + HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!"; errorText_ = errorStream_.str(); @@ -3631,8 +3656,8 @@ unsigned int RtApiDs :: getDeviceCount( void ) } // Query DirectSoundCapture devices. - isInput = true; - result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput ); + probeInfo.isInput = true; + result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!"; errorText_ = errorStream_.str(); @@ -3661,12 +3686,14 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device ) if ( dsDevices.size() == 0 ) { errorText_ = "RtApiDs::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); + return info; } } if ( device >= dsDevices.size() ) { errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } HRESULT result; @@ -4321,6 +4348,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned stream_.deviceBuffer = 0; } + stream_.state = STREAM_CLOSED; return FAILURE; } @@ -4642,12 +4670,14 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } while ( true ) { result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer ); @@ -4655,12 +4685,14 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer ); if ( FAILED( result ) ) { errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break; Sleep( 1 ); @@ -4681,6 +4713,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0]; if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0]; @@ -4731,6 +4764,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } // We will copy our output buffer into the region between @@ -4771,6 +4805,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } // Copy our buffer into the DS buffer @@ -4783,6 +4818,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize; handle->bufferPointer[0] = nextWritePointer; @@ -4817,6 +4853,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset @@ -4877,6 +4914,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset @@ -4890,6 +4928,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } if ( duplexPrerollBytes <= 0 ) { @@ -4910,6 +4949,7 @@ void RtApiDs :: callbackEvent() errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!"; errorText_ = errorStream_.str(); error( RtError::SYSTEM_ERROR ); + return; } handle->bufferPointer[1] = nextReadPointer; @@ -4931,7 +4971,7 @@ void RtApiDs :: callbackEvent() // Definitions for utility functions and callbacks // specific to the DirectSound implementation. -extern "C" unsigned __stdcall callbackHandler( void *ptr ) +static unsigned __stdcall callbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiDs *object = (RtApiDs *) info->object; @@ -4947,7 +4987,7 @@ extern "C" unsigned __stdcall callbackHandler( void *ptr ) #include "tchar.h" -std::string convertTChar( LPCTSTR name ) +static std::string convertTChar( LPCTSTR name ) { #if defined( UNICODE ) || defined( _UNICODE ) int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL); @@ -4965,11 +5005,12 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, LPCTSTR module, LPVOID lpContext ) { - bool *isInput = (bool *) lpContext; + struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext; + std::vector& dsDevices = *probeInfo.dsDevices; HRESULT hr; bool validDevice = false; - if ( *isInput == true ) { + if ( probeInfo.isInput == true ) { DSCCAPS caps; LPDIRECTSOUNDCAPTURE object; @@ -5001,13 +5042,14 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid, // If good device, then save its name and guid. std::string name = convertTChar( description ); - if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) + //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" ) + if ( lpguid == NULL ) name = "Default Device"; if ( validDevice ) { for ( unsigned int i=0; i= nDevices ) { errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } foundDevice: @@ -5961,6 +6005,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.deviceBuffer = 0; } + stream_.state = STREAM_CLOSED; return FAILURE; } @@ -6335,7 +6380,7 @@ void RtApiAlsa :: callbackEvent() if ( doStopStream == 1 ) this->stopStream(); } -extern "C" void *alsaCallbackHandler( void *ptr ) +static void *alsaCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiAlsa *object = (RtApiAlsa *) info->object; @@ -6369,9 +6414,8 @@ extern "C" void *alsaCallbackHandler( void *ptr ) #include #include -namespace { -const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000, - 44100, 48000, 96000, 0}; } +static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000, + 44100, 48000, 96000, 0}; struct rtaudio_pa_format_mapping_t { RtAudioFormat rtaudio_format; @@ -6423,7 +6467,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int device ) return info; } -extern "C" void *pulseaudio_callback( void * user ) +static void *pulseaudio_callback( void * user ) { CallbackInfo *cbi = static_cast( user ); RtApiPulse *context = static_cast( cbi->object ); @@ -6618,6 +6662,7 @@ void RtApiPulse::stopStream( void ) errorText_ = errorStream_.str(); MUTEX_UNLOCK( &stream_.mutex ); error( RtError::SYSTEM_ERROR ); + return; } } @@ -6651,6 +6696,7 @@ void RtApiPulse::abortStream( void ) errorText_ = errorStream_.str(); MUTEX_UNLOCK( &stream_.mutex ); error( RtError::SYSTEM_ERROR ); + return; } } @@ -6748,9 +6794,8 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, } } } - + stream_.device[mode] = device; - stream_.state = STREAM_STOPPED; // Setup the buffer conversion information structure. if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel ); @@ -6797,8 +6842,6 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, else stream_.mode = DUPLEX; - stream_.state = STREAM_STOPPED; - if ( !stream_.callbackInfo.isRunning ) { stream_.callbackInfo.object = this; stream_.callbackInfo.isRunning = true; @@ -6807,11 +6850,30 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, goto error; } } + + stream_.state = STREAM_STOPPED; return true; error: - closeStream(); - return false; + if ( pah && stream_.callbackInfo.isRunning ) { + pthread_cond_destroy( &pah->runnable_cv ); + delete pah; + stream_.apiHandle = 0; + } + + for ( int i=0; i<2; i++ ) { + if ( stream_.userBuffer[i] ) { + free( stream_.userBuffer[i] ); + stream_.userBuffer[i] = 0; + } + } + + if ( stream_.deviceBuffer ) { + free( stream_.deviceBuffer ); + stream_.deviceBuffer = 0; + } + + return FAILURE; } //******************** End of __LINUX_PULSE__ *********************// @@ -6827,7 +6889,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, #include #include -extern "C" void *ossCallbackHandler(void * ptr); +static void *ossCallbackHandler(void * ptr); // A structure to hold various information related to the OSS API // implementation. @@ -6898,12 +6960,14 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device ) close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: no devices found!"; error( RtError::INVALID_USE ); + return info; } if ( device >= nDevices ) { close( mixerfd ); errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!"; error( RtError::INVALID_USE ); + return info; } oss_audioinfo ainfo; @@ -7734,7 +7798,7 @@ void RtApiOss :: callbackEvent() if ( doStopStream == 1 ) this->stopStream(); } -extern "C" void *ossCallbackHandler( void *ptr ) +static void *ossCallbackHandler( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; RtApiOss *object = (RtApiOss *) info->object; @@ -7763,6 +7827,28 @@ extern "C" void *ossCallbackHandler( void *ptr ) void RtApi :: error( RtError::Type type ) { errorStream_.str(""); // clear the ostringstream + + RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback; + if ( errorCallback ) { + // abortStream() can generate new error messages. Ignore them. Just keep original one. + static bool firstErrorOccured = false; + + if ( firstErrorOccured ) + return; + + firstErrorOccured = true; + const std::string errorMessage = errorText_; + + if ( type != RtError::WARNING && stream_.state != STREAM_STOPPED) { + stream_.callbackInfo.isRunning = false; // exit from the thread + abortStream(); + } + + errorCallback( type, errorMessage ); + firstErrorOccured = false; + return; + } + if ( type == RtError::WARNING && showWarnings_ == true ) std::cerr << '\n' << errorText_ << "\n\n"; else if ( type != RtError::WARNING ) @@ -7792,6 +7878,7 @@ void RtApi :: clearStreamInfo() stream_.callbackInfo.callback = 0; stream_.callbackInfo.userData = 0; stream_.callbackInfo.isRunning = false; + stream_.callbackInfo.errorCallback = 0; for ( int i=0; i<2; i++ ) { stream_.device[i] = 11111; stream_.doConvertBuffer[i] = false; -- cgit v1.2.3