diff options
| author | Gary Scavone <gary@music.mcgill.ca> | 2019-07-30 12:26:44 -0400 |
|---|---|---|
| committer | Gary Scavone <gary@music.mcgill.ca> | 2019-07-30 12:26:44 -0400 |
| commit | 6c7651fd65e2d6d423836cee77a48d1b238b2595 (patch) | |
| tree | 22f480750f83e3c8b4155bd8557438c4f34da142 | |
| parent | a09f92013c020e23bad9fecd2cb7ad8b9dbb4fd6 (diff) | |
Added new setErrorCallback() function and removed errorCallback argument in openStream(). Also added RtAudioError::Type return value to openStream(), startStream(), stopStream() and abortStream() functions, but only implemented in RtApiCore.
| -rw-r--r-- | RtAudio.cpp | 136 | ||||
| -rw-r--r-- | RtAudio.h | 118 | ||||
| -rw-r--r-- | rtaudio_c.cpp | 3 | ||||
| -rw-r--r-- | tests/playsaw.cpp | 15 |
4 files changed, 152 insertions, 120 deletions
diff --git a/RtAudio.cpp b/RtAudio.cpp index a14f954..e147b36 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -264,7 +264,7 @@ RtAudio :: RtAudio( RtAudio::Api api ) // It should not be possible to get here because the preprocessor // definition __RTAUDIO_DUMMY__ is automatically defined in RtAudio.h // if no API-specific definitions are passed to the compiler. But just - // in case something weird happens, we'll thow an error. + // in case something weird happens, we'll throw an error. std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n"; throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) ); } @@ -275,17 +275,17 @@ RtAudio :: ~RtAudio() delete rtapi_; } -void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, - RtAudio::StreamParameters *inputParameters, - RtAudioFormat format, unsigned int sampleRate, - unsigned int *bufferFrames, - RtAudioCallback callback, void *userData, - RtAudio::StreamOptions *options, - RtAudioErrorCallback errorCallback ) +//void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, +RtAudioError::Type RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, + RtAudio::StreamParameters *inputParameters, + RtAudioFormat format, unsigned int sampleRate, + unsigned int *bufferFrames, + RtAudioCallback callback, void *userData, + RtAudio::StreamOptions *options ) //, RtAudioErrorCallback errorCallback ) { return rtapi_->openStream( outputParameters, inputParameters, format, sampleRate, bufferFrames, callback, - userData, options, errorCallback ); + userData, options ); //, errorCallback ); } // *************************************************** // @@ -299,8 +299,9 @@ RtApi :: RtApi() { clearStreamInfo(); MUTEX_INITIALIZE( &stream_.mutex ); + errorCallback_ = 0; showWarnings_ = true; - firstErrorOccurred_ = false; + //firstErrorOccurred_ = false; } RtApi :: ~RtApi() @@ -308,18 +309,19 @@ RtApi :: ~RtApi() MUTEX_DESTROY( &stream_.mutex ); } -void RtApi :: openStream( RtAudio::StreamParameters *oParams, - RtAudio::StreamParameters *iParams, - RtAudioFormat format, unsigned int sampleRate, - unsigned int *bufferFrames, - RtAudioCallback callback, void *userData, - RtAudio::StreamOptions *options, - RtAudioErrorCallback errorCallback ) +//void RtApi :: openStream( RtAudio::StreamParameters *oParams, +RtAudioError::Type RtApi :: openStream( RtAudio::StreamParameters *oParams, + RtAudio::StreamParameters *iParams, + RtAudioFormat format, unsigned int sampleRate, + unsigned int *bufferFrames, + RtAudioCallback callback, void *userData, + RtAudio::StreamOptions *options ) //, RtAudioErrorCallback errorCallback ) { + //RtAudioError::Type type = RtAudioError::NO_ERROR; if ( stream_.state != STREAM_CLOSED ) { + //type = RtAudioError::INVALID_USE; errorText_ = "RtApi::openStream: a stream is already open!"; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); } // Clear stream information potentially left from a previously open stream. @@ -327,26 +329,26 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, if ( oParams && oParams->nChannels < 1 ) { errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one."; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::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( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); + //return; } if ( oParams == NULL && iParams == NULL ) { errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!"; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); + //return; } if ( formatBytes(format) == 0 ) { errorText_ = "RtApi::openStream: 'format' parameter value is undefined."; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); + //return; } unsigned int nDevices = getDeviceCount(); @@ -355,8 +357,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, oChannels = oParams->nChannels; if ( oParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: output device parameter value is invalid."; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); + //return; } } @@ -365,8 +367,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, iChannels = iParams->nChannels; if ( iParams->deviceId >= nDevices ) { errorText_ = "RtApi::openStream: input device parameter value is invalid."; - error( RtAudioError::INVALID_USE ); - return; + return error( RtAudioError::INVALID_USE ); + //return; } } @@ -377,8 +379,8 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel, sampleRate, format, bufferFrames, options ); if ( result == false ) { - error( RtAudioError::SYSTEM_ERROR ); - return; + return error( RtAudioError::SYSTEM_ERROR ); + //return; } } @@ -388,17 +390,18 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, sampleRate, format, bufferFrames, options ); if ( result == false ) { if ( oChannels > 0 ) closeStream(); - error( RtAudioError::SYSTEM_ERROR ); - return; + return error( RtAudioError::SYSTEM_ERROR ); + //return; } } stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.userData = userData; - stream_.callbackInfo.errorCallback = (void *) errorCallback; + //stream_.callbackInfo.errorCallback = (void *) errorCallback; if ( options ) options->numberOfBuffers = stream_.nBuffers; stream_.state = STREAM_STOPPED; + return RtAudioError::NO_ERROR; } unsigned int RtApi :: getDefaultInputDevice( void ) @@ -490,14 +493,12 @@ void RtApi :: setStreamTime( double time ) */ } -/* unsigned int RtApi :: getStreamSampleRate( void ) { - verifyStream(); - - return stream_.sampleRate; + //verifyStream(); + if ( isStreamOpen() ) return stream_.sampleRate; + else return 0; } -*/ // *************************************************** // @@ -1564,7 +1565,8 @@ void RtApiCore :: closeStream( void ) //stream_.state = STREAM_CLOSED; } -void RtApiCore :: startStream( void ) +//void RtApiCore :: startStream( void ) +RtAudioError::Type RtApiCore :: startStream( void ) { //verifyStream(); if ( stream_.state != STREAM_STOPPED ) { @@ -1572,8 +1574,8 @@ void RtApiCore :: startStream( void ) errorText_ = "RtApiCore::startStream(): the stream is already running!"; else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED ) errorText_ = "RtApiCore::startStream(): the stream is stopping or closed!"; - error( RtAudioError::WARNING ); - return; + return error( RtAudioError::WARNING ); + //return; } /* @@ -1616,11 +1618,12 @@ void RtApiCore :: startStream( void ) stream_.state = STREAM_RUNNING; unlock: - if ( result == noErr ) return; - error( RtAudioError::SYSTEM_ERROR ); + if ( result == noErr ) return RtAudioError::NO_ERROR; + return error( RtAudioError::SYSTEM_ERROR ); } -void RtApiCore :: stopStream( void ) +//void RtApiCore :: stopStream( void ) +RtAudioError::Type RtApiCore :: stopStream( void ) { //verifyStream(); if ( stream_.state != STREAM_RUNNING && stream_.state != STREAM_STOPPING ) { @@ -1628,8 +1631,8 @@ void RtApiCore :: stopStream( void ) errorText_ = "RtApiCore::stopStream(): the stream is already stopped!"; else if ( stream_.state == STREAM_CLOSED ) errorText_ = "RtApiCore::stopStream(): the stream is closed!"; - error( RtAudioError::WARNING ); - return; + return error( RtAudioError::WARNING ); + //return; } OSStatus result = noErr; @@ -1662,11 +1665,12 @@ void RtApiCore :: stopStream( void ) stream_.state = STREAM_STOPPED; unlock: - if ( result == noErr ) return; - error( RtAudioError::SYSTEM_ERROR ); + if ( result == noErr ) return RtAudioError::NO_ERROR; + return error( RtAudioError::SYSTEM_ERROR ); } -void RtApiCore :: abortStream( void ) +//void RtApiCore :: abortStream( void ) +RtAudioError::Type RtApiCore :: abortStream( void ) { //verifyStream(); if ( stream_.state != STREAM_RUNNING ) { @@ -1674,15 +1678,15 @@ void RtApiCore :: abortStream( void ) errorText_ = "RtApiCore::abortStream(): the stream is already stopped!"; else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED ) errorText_ = "RtApiCore::abortStream(): the stream is stopping or closed!"; - error( RtAudioError::WARNING ); - return; + return error( RtAudioError::WARNING ); + //return; } CoreHandle *handle = (CoreHandle *) stream_.apiHandle; handle->drainCounter = 2; stream_.state = STREAM_STOPPING; - stopStream(); + return stopStream(); } // This function will be called by a spawned thread when the user @@ -9983,19 +9987,21 @@ static void *ossCallbackHandler( void *ptr ) // This method can be modified to control the behavior of error // message printing. -void RtApi :: error( RtAudioError::Type type ) +//void RtApi :: error( RtAudioError::Type type ) +RtAudioError::Type RtApi :: error( RtAudioError::Type type ) { - errorStream_.str(""); // clear the ostringstream + errorStream_.str(""); // clear the ostringstream to avoid repeated messages - RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback; - if ( errorCallback ) { + // Don't output warnings if showWarnings_ is false + if ( type == RtAudioError::WARNING && showWarnings_ == false ) return type; + + if ( errorCallback_ ) { const std::string errorMessage = errorText_; - errorCallback( type, errorMessage ); - } - else { - if ( showWarnings_ == true ) - std::cerr << '\n' << errorText_ << "\n\n"; + errorCallback_( type, errorMessage ); } + else + std::cerr << '\n' << errorText_ << "\n\n"; + return type; } /* @@ -10023,7 +10029,7 @@ void RtApi :: clearStreamInfo() stream_.callbackInfo.callback = 0; stream_.callbackInfo.userData = 0; stream_.callbackInfo.isRunning = false; - stream_.callbackInfo.errorCallback = 0; + //stream_.callbackInfo.errorCallback = 0; for ( int i=0; i<2; i++ ) { stream_.device[i] = 11111; stream_.doConvertBuffer[i] = false; @@ -221,8 +221,8 @@ class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error public: //! Defined RtAudioError types. enum Type { + NO_ERROR, /*!< No error. */ WARNING, /*!< A non-critical error. */ - DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */ UNSPECIFIED, /*!< The default, unspecified error type. */ NO_DEVICES_FOUND, /*!< No devices found on system. */ INVALID_DEVICE, /*!< An invalid device ID was specified. */ @@ -531,11 +531,12 @@ class RTAUDIO_DLL_PUBLIC RtAudio \param errorCallback A client-defined function that will be invoked when an error has occured. */ - void openStream( RtAudio::StreamParameters *outputParameters, - RtAudio::StreamParameters *inputParameters, - RtAudioFormat format, unsigned int sampleRate, - unsigned int *bufferFrames, RtAudioCallback callback, - void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); + //void openStream( RtAudio::StreamParameters *outputParameters, + RtAudioError::Type openStream( RtAudio::StreamParameters *outputParameters, + RtAudio::StreamParameters *inputParameters, + RtAudioFormat format, unsigned int sampleRate, + unsigned int *bufferFrames, RtAudioCallback callback, + void *userData = NULL, RtAudio::StreamOptions *options = NULL ); //, RtAudioErrorCallback errorCallback = NULL ); //! A function that closes a stream and frees any associated stream memory. /*! @@ -546,30 +547,30 @@ class RTAUDIO_DLL_PUBLIC RtAudio //! A function that starts a stream. /*! - An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs - during processing. An RtAudioError (type = INVALID_USE) is thrown if a - stream is not open. A warning is issued if the stream is already - running. + An RtAudioError::SYSTEM_ERROR is returned if an error occurs + during processing. An RtAudioError:WARNING is returned if a + stream is not open or is already running. */ - void startStream( void ); + //void startStream( void ); + RtAudioError::Type startStream( void ); //! Stop a stream, allowing any samples remaining in the output queue to be played. /*! - An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs - during processing. An RtAudioError (type = INVALID_USE) is thrown if a - stream is not open. A warning is issued if the stream is already - stopped. + An RtAudioError::SYSTEM_ERROR is returned if an error occurs + during processing. An RtAudioError::WARNING is returned if a + stream is not open or is already stopped. */ - void stopStream( void ); + //void stopStream( void ); + RtAudioError::Type stopStream( void ); //! Stop a stream, discarding any samples remaining in the input/output queue. /*! - An RtAudioError (type = SYSTEM_ERROR) is thrown if an error occurs - during processing. An RtAudioError (type = INVALID_USE) is thrown if a - stream is not open. A warning is issued if the stream is already - stopped. + An RtAudioError::SYSTEM_ERROR is returned if an error occurs + during processing. An RtAudioError::WARNING is returned if a + stream is not open or is already stopped. */ - void abortStream( void ); + //void abortStream( void ); + RtAudioError::Type abortStream( void ); //! Returns true if a stream is open and false if not. bool isStreamOpen( void ) const; @@ -600,15 +601,23 @@ class RTAUDIO_DLL_PUBLIC RtAudio */ long getStreamLatency( void ); - //! Returns actual sample rate in use by the stream. - /*! - On some systems, the sample rate used may be slightly different - than that specified in the stream parameters. If a stream is not - open, an RtAudioError (type = INVALID_USE) will be thrown. - */ + //! Returns actual sample rate in use by the (open) stream. + /*! + On some systems, the sample rate used may be slightly different + than that specified in the stream parameters. If a stream is not + open, a value of zero is returned. + */ unsigned int getStreamSampleRate( void ); - //! Specify whether warning messages should be printed to stderr. + //! Set a client-defined function that will be invoked when an error or warning occurs. + void setErrorCallback( RtAudioErrorCallback errorCallback ); + + //! Specify whether warning messages should be output or not. + /*! + The default behaviour is for warning messages to be output, + either to a client-defined error callback function (if specified) + or to stderr. + */ void showWarnings( bool value = true ); protected: @@ -653,7 +662,7 @@ struct CallbackInfo { ThreadHandle thread; void *callback; void *userData; - void *errorCallback; + // void *errorCallback; void *apiInfo; // void pointer for API specific callback information bool isRunning; bool doRealtime; @@ -662,7 +671,7 @@ struct CallbackInfo { // Default constructor. CallbackInfo() - :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0), deviceDisconnected(false) {} + :object(0), callback(0), userData(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0), deviceDisconnected(false) {} // errorCallback(0), }; // **************************************************************** // @@ -725,22 +734,26 @@ public: virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0; virtual unsigned int getDefaultInputDevice( void ); virtual unsigned int getDefaultOutputDevice( void ); - void openStream( RtAudio::StreamParameters *outputParameters, - RtAudio::StreamParameters *inputParameters, - RtAudioFormat format, unsigned int sampleRate, - unsigned int *bufferFrames, RtAudioCallback callback, - void *userData, RtAudio::StreamOptions *options, - RtAudioErrorCallback errorCallback ); + //void openStream( RtAudio::StreamParameters *outputParameters, + RtAudioError::Type openStream( RtAudio::StreamParameters *outputParameters, + RtAudio::StreamParameters *inputParameters, + RtAudioFormat format, unsigned int sampleRate, + unsigned int *bufferFrames, RtAudioCallback callback, + void *userData, RtAudio::StreamOptions *options ); //, RtAudioErrorCallback errorCallback ); virtual void closeStream( void ); - virtual void startStream( void ) = 0; - virtual void stopStream( void ) = 0; - virtual void abortStream( void ) = 0; + //virtual void startStream( void ) = 0; + virtual RtAudioError::Type startStream( void ) = 0; + //virtual void stopStream( void ) = 0; + //virtual void abortStream( void ) = 0; + virtual RtAudioError::Type stopStream( void ) = 0; + virtual RtAudioError::Type abortStream( void ) = 0; long getStreamLatency( void ); - unsigned int getStreamSampleRate( void ) const { return stream_.sampleRate; } + unsigned int getStreamSampleRate( void ); // const { return stream_.sampleRate; } virtual double getStreamTime( void ) const { return stream_.streamTime; } virtual void setStreamTime( double time ); bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; } bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; } + void setErrorCallback( RtAudioErrorCallback errorCallback ) { errorCallback_ = errorCallback; } void showWarnings( bool value ) { showWarnings_ = value; } @@ -816,9 +829,10 @@ protected: std::ostringstream errorStream_; std::string errorText_; + RtAudioErrorCallback errorCallback_; bool showWarnings_; RtApiStream stream_; - bool firstErrorOccurred_; + //bool firstErrorOccurred_; /*! Protected, api-specific method that attempts to open a device @@ -845,7 +859,8 @@ protected: void verifyStream( void ); //! Protected common error method to allow global control over error handling. - void error( RtAudioError::Type type ); + //void error( RtAudioError::Type type ); + RtAudioError::Type error( RtAudioError::Type type ); /*! Protected method used to perform format, channel number, and/or interleaving @@ -875,15 +890,19 @@ inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { ret inline unsigned int RtAudio :: getDefaultInputDevice( void ) { return rtapi_->getDefaultInputDevice(); } inline unsigned int RtAudio :: getDefaultOutputDevice( void ) { return rtapi_->getDefaultOutputDevice(); } inline void RtAudio :: closeStream( void ) { return rtapi_->closeStream(); } -inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); } -inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } -inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } +//inline void RtAudio :: startStream( void ) { return rtapi_->startStream(); } +inline RtAudioError::Type RtAudio :: startStream( void ) { return rtapi_->startStream(); } +//inline void RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } +//inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } +inline RtAudioError::Type RtAudio :: stopStream( void ) { return rtapi_->stopStream(); } +inline RtAudioError::Type RtAudio :: abortStream( void ) { return rtapi_->abortStream(); } inline bool RtAudio :: isStreamOpen( void ) const { return rtapi_->isStreamOpen(); } inline bool RtAudio :: isStreamRunning( void ) const { return rtapi_->isStreamRunning(); } inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); } inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); } inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); } inline void RtAudio :: setStreamTime( double time ) { return rtapi_->setStreamTime( time ); } +inline void RtAudio :: setErrorCallback( RtAudioErrorCallback errorCallback ) { rtapi_->setErrorCallback( errorCallback ); } inline void RtAudio :: showWarnings( bool value ) { rtapi_->showWarnings( value ); } // RtApi Subclass prototypes. @@ -904,9 +923,12 @@ public: unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); void closeStream( void ); - void startStream( void ); - void stopStream( void ); - void abortStream( void ); + //void startStream( void ); + RtAudioError::Type startStream( void ); + //void stopStream( void ;) + RtAudioError::Type stopStream( void ); + //void abortStream( void ); + RtAudioError::Type abortStream( void ); // This function is intended for internal use only. It must be // public because it is called by the internal callback handler, diff --git a/rtaudio_c.cpp b/rtaudio_c.cpp index ad91bab..bcb6930 100644 --- a/rtaudio_c.cpp +++ b/rtaudio_c.cpp @@ -161,8 +161,7 @@ int rtaudio_open_stream(rtaudio_t audio, audio->cb = cb; audio->userdata = userdata; audio->audio->openStream(out, in, (RtAudioFormat)format, sample_rate, - buffer_frames, proxy_cb_func, (void *)audio, opts, - NULL); + buffer_frames, proxy_cb_func, (void *)audio, opts); //, NULL); return 0; } catch (RtAudioError &err) { audio->has_error = 1; diff --git a/tests/playsaw.cpp b/tests/playsaw.cpp index beaf714..e875313 100644 --- a/tests/playsaw.cpp +++ b/tests/playsaw.cpp @@ -66,8 +66,7 @@ void usage( void ) { void errorCallback( RtAudioError::Type /*type*/, const std::string &errorText ) { - // This example error handling function does exactly the same thing - // as the embedded RtAudio::error() function. + // This example error handling function simply outputs the error message to stderr. std::cerr << "\nerrorCallback: " << errorText << "\n\n"; } @@ -172,7 +171,9 @@ int main( int argc, char *argv[] ) double *data = (double *) calloc( channels, sizeof( double ) ); - // Let RtAudio print messages to stderr. + // Specify our own error callback function and tell RtAudio to + // output all messages, even warnings. + dac.setErrorCallback( &errorCallback ); dac.showWarnings( true ); // Set our stream parameters for output only. @@ -191,11 +192,15 @@ int main( int argc, char *argv[] ) options.flags |= RTAUDIO_NONINTERLEAVED; #endif - dac.openStream( &oParams, NULL, FORMAT, fs, &bufferFrames, &saw, (void *)data, &options, &errorCallback ); + // An error in the openStream() function can be detected either by + // checking for a non-zero return value OR by a subsequent call to + // isStreamOpen(). + if ( dac.openStream( &oParams, NULL, FORMAT, fs, &bufferFrames, &saw, (void *)data, &options ) ) + goto cleanup; if ( dac.isStreamOpen() == false ) goto cleanup; // Stream is open ... now start it. - dac.startStream(); + if ( dac.startStream() ) goto cleanup; if ( checkCount ) { while ( dac.isStreamRunning() == true ) SLEEP( 100 ); |
