From b96814b6bc97b32a590521ae8f401c40dac4cc7c Mon Sep 17 00:00:00 2001 From: Gary Scavone Date: Sat, 22 Nov 2008 03:32:52 +0000 Subject: [PATCH] Various updates to configure script, rtaudio files, and test files in preparation for upcoming release (gps). --- Makefile.in | 6 +- RtAudio.cpp | 302 ++++++++++++++++++++-------- RtAudio.h | 41 +++- config.guess => config/config.guess | 0 config.sub => config/config.sub | 0 install.sh => config/install.sh | 0 configure.ac | 119 +++++------ doc/doxygen/tutorial.txt | 2 +- readme | 2 +- rtaudio-config.in | 13 +- tests/Makefile.in | 13 +- tests/testall.cpp | 30 +-- 12 files changed, 339 insertions(+), 189 deletions(-) rename config.guess => config/config.guess (100%) rename config.sub => config/config.sub (100%) rename install.sh => config/install.sh (100%) diff --git a/Makefile.in b/Makefile.in index 23a444f..3230002 100644 --- a/Makefile.in +++ b/Makefile.in @@ -11,10 +11,8 @@ CC = @CXX@ AR = @AR@ RANLIB = @RANLIB@ -DEFS = @debug@ -DEFS += @audio_apis@ -CFLAGS = @CFLAGS@ -Iinclude -CFLAGS += @warn@ +DEFS = @CPPFLAGS@ +CFLAGS = @CXXFLAGS@ -Iinclude all : $(LIBRARY) diff --git a/RtAudio.cpp b/RtAudio.cpp index 8d15a34..05e3afa 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -359,6 +359,13 @@ double RtApi :: getStreamTime( void ) #endif } +unsigned int RtApi :: getStreamSampleRate( void ) +{ + verifyStream(); + + return stream_.sampleRate; +} + // *************************************************** // // @@ -393,6 +400,7 @@ double RtApi :: getStreamTime( void ) // implementation. struct CoreHandle { AudioDeviceID id[2]; // device ids + AudioDeviceIOProcID procId[2]; UInt32 iStream[2]; // device stream index (first for mono mode) bool xrun[2]; char *deviceBuffer; @@ -1105,7 +1113,8 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne handle->id[mode] = id; // Allocate necessary internal buffers. - unsigned long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); + unsigned long bufferBytes; + bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory."; @@ -1172,7 +1181,12 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Only one callback procedure per device. stream_.mode = DUPLEX; else { +#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] ); +#else + // deprecated in favor of AudioDeviceCreateIOProcID() result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo ); +#endif if ( result != noErr ) { errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ")."; errorText_ = errorStream_.str(); @@ -1225,13 +1239,23 @@ void RtApiCore :: closeStream( void ) if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[0], callbackHandler ); +#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] ); +#else + // deprecated in favor of AudioDeviceDestroyIOProcID() AudioDeviceRemoveIOProc( handle->id[0], callbackHandler ); +#endif } if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) { if ( stream_.state == STREAM_RUNNING ) AudioDeviceStop( handle->id[1], callbackHandler ); +#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 ) + AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] ); +#else + // deprecated in favor of AudioDeviceDestroyIOProcID() AudioDeviceRemoveIOProc( handle->id[1], callbackHandler ); +#endif } for ( int i=0; i<2; i++ ) { @@ -1470,7 +1494,8 @@ bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, } } - AudioDeviceID inputDevice = handle->id[1]; + AudioDeviceID inputDevice; + inputDevice = handle->id[1]; if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) { if ( stream_.doConvertBuffer[1] ) { @@ -1610,7 +1635,9 @@ RtApiJack :: ~RtApiJack() unsigned int RtApiJack :: getDeviceCount( void ) { // See if we can become a jack client. - jack_client_t *client = jack_client_new( "RtApiJackCount" ); + jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption; + jack_status_t *status = NULL; + jack_client_t *client = jack_client_open( "RtApiJackCount", options, status ); if ( client == 0 ) return 0; const char **ports; @@ -1619,7 +1646,7 @@ unsigned int RtApiJack :: getDeviceCount( void ) ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). - unsigned int iColon = 0; + size_t iColon = 0; do { port = (char *) ports[ nChannels ]; iColon = port.find(":"); @@ -1643,7 +1670,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) RtAudio::DeviceInfo info; info.probed = false; - jack_client_t *client = jack_client_new( "RtApiJackInfo" ); + jack_options_t options = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption + jack_status_t *status = NULL; + jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status ); if ( client == 0 ) { errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!"; error( RtError::WARNING ); @@ -1656,7 +1685,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). - unsigned int iColon = 0; + size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); @@ -1771,10 +1800,12 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Look for jack server and try to become a client (only do once per stream). jack_client_t *client = 0; if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) { + jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer | JackUseExactName ); //JackNullOption; + jack_status_t *status = NULL; if ( options && !options->streamName.empty() ) - client = jack_client_new( options->streamName.c_str() ); + client = jack_client_open( options->streamName.c_str(), jackoptions, status ); else - client = jack_client_new( "RtApiJack" ); + client = jack_client_open( "RtApiJack", jackoptions, status ); if ( client == 0 ) { errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!"; error( RtError::WARNING ); @@ -1792,7 +1823,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne ports = jack_get_ports( client, NULL, NULL, 0 ); if ( ports ) { // Parse the port names up to the first colon (:). - unsigned int iColon = 0; + size_t iColon = 0; do { port = (char *) ports[ nPorts ]; iColon = port.find(":"); @@ -2625,11 +2656,28 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; else if ( granularity == -1 ) { // Make sure bufferSize is a power of two. - double power = std::log10( (double) *bufferSize ) / log10( 2.0 ); - *bufferSize = (int) pow( 2.0, floor(power+0.5) ); - if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; - else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; - else *bufferSize = preferSize; + int log2_of_min_size = 0; + int log2_of_max_size = 0; + + for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) { + if ( minSize & ((long)1 << i) ) log2_of_min_size = i; + if ( maxSize & ((long)1 << i) ) log2_of_max_size = i; + } + + long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) ); + int min_delta_num = log2_of_min_size; + + for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) { + long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) ); + if (current_delta < min_delta) { + min_delta = current_delta; + min_delta_num = i; + } + } + + *bufferSize = ( (unsigned int)1 << min_delta_num ); + if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize; + else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize; } else if ( granularity != 0 ) { // Set to an even multiple of granularity, rounding up. @@ -3235,7 +3283,7 @@ static const char* getAsioErrorString( ASIOError result ) static inline DWORD dsPointerDifference( DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize ) { - if (laterPointer > earlierPointer) + if ( laterPointer > earlierPointer ) return laterPointer - earlierPointer; else return laterPointer - earlierPointer + bufferSize; @@ -4828,6 +4876,7 @@ struct AlsaHandle { snd_pcm_t *handles[2]; bool synchronized; bool xrun[2]; + pthread_cond_t runnable; AlsaHandle() :synchronized(false) { xrun[0] = false; xrun[1] = false; } @@ -5414,19 +5463,10 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } // Set the buffer number, which in ALSA is referred to as the "period". - int dir; + int totalSize, dir; unsigned int periods = 0; if ( options ) periods = options->numberOfBuffers; - if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2; - // Even though the hardware might allow 1 buffer, it won't work reliably. - if ( periods < 2 ) periods = 2; - result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir ); - if ( result < 0 ) { - snd_pcm_close( phandle ); - errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << "."; - errorText_ = errorStream_.str(); - return FAILURE; - } + totalSize = *bufferSize * periods; // Set the buffer (or period) size. snd_pcm_uframes_t periodSize = *bufferSize; @@ -5439,6 +5479,18 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } *bufferSize = periodSize; + if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2; + else periods = totalSize / *bufferSize; + // Even though the hardware might allow 1 buffer, it won't work reliably. + if ( periods < 2 ) periods = 2; + result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir ); + if ( result < 0 ) { + snd_pcm_close( phandle ); + errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << "."; + errorText_ = errorStream_.str(); + return FAILURE; + } + // 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 ) { @@ -5468,9 +5520,19 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne snd_pcm_sw_params_alloca( &sw_params ); snd_pcm_sw_params_current( phandle, sw_params ); snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize ); - snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, 0x7fffffff ); + snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX ); snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 ); - snd_pcm_sw_params_set_silence_size( phandle, sw_params, INT_MAX ); + + // The following two settings were suggested by Theo Veenker + //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize ); + //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 ); + + // here are two options for a fix + //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX ); + snd_pcm_uframes_t val; + snd_pcm_sw_params_get_boundary( sw_params, &val ); + snd_pcm_sw_params_set_silence_size( phandle, sw_params, val ); + result = snd_pcm_sw_params( phandle, sw_params ); if ( result < 0 ) { snd_pcm_close( phandle ); @@ -5504,6 +5566,12 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory."; goto error; } + + if ( pthread_cond_init( &apiInfo->runnable, NULL ) ) { + errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable."; + goto error; + } + stream_.apiHandle = (void *) apiInfo; apiInfo->handles[0] = 0; apiInfo->handles[1] = 0; @@ -5572,13 +5640,28 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.callbackInfo.object = (void *) this; // Set the thread attributes for joinable and realtime scheduling - // priority. The higher priority will only take affect if the - // program is run as root or suid. + // priority (optional). The higher priority will only take affect + // if the program is run as root or suid. Note, under Linux + // processes with CAP_SYS_NICE privilege, a user can change + // scheduling policy and priority (thus need not be root). See + // POSIX "capabilities". pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) - pthread_attr_setschedpolicy( &attr, SCHED_RR ); + if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { + struct sched_param param; + int priority = options->priority; + int min = sched_get_priority_min( SCHED_RR ); + int max = sched_get_priority_max( SCHED_RR ); + if ( priority < min ) priority = min; + else if ( priority > max ) priority = max; + param.sched_priority = priority; + pthread_attr_setschedparam( &attr, ¶m ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + } + else + pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #endif @@ -5597,6 +5680,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne error: if ( apiInfo ) { + pthread_cond_destroy( &apiInfo->runnable ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; @@ -5626,10 +5710,14 @@ void RtApiAlsa :: closeStream() return; } + AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; + MUTEX_LOCK( &stream_.mutex ); + if ( stream_.state == STREAM_STOPPED ) + pthread_cond_signal( &apiInfo->runnable ); + MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); - AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; if ( stream_.state == STREAM_RUNNING ) { stream_.state = STREAM_STOPPED; if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) @@ -5639,6 +5727,7 @@ void RtApiAlsa :: closeStream() } if ( apiInfo ) { + pthread_cond_destroy( &apiInfo->runnable ); if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] ); if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] ); delete apiInfo; @@ -5707,6 +5796,8 @@ void RtApiAlsa :: startStream() unlock: MUTEX_UNLOCK( &stream_.mutex ); + pthread_cond_signal( &apiInfo->runnable ); + if ( result >= 0 ) return; error( RtError::SYSTEM_ERROR ); } @@ -5720,8 +5811,7 @@ void RtApiAlsa :: stopStream() return; } - // Change the state before the lock to improve shutdown response - // when using a callback. + // Change the state before the lock to improve shutdown response. stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); @@ -5765,8 +5855,7 @@ void RtApiAlsa :: abortStream() return; } - // Change the state before the lock to improve shutdown response - // when using a callback. + // Change the state before the lock to improve shutdown response. stream_.state = STREAM_STOPPED; MUTEX_LOCK( &stream_.mutex ); @@ -5794,16 +5883,21 @@ void RtApiAlsa :: abortStream() unlock: MUTEX_UNLOCK( &stream_.mutex ); - stream_.state = STREAM_STOPPED; if ( result >= 0 ) return; error( RtError::SYSTEM_ERROR ); } void RtApiAlsa :: callbackEvent() { + AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { - if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds - return; + MUTEX_LOCK( &stream_.mutex ); + pthread_cond_wait( &apiInfo->runnable, &stream_.mutex ); + if ( stream_.state != STREAM_RUNNING ) { + MUTEX_UNLOCK( &stream_.mutex ); + return; + } + MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { @@ -5813,7 +5907,6 @@ void RtApiAlsa :: callbackEvent() } int doStopStream = 0; - AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle; RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; @@ -5828,6 +5921,11 @@ void RtApiAlsa :: callbackEvent() doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); + if ( doStopStream == 2 ) { + abortStream(); + return; + } + MUTEX_LOCK( &stream_.mutex ); // The state might change while waiting on a mutex. @@ -5867,7 +5965,7 @@ void RtApiAlsa :: callbackEvent() } if ( result < (int) stream_.bufferSize ) { - // Either an error or underrun occured. + // Either an error or overrun occured. if ( result == -EPIPE ) { snd_pcm_state_t state = snd_pcm_state( handle[1] ); if ( state == SND_PCM_STATE_XRUN ) { @@ -5888,7 +5986,7 @@ void RtApiAlsa :: callbackEvent() errorText_ = errorStream_.str(); } error( RtError::WARNING ); - goto unlock; + goto tryOutput; } // Do byte swapping if necessary. @@ -5904,6 +6002,8 @@ void RtApiAlsa :: callbackEvent() if ( result == 0 && frames > 0 ) stream_.latency[1] = frames; } + tryOutput: + if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) { // Setup parameters and do buffer conversion if necessary. @@ -5969,7 +6069,6 @@ void RtApiAlsa :: callbackEvent() RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); - else if ( doStopStream == 2 ) this->abortStream(); } extern "C" void *alsaCallbackHandler( void *ptr ) @@ -5978,15 +6077,6 @@ extern "C" void *alsaCallbackHandler( void *ptr ) RtApiAlsa *object = (RtApiAlsa *) info->object; bool *isRunning = &info->isRunning; -#ifdef SCHED_RR - // Set a higher scheduler priority (P.J. Leonard) - struct sched_param param; - int min = sched_get_priority_min( SCHED_RR ); - int max = sched_get_priority_max( SCHED_RR ); - param.sched_priority = min + ( max - min ) / 2; // Is this the best number? - sched_setscheduler( 0, SCHED_RR, ¶m ); -#endif - while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); @@ -6017,6 +6107,7 @@ struct OssHandle { int id[2]; // device ids bool xrun[2]; bool triggered; + pthread_cond_t runnable; OssHandle() :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; } @@ -6474,6 +6565,11 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned goto error; } + if ( pthread_cond_init( &handle->runnable, NULL ) ) { + errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable."; + goto error; + } + stream_.apiHandle = (void *) handle; } else { @@ -6537,7 +6633,19 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); #ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread) - pthread_attr_setschedpolicy( &attr, SCHED_RR ); + if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) { + struct sched_param param; + int priority = options->priority; + int min = sched_get_priority_min( SCHED_RR ); + int max = sched_get_priority_max( SCHED_RR ); + if ( priority < min ) priority = min; + else if ( priority > max ) priority = max; + param.sched_priority = priority; + pthread_attr_setschedparam( &attr, ¶m ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + } + else + pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #else pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); #endif @@ -6556,6 +6664,7 @@ bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned error: if ( handle ) { + pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; @@ -6585,10 +6694,14 @@ void RtApiOss :: closeStream() return; } + OssHandle *handle = (OssHandle *) stream_.apiHandle; stream_.callbackInfo.isRunning = false; + MUTEX_LOCK( &stream_.mutex ); + if ( stream_.state == STREAM_STOPPED ) + pthread_cond_signal( &handle->runnable ); + MUTEX_UNLOCK( &stream_.mutex ); pthread_join( stream_.callbackInfo.thread, NULL ); - OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.state == STREAM_RUNNING ) { if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 ); @@ -6598,6 +6711,7 @@ void RtApiOss :: closeStream() } if ( handle ) { + pthread_cond_destroy( &handle->runnable ); if ( handle->id[0] ) close( handle->id[0] ); if ( handle->id[1] ) close( handle->id[1] ); delete handle; @@ -6637,6 +6751,9 @@ void RtApiOss :: startStream() // when fed samples. MUTEX_UNLOCK( &stream_.mutex ); + + OssHandle *handle = (OssHandle *) stream_.apiHandle; + pthread_cond_signal( &handle->runnable ); } void RtApiOss :: stopStream() @@ -6753,9 +6870,15 @@ void RtApiOss :: abortStream() void RtApiOss :: callbackEvent() { + OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.state == STREAM_STOPPED ) { - if ( stream_.callbackInfo.isRunning ) usleep( 50000 ); // sleep 50 milliseconds - return; + MUTEX_LOCK( &stream_.mutex ); + pthread_cond_wait( &handle->runnable, &stream_.mutex ); + if ( stream_.state != STREAM_RUNNING ) { + MUTEX_UNLOCK( &stream_.mutex ); + return; + } + MUTEX_UNLOCK( &stream_.mutex ); } if ( stream_.state == STREAM_CLOSED ) { @@ -6769,7 +6892,6 @@ void RtApiOss :: callbackEvent() RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; double streamTime = getStreamTime(); RtAudioStreamStatus status = 0; - OssHandle *handle = (OssHandle *) stream_.apiHandle; if ( stream_.mode != INPUT && handle->xrun[0] == true ) { status |= RTAUDIO_OUTPUT_UNDERFLOW; handle->xrun[0] = false; @@ -6780,6 +6902,10 @@ void RtApiOss :: callbackEvent() } doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1], stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData ); + if ( doStopStream == 2 ) { + this->abortStream(); + return; + } MUTEX_LOCK( &stream_.mutex ); @@ -6828,7 +6954,7 @@ void RtApiOss :: callbackEvent() handle->xrun[0] = true; errorText_ = "RtApiOss::callbackEvent: audio write error."; error( RtError::WARNING ); - goto unlock; + // Continue on to input section. } } @@ -6872,7 +6998,6 @@ void RtApiOss :: callbackEvent() RtApi::tickStreamTime(); if ( doStopStream == 1 ) this->stopStream(); - else if ( doStopStream == 2 ) this->abortStream(); } extern "C" void *ossCallbackHandler( void *ptr ) @@ -6881,13 +7006,6 @@ extern "C" void *ossCallbackHandler( void *ptr ) RtApiOss *object = (RtApiOss *) info->object; bool *isRunning = &info->isRunning; -#ifdef SCHED_RR - // Set a higher scheduler priority (P.J. Leonard) - struct sched_param param; - param.sched_priority = 39; // Is this the best number? - sched_setscheduler( 0, SCHED_RR, ¶m ); -#endif - while ( *isRunning == true ) { pthread_testcancel(); object->callbackEvent(); @@ -7077,10 +7195,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info if (info.inFormat == RTAUDIO_SINT8) { signed char *in = (signed char *)inBuffer; - scale = 1.0 / 128.0; + scale = 1.0 / 127.5; for (unsigned int i=0; i>8) | (x<<8); } +//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); } +//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); } + void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format ) { register char val; @@ -7516,8 +7646,8 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat *(ptr) = *(ptr+1); *(ptr+1) = val; - // Increment 4 bytes. - ptr += 4; + // Increment 3 more bytes. + ptr += 3; } } else if ( format == RTAUDIO_FLOAT64 ) { @@ -7545,8 +7675,8 @@ void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat *(ptr) = *(ptr+1); *(ptr+1) = val; - // Increment 8 bytes. - ptr += 8; + // Increment 5 more bytes. + ptr += 5; } } } diff --git a/RtAudio.h b/RtAudio.h index 8696262..370ba26 100644 --- a/RtAudio.h +++ b/RtAudio.h @@ -108,11 +108,15 @@ static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/mi If the RTAUDIO_HOG_DEVICE flag is set, RtAudio will attempt to open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. + + If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt + to select realtime scheduling (round-robin) for the callback thread. */ typedef unsigned int RtAudioStreamFlags; static const RtAudioStreamFlags RTAUDIO_NONINTERLEAVED = 0x1; // Use non-interleaved buffers (default = interleaved). static const RtAudioStreamFlags RTAUDIO_MINIMIZE_LATENCY = 0x2; // Attempt to set stream parameters for lowest possible latency. static const RtAudioStreamFlags RTAUDIO_HOG_DEVICE = 0x4; // Attempt grab device and prevent use by others. +static const RtAudioStreamFlags RTAUDIO_SCHEDULE_REALTIME = 0x8; // Try to select realtime scheduling for callback thread. /*! \typedef typedef unsigned long RtAudioStreamStatus; \brief RtAudio stream status (over- or underflow) flags. @@ -240,9 +244,10 @@ class RtAudio The following flags can be OR'ed together to allow a client to make changes to the default stream behavior: - - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). - - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. - - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. + - \e RTAUDIO_NONINTERLEAVED: Use non-interleaved buffers (default = interleaved). + - \e RTAUDIO_MINIMIZE_LATENCY: Attempt to set stream parameters for lowest possible latency. + - \e RTAUDIO_HOG_DEVICE: Attempt grab device for exclusive use. + - \e RTAUDIO_SCHEDULE_REALTIME: Attempt to select realtime scheduling for callback thread. By default, RtAudio streams pass and receive audio data from the client in an interleaved format. By passing the @@ -268,6 +273,11 @@ class RtAudio open the input and/or output stream device(s) for exclusive use. Note that this is not possible with all supported audio APIs. + If the RTAUDIO_SCHEDULE_REALTIME flag is set, RtAudio will attempt + to select realtime scheduling (round-robin) for the callback thread. + The \c priority parameter will only be used if the RTAUDIO_SCHEDULE_REALTIME + flag is set. It defines the thread's realtime priority. + The \c numberOfBuffers parameter can be used to control stream latency in the Windows DirectSound, Linux OSS, and Linux Alsa APIs only. A value of two is usually the smallest allowed. Larger @@ -285,10 +295,11 @@ class RtAudio RtAudioStreamFlags flags; /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). */ unsigned int numberOfBuffers; /*!< Number of stream buffers. */ std::string streamName; /*!< A stream name (currently used only in Jack). */ + int priority; /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */ // Default constructor. StreamOptions() - : flags(0), numberOfBuffers(0) {} + : flags(0), numberOfBuffers(0), priority(0) {} }; //! A static function to determine the available compiled audio APIs. @@ -440,10 +451,10 @@ class RtAudio void abortStream( void ); //! Returns true if a stream is open and false if not. - bool isStreamOpen( void ) throw(); + bool isStreamOpen( void ) const throw(); //! Returns true if the stream is running and false if it is stopped or not open. - bool isStreamRunning( void ) throw(); + bool isStreamRunning( void ) const throw(); //! Returns the number of elapsed seconds since the stream was started. /*! @@ -462,6 +473,14 @@ class 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 RtError (type = INVALID_USE) will be thrown. + */ + unsigned int getStreamSampleRate( void ); + //! Specify whether warning messages should be printed to stderr. void showWarnings( bool value = true ) throw(); @@ -551,9 +570,10 @@ public: virtual void stopStream( void ) = 0; virtual void abortStream( void ) = 0; long getStreamLatency( void ); + unsigned int getStreamSampleRate( void ); virtual double getStreamTime( void ); - bool isStreamOpen( void ) { return stream_.state != STREAM_CLOSED; }; - bool isStreamRunning( void ) { return stream_.state == STREAM_RUNNING; }; + bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }; + bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }; void showWarnings( bool value ) { showWarnings_ = value; }; @@ -688,9 +708,10 @@ inline void RtAudio :: closeStream( void ) throw() { 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 bool RtAudio :: isStreamOpen( void ) throw() { return rtapi_->isStreamOpen(); } -inline bool RtAudio :: isStreamRunning( void ) throw() { return rtapi_->isStreamRunning(); } +inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); } +inline bool RtAudio :: isStreamRunning( void ) const throw() { 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 :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); } diff --git a/config.guess b/config/config.guess similarity index 100% rename from config.guess rename to config/config.guess diff --git a/config.sub b/config/config.sub similarity index 100% rename from config.sub rename to config/config.sub diff --git a/install.sh b/config/install.sh similarity index 100% rename from install.sh rename to config/install.sh diff --git a/configure.ac b/configure.ac index 027dae0..97989d2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,6 @@ # Process this file with autoconf to produce a configure script. AC_INIT(RtAudio, 4.0, gary@music.mcgill.ca, rtaudio) +AC_CONFIG_AUX_DIR(config) AC_CONFIG_SRCDIR(RtAudio.cpp) AC_CONFIG_FILES([rtaudio-config Makefile tests/Makefile]) @@ -7,8 +8,7 @@ AC_CONFIG_FILES([rtaudio-config Makefile tests/Makefile]) AC_SUBST( GXX, ["no"] ) # Checks for programs. -AC_PROG_CC -AC_PROG_CXX(g++ CC c++ cxx) +AC_PROG_CXX AC_PROG_RANLIB AC_PATH_PROG(AR, ar, no) if [[ $AR = "no" ]] ; then @@ -19,66 +19,65 @@ fi AC_HEADER_STDC AC_CHECK_HEADERS(sys/ioctl.h unistd.h) -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST - # Check for debug AC_MSG_CHECKING(whether to compile debug version) AC_ARG_ENABLE(debug, [ --enable-debug = enable various debug output], - [AC_SUBST( debug, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cflags, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)], - [AC_SUBST( debug, [] ) AC_SUBST( cflags, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)]) + [AC_SUBST( cppflag, [-D__RTAUDIO_DEBUG__] ) AC_SUBST( cxxflag, [-g] ) AC_SUBST( object_path, [Debug] ) AC_MSG_RESULT(yes)], + [AC_SUBST( cppflag, [] ) AC_SUBST( cxxflag, [-O2] ) AC_SUBST( object_path, [Release] ) AC_MSG_RESULT(no)]) + # Checks for functions -AC_CHECK_FUNC(gettimeofday, [CFLAGS=$CFLAGS" -DHAVE_GETTIMEOFDAY"], ) +AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], ) + +# For -I and -D flags +CPPFLAGS="$CPPFLAGS $cppflag" + +# For debugging and optimization ... overwrite default because it has both -g and -O2 +#CXXFLAGS="$CXXFLAGS $cxxflag" +CXXFLAGS="$cxxflag" # Check compiler and use -Wall if gnu. if [test $GXX = "yes" ;] then - AC_SUBST( warn, [-Wall] ) + AC_SUBST( cxxflag, [-Wall] ) fi -CFLAGS="$CFLAGS $cflags" +CXXFLAGS="$CXXFLAGS $cxxflag" # Checks for package options and external software +AC_SUBST( api, [""] ) AC_CANONICAL_HOST AC_MSG_CHECKING(for audio API) case $host in *-*-netbsd*) - AC_SUBST( sound_api, [-D__LINUX_OSS__] ) AC_MSG_RESULT(using OSS) - AC_SUBST( audio_apis, [-D__LINUX_OSS__] ) - CFLAGS=$CFLAGS" -lossaudio" + api="$api -D__LINUX_OSS__" + LIBS="$LIBS -lossaudio" AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!)) ;; *-*-linux*) - AC_SUBST( sound_api, [_NO_API_] ) - AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)], [AC_SUBST( sound_api, [-D__UNIX_JACK__] ) AC_MSG_RESULT(using JACK)], ) - if [test $sound_api = -D__UNIX_JACK__;] then - TEMP_LIBS=$LIBS - AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!)) - AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!)) - LIBS="`pkg-config --CFLAGS --libs jack` $TEMP_LIBS -lasound" - audio_apis="-D__UNIX_JACK__" - fi + AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)], [ + api="$api -D__UNIX_JACK__" + AC_MSG_RESULT(using JACK) + AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!)) + AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(Jack support also requires the asound library!))], ) # Look for ALSA flag - AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_ALSA__] ) AC_MSG_RESULT(using ALSA)], ) - if [test $sound_api = -D__LINUX_ALSA__;] then - AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!)) - audio_apis="-D__LINUX_ALSA__ $audio_apis" - fi + AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)], [ + api="$api -D__LINUX_ALSA__" + AC_MSG_RESULT(using ALSA) + AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))], ) # Look for OSS flag - AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [AC_SUBST( sound_api, [-D__LINUX_OSS__] ) AC_MSG_RESULT(using OSS)], ) - if test $sound_api = -D__LINUX_OSS__; then - audio_apis="-D__LINUX_OSS__ $audio_apis" - fi + AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (linux only)], [ + api="$api -D__LINUX_OSS__" + AC_MSG_RESULT(using OSS)], ) # If no audio api flags specified, use ALSA - if [test $sound_api = _NO_API_;] then + if [test "$api" == "";] then AC_MSG_RESULT(using ALSA) - AC_SUBST( audio_apis, [-D__LINUX_ALSA__] ) + AC_SUBST( api, [-D__LINUX_ALSA__] ) AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!)) fi @@ -86,54 +85,47 @@ case $host in ;; *-apple*) - AC_SUBST( sound_api, [_NO_API_] ) - AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (unix only)], [AC_SUBST( sound_api, [-D__UNIX_JACK__] ) AC_MSG_RESULT(using JACK)], ) - if [test $sound_api = -D__UNIX_JACK__;] then - AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!)) - audio_apis="-D__UNIX_JACK__" - fi + AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (unix only)], [ + api="$api -D__UNIX_JACK__" + AC_MSG_RESULT(using JACK) + AC_CHECK_LIB(jack, jack_client_new, , AC_MSG_ERROR(JACK support requires the jack library!))], ) # Look for Core flag - AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [AC_SUBST( sound_api, [-D__MACOSX_CORE__] ) AC_MSG_RESULT(using CoreAudio)], ) - if test $sound_api = -D__MACOSX_CORE__; then + AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [ + api="$api -D__MACOSX_CORE__" + AC_MSG_RESULT(using CoreAudio) AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] ) - AC_SUBST( frameworks, ["-framework CoreAudio -framework CoreFoundation"] ) - audio_apis="-D__MACOSX_CORE__ $audio_apis" - fi + LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ], ) # If no audio api flags specified, use CoreAudio - if [test $sound_api = _NO_API_;] then - AC_SUBST( sound_api, [-D__MACOSX_CORE__] ) + if [test "$api" == ""; ] then + AC_SUBST( api, [-D__MACOSX_CORE__] ) AC_MSG_RESULT(using CoreAudio) AC_CHECK_HEADER(CoreAudio/CoreAudio.h, - [AC_SUBST( audio_apis, [-D__MACOSX_CORE__] )], + [], [AC_MSG_ERROR(CoreAudio header files not found!)] ) - AC_SUBST( frameworks, ["-framework CoreAudio -framework CoreFoundation"] ) + AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] ) fi AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!)) ;; *-mingw32*) - AC_SUBST( sound_api, [_NO_API_] ) - AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)], [AC_SUBST( sound_api, [-D__WINDOWS_ASIO__] ) AC_MSG_RESULT(using ASIO)], ) - if [test $sound_api = -D__WINDOWS_ASIO__;] then - audio_apis="-D__WINDOWS_ASIO__" - AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) - fi + AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)], [ + api="$api -D__WINDOWS_ASIO__" + AC_MSG_RESULT(using ASIO) + AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ], ) # Look for DirectSound flag - AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)], [AC_SUBST( sound_api, [-D__WINDOWS_DS__] ) AC_MSG_RESULT(using DirectSound)], ) - if test $sound_api = -D__WINDOWS_DS__; then - audio_apis="-D__WINDOWS_DS__ $audio_apis" - LIBS="-ldsound -lwinmm $LIBS" - fi + AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)], [ + api="$api -D__WINDOWS_DS__" + AC_MSG_RESULT(using DirectSound) + LIBS="-ldsound -lwinmm $LIBS" ], ) # If no audio api flags specified, use DirectSound - if [test $sound_api = _NO_API_;] then - AC_SUBST( sound_api, [-D__WINDOWS_DS__] ) + if [test "$api" == "";] then + AC_SUBST( api, [-D__WINDOWS_DS__] ) AC_MSG_RESULT(using DirectSound) - audio_apis="-D__WINDOWS_DS__" LIBS="-ldsound -lwinmm $LIBS" fi @@ -146,8 +138,7 @@ case $host in ;; esac -# Checks for library functions. -AC_PROG_GCC_TRADITIONAL +CPPFLAGS="$CPPFLAGS $api" AC_OUTPUT diff --git a/doc/doxygen/tutorial.txt b/doc/doxygen/tutorial.txt index 906afe3..c8fd9cf 100644 --- a/doc/doxygen/tutorial.txt +++ b/doc/doxygen/tutorial.txt @@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio: \section download Download -Latest Release (24 January 2008): Version 4.0.4 +Latest Release (24 January 2008): Version 4.0.4 \section documentation Documentation Links diff --git a/readme b/readme index 8228cd3..7c2c7b9 100644 --- a/readme +++ b/readme @@ -11,7 +11,7 @@ tests/Windows: Visual C++ .net test program workspace and projects OVERVIEW: -RtAudio is a set of C++ classes that provide a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives: +RtAudio is a set of C++ classes that provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, and OSS), Macintosh OS X, SGI, and Windows (DirectSound and ASIO) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives: - object-oriented C++ design - simple, common API across all supported platforms diff --git a/rtaudio-config.in b/rtaudio-config.in index c689a98..2422b60 100644 --- a/rtaudio-config.in +++ b/rtaudio-config.in @@ -1,16 +1,19 @@ #! /bin/sh if (test "x$#" != "x1") ; then - echo "Usage: $0 [--libs | --cxxflags]" + echo "Usage: $0 [--libs | --cxxflags | --cppflags]" exit; fi -LIBRARY="@LIBS@ @frameworks@" -CFLAGS="@audio_apis@" +LIBRARY="@LIBS@" +CXXFLAGS="@CXXFLAGS@" +CPPFLAGS="@CPPFLAGS@" if (test "x$1" == "x--libs") ; then echo "$LIBRARY" -elif (test "x$1" == "x--CFLAGS") ; then - echo "$CFLAGS" +elif (test "x$1" == "x--cxxflags") ; then + echo "$CXXFLAGS" +elif (test "x$1" == "x--cppflags") ; then + echo "$CPPFLAGS" else echo "Unknown option: $1" fi diff --git a/tests/Makefile.in b/tests/Makefile.in index 059b5ce..4e93823 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -11,12 +11,10 @@ vpath %.o $(OBJECT_PATH) OBJECTS = RtAudio.o @objects@ CC = @CXX@ -DEFS = @debug@ -DEFS += @audio_apis@ -CFLAGS = @CFLAGS@ -CFLAGS += @warn@ -I$(INCLUDE) -I../include +DEFS = @CPPFLAGS@ +CFLAGS = @CXXFLAGS@ +CFLAGS += -I$(INCLUDE) -I../include LIBRARY = @LIBS@ -LIBRARY += @frameworks@ %.o : $(SRC_PATH)/%.cpp $(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@ @@ -44,11 +42,14 @@ duplex : duplex.cpp $(OBJECTS) testall : testall.cpp $(OBJECTS) $(CC) $(CFLAGS) $(DEFS) -o testall testall.cpp $(OBJECT_PATH)/*.o $(LIBRARY) - clean : -rm $(OBJECT_PATH)/*.o -rm $(PROGRAMS) -rm -f *.raw *~ *.exe + -rm -fR *.dSYM + +distclean: clean + -rm Makefile strip : strip $(PROGRAMS) diff --git a/tests/testall.cpp b/tests/testall.cpp index 2eeb330..1f3ea26 100644 --- a/tests/testall.cpp +++ b/tests/testall.cpp @@ -1,7 +1,7 @@ /******************************************/ /* testall.cpp - by Gary P. Scavone, 2007 + by Gary P. Scavone, 2007-2008 This program will make a variety of calls to extensively test RtAudio functionality. @@ -17,11 +17,13 @@ void usage( void ) { // Error function in case of incorrect command-line // argument specifications - std::cout << "\nuseage: testall N fs \n"; + std::cout << "\nuseage: testall N fs \n"; std::cout << " where N = number of channels,\n"; std::cout << " fs = the sample rate,\n"; - std::cout << " device = optional device to use (default = 0),\n"; - std::cout << " and channelOffset = an optional channel offset on the device (default = 0).\n\n"; + std::cout << " iDevice = optional input device to use (default = 0),\n"; + std::cout << " oDevice = optional output device to use (default = 0),\n"; + std::cout << " iChannelOffset = an optional input channel offset (default = 0),\n"; + std::cout << " and oChannelOffset = optional output channel offset (default = 0).\n\n"; exit( 0 ); } @@ -89,11 +91,11 @@ int inout( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, int main( int argc, char *argv[] ) { - unsigned int bufferFrames, fs, device = 0, offset = 0; + unsigned int bufferFrames, fs, oDevice = 0, iDevice = 0, iOffset = 0, oOffset = 0; char input; // minimal command-line checking - if (argc < 3 || argc > 5 ) usage(); + if (argc < 3 || argc > 7 ) usage(); RtAudio dac; if ( dac.getDeviceCount() < 1 ) { @@ -104,9 +106,13 @@ int main( int argc, char *argv[] ) channels = (unsigned int) atoi( argv[1] ); fs = (unsigned int) atoi( argv[2] ); if ( argc > 3 ) - device = (unsigned int) atoi( argv[3] ); + iDevice = (unsigned int) atoi( argv[3] ); if ( argc > 4 ) - offset = (unsigned int) atoi( argv[4] ); + oDevice = (unsigned int) atoi(argv[4]); + if ( argc > 5 ) + iOffset = (unsigned int) atoi(argv[5]); + if ( argc > 6 ) + oOffset = (unsigned int) atoi(argv[6]); double *data = (double *) calloc( channels, sizeof( double ) ); @@ -116,9 +122,9 @@ int main( int argc, char *argv[] ) // Set our stream parameters for output only. bufferFrames = 256; RtAudio::StreamParameters oParams, iParams; - oParams.deviceId = device; + oParams.deviceId = oDevice; oParams.nChannels = channels; - oParams.firstChannel = offset; + oParams.firstChannel = oOffset; RtAudio::StreamOptions options; options.flags = RTAUDIO_HOG_DEVICE; @@ -181,9 +187,9 @@ int main( int argc, char *argv[] ) // Now open a duplex stream. unsigned int bufferBytes; - iParams.deviceId = device; + iParams.deviceId = iDevice; iParams.nChannels = channels; - iParams.firstChannel = offset; + iParams.firstChannel = iOffset; options.flags = RTAUDIO_NONINTERLEAVED; try { dac.openStream( &oParams, &iParams, RTAUDIO_SINT32, fs, &bufferFrames, &inout, (void *)&bufferBytes, &options );