Browse Source

Various updates to configure script, rtaudio files, and test files in preparation for upcoming release (gps).

tags/4.0.5
Gary Scavone Stephen Sinclair 16 years ago
parent
commit
b96814b6bc
12 changed files with 339 additions and 189 deletions
  1. +2
    -4
      Makefile.in
  2. +216
    -86
      RtAudio.cpp
  3. +31
    -10
      RtAudio.h
  4. +0
    -0
      config/config.guess
  5. +0
    -0
      config/config.sub
  6. +0
    -0
      config/install.sh
  7. +55
    -64
      configure.ac
  8. +1
    -1
      doc/doxygen/tutorial.txt
  9. +1
    -1
      readme
  10. +8
    -5
      rtaudio-config.in
  11. +7
    -6
      tests/Makefile.in
  12. +18
    -12
      tests/testall.cpp

+ 2
- 4
Makefile.in View File

@@ -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)



+ 216
- 86
RtAudio.cpp View File

@@ -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, &param );
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, &param );
#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, &param );
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, &param );
#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<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7089,10 +7208,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
scale = 1.0 / 32768.0;
scale = 1.0 / 32767.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7101,10 +7221,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
scale = 1.0 / 8388608.0;
scale = 1.0 / 8388607.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]] & 0x00ffffff);
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7113,10 +7234,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
scale = 1.0 / 2147483648.0;
scale = 1.0 / 2147483647.5;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7151,10 +7273,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 = (Float32) ( 1.0 / 127.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7163,10 +7286,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT16) {
Int16 *in = (Int16 *)inBuffer;
scale = 1.0 / 32768.0;
scale = (Float32) ( 1.0 / 32767.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7175,10 +7299,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT24) {
Int32 *in = (Int32 *)inBuffer;
scale = 1.0 / 8388608.0;
scale = (Float32) ( 1.0 / 8388607.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]] & 0x00ffffff);
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7187,10 +7312,11 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
else if (info.inFormat == RTAUDIO_SINT32) {
Int32 *in = (Int32 *)inBuffer;
scale = 1.0 / 2147483648.0;
scale = (Float32) ( 1.0 / 2147483647.5 );
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
out[info.outOffset[j]] += 0.5;
out[info.outOffset[j]] *= scale;
}
in += info.inJump;
@@ -7269,7 +7395,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7279,7 +7405,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7336,7 +7462,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388608.0);
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7346,7 +7472,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.0);
out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7401,7 +7527,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7411,7 +7537,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.0);
out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7465,7 +7591,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float32 *in = (Float32 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7475,7 +7601,7 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
Float64 *in = (Float64 *)inBuffer;
for (unsigned int i=0; i<stream_.bufferSize; i++) {
for (j=0; j<info.channels; j++) {
out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.0);
out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
}
in += info.inJump;
out += info.outJump;
@@ -7484,6 +7610,10 @@ void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info
}
}

//static inline uint16_t bswap_16(uint16_t x) { return (x>>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;
}
}
}


+ 31
- 10
RtAudio.h View File

@@ -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 ); }



config.guess → config/config.guess View File


config.sub → config/config.sub View File


install.sh → config/install.sh View File


+ 55
- 64
configure.ac View File

@@ -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



+ 1
- 1
doc/doxygen/tutorial.txt View File

@@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio:

\section download Download

Latest Release (24 January 2008): <A href="http://music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.4.tar.gz">Version 4.0.4</A>
Latest Release (24 January 2008): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.4.tar.gz">Version 4.0.4</A>

\section documentation Documentation Links



+ 1
- 1
readme View File

@@ -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


+ 8
- 5
rtaudio-config.in View File

@@ -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

+ 7
- 6
tests/Makefile.in View File

@@ -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)

+ 18
- 12
tests/testall.cpp View File

@@ -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 <device> <channelOffset>\n";
std::cout << "\nuseage: testall N fs <iDevice> <oDevice> <iChannelOffset> <oChannelOffset>\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 );


Loading…
Cancel
Save