Browse Source

Various updates for pulse audio, preparation for release 4.0.12, error callback addition (GS).

tags/4.0.12
Gary Scavone Stephen Sinclair 12 years ago
parent
commit
906e5ba67f
7 changed files with 212 additions and 108 deletions
  1. +1
    -1
      Makefile.in
  2. +160
    -73
      RtAudio.cpp
  3. +40
    -31
      RtAudio.h
  4. +1
    -1
      doc/doxygen/compiling.txt
  5. +1
    -1
      doc/doxygen/tutorial.txt
  6. +8
    -0
      doc/release.txt
  7. +1
    -1
      librtaudio.pc.in

+ 1
- 1
Makefile.in View File

@@ -8,7 +8,7 @@ OBJECTS = RtAudio.o @objects@


STATIC = librtaudio.a STATIC = librtaudio.a
SHARED = @sharedlib@ SHARED = @sharedlib@
RELEASE = 4.0.11
RELEASE = 4.0.12
MAJOR = 4 MAJOR = 4
LIBRARIES = $(STATIC) $(SHARED) LIBRARIES = $(STATIC) $(SHARED)




+ 160
- 73
RtAudio.cpp View File

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


+ 40
- 31
RtAudio.h View File

@@ -42,7 +42,7 @@
\file RtAudio.h \file RtAudio.h
*/ */


// RtAudio: Version 4.0.11
// RtAudio: Version 4.0.12


#ifndef __RTAUDIO_H #ifndef __RTAUDIO_H
#define __RTAUDIO_H #define __RTAUDIO_H
@@ -59,12 +59,10 @@
internal routines will automatically take care of any necessary internal routines will automatically take care of any necessary
byte-swapping between the host format and the soundcard. Thus, byte-swapping between the host format and the soundcard. Thus,
endian-ness is not a concern in the following format definitions. endian-ness is not a concern in the following format definitions.
Note that 24-bit data is expected to be encapsulated in a 32-bit
format.


- \e RTAUDIO_SINT8: 8-bit signed integer. - \e RTAUDIO_SINT8: 8-bit signed integer.
- \e RTAUDIO_SINT16: 16-bit signed integer. - \e RTAUDIO_SINT16: 16-bit signed integer.
- \e RTAUDIO_SINT24: Lower 3 bytes of 32-bit signed integer.
- \e RTAUDIO_SINT24: 24-bit signed integer.
- \e RTAUDIO_SINT32: 32-bit signed integer. - \e RTAUDIO_SINT32: 32-bit signed integer.
- \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0. - \e RTAUDIO_FLOAT32: Normalized between plus/minus 1.0.
- \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0. - \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
@@ -72,7 +70,7 @@
typedef unsigned long RtAudioFormat; typedef unsigned long RtAudioFormat;
static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer. static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer. static const RtAudioFormat RTAUDIO_SINT16 = 0x2; // 16-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // Lower 3 bytes of 32-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT24 = 0x4; // 24-bit signed integer.
static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer. static const RtAudioFormat RTAUDIO_SINT32 = 0x8; // 32-bit signed integer.
static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0. static const RtAudioFormat RTAUDIO_FLOAT32 = 0x10; // Normalized between plus/minus 1.0.
static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0. static const RtAudioFormat RTAUDIO_FLOAT64 = 0x20; // Normalized between plus/minus 1.0.
@@ -186,6 +184,12 @@ typedef int (*RtAudioCallback)( void *outputBuffer, void *inputBuffer,
RtAudioStreamStatus status, RtAudioStreamStatus status,
void *userData ); void *userData );


//! RtAudio error callback function prototype.
/*!
\param type Type of error.
\param errorText Error description.
*/
typedef void (*RtAudioErrorCallback)( RtError::Type type, const std::string &errorText );


// **************************************************************** // // **************************************************************** //
// //
@@ -423,12 +427,14 @@ class RtAudio
chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the chosen. If the RTAUDIO_MINIMIZE_LATENCY flag bit is set, the
lowest allowable value is used. The actual value used is lowest allowable value is used. The actual value used is
returned via the structure argument. The parameter is API dependent. returned via the structure argument. The parameter is API dependent.
\param errorCallback A client-defined function that will be invoked
when an error has occured.
*/ */
void openStream( RtAudio::StreamParameters *outputParameters, void openStream( RtAudio::StreamParameters *outputParameters,
RtAudio::StreamParameters *inputParameters, RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback, unsigned int *bufferFrames, RtAudioCallback callback,
void *userData = NULL, RtAudio::StreamOptions *options = NULL );
void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL );


//! A function that closes a stream and frees any associated stream memory. //! A function that closes a stream and frees any associated stream memory.
/*! /*!
@@ -535,6 +541,7 @@ struct CallbackInfo {
ThreadHandle thread; ThreadHandle thread;
void *callback; void *callback;
void *userData; void *userData;
void *errorCallback;
void *apiInfo; // void pointer for API specific callback information void *apiInfo; // void pointer for API specific callback information
bool isRunning; bool isRunning;
bool doRealtime; bool doRealtime;
@@ -542,7 +549,7 @@ struct CallbackInfo {


// Default constructor. // Default constructor.
CallbackInfo() CallbackInfo()
:object(0), callback(0), userData(0), apiInfo(0), isRunning(false), doRealtime(false) {}
:object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false) {}
}; };


// **************************************************************** // // **************************************************************** //
@@ -610,7 +617,8 @@ public:
RtAudio::StreamParameters *inputParameters, RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback, unsigned int *bufferFrames, RtAudioCallback callback,
void *userData, RtAudio::StreamOptions *options );
void *userData, RtAudio::StreamOptions *options,
RtAudioErrorCallback errorCallback );
virtual void closeStream( void ); virtual void closeStream( void );
virtual void startStream( void ) = 0; virtual void startStream( void ) = 0;
virtual void stopStream( void ) = 0; virtual void stopStream( void ) = 0;
@@ -618,9 +626,9 @@ public:
long getStreamLatency( void ); long getStreamLatency( void );
unsigned int getStreamSampleRate( void ); unsigned int getStreamSampleRate( void );
virtual double getStreamTime( void ); virtual double getStreamTime( void );
bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; };
bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; };
void showWarnings( bool value ) { showWarnings_ = value; };
bool isStreamOpen( void ) const { return stream_.state != STREAM_CLOSED; }
bool isStreamRunning( void ) const { return stream_.state == STREAM_RUNNING; }
void showWarnings( bool value ) { showWarnings_ = value; }




protected: protected:
@@ -759,7 +767,7 @@ inline void RtAudio :: abortStream( void ) { return rtapi_->abortStream(); }
inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); } inline bool RtAudio :: isStreamOpen( void ) const throw() { return rtapi_->isStreamOpen(); }
inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); } inline bool RtAudio :: isStreamRunning( void ) const throw() { return rtapi_->isStreamRunning(); }
inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); } inline long RtAudio :: getStreamLatency( void ) { return rtapi_->getStreamLatency(); }
inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); };
inline unsigned int RtAudio :: getStreamSampleRate( void ) { return rtapi_->getStreamSampleRate(); }
inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); } inline double RtAudio :: getStreamTime( void ) { return rtapi_->getStreamTime(); }
inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); } inline void RtAudio :: showWarnings( bool value ) throw() { rtapi_->showWarnings( value ); }


@@ -775,7 +783,7 @@ public:


RtApiCore(); RtApiCore();
~RtApiCore(); ~RtApiCore();
RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; };
RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultOutputDevice( void );
@@ -813,7 +821,7 @@ public:


RtApiJack(); RtApiJack();
~RtApiJack(); ~RtApiJack();
RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; };
RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void ); void closeStream( void );
@@ -846,7 +854,7 @@ public:


RtApiAsio(); RtApiAsio();
~RtApiAsio(); ~RtApiAsio();
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; };
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void ); void closeStream( void );
@@ -882,7 +890,7 @@ public:


RtApiDs(); RtApiDs();
~RtApiDs(); ~RtApiDs();
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; };
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultOutputDevice( void );
unsigned int getDefaultInputDevice( void ); unsigned int getDefaultInputDevice( void );
@@ -904,6 +912,7 @@ public:
bool coInitialized_; bool coInitialized_;
bool buffersRolling; bool buffersRolling;
long duplexPrerollBytes; long duplexPrerollBytes;
std::vector<struct DsDevice> dsDevices;
bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate, unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize, RtAudioFormat format, unsigned int *bufferSize,
@@ -920,7 +929,7 @@ public:


RtApiAlsa(); RtApiAlsa();
~RtApiAlsa(); ~RtApiAlsa();
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; };
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void ); void closeStream( void );
@@ -952,7 +961,7 @@ class RtApiPulse: public RtApi
{ {
public: public:
~RtApiPulse(); ~RtApiPulse();
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; };
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void ); void closeStream( void );
@@ -986,7 +995,7 @@ public:


RtApiOss(); RtApiOss();
~RtApiOss(); ~RtApiOss();
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; };
RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
unsigned int getDeviceCount( void ); unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void ); void closeStream( void );
@@ -1016,21 +1025,21 @@ class RtApiDummy: public RtApi
{ {
public: public:


RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); };
RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; };
unsigned int getDeviceCount( void ) { return 0; };
RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) { RtAudio::DeviceInfo info; return info; };
void closeStream( void ) {};
void startStream( void ) {};
void stopStream( void ) {};
void abortStream( void ) {};
RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtError::WARNING ); }
RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; }
unsigned int getDeviceCount( void ) { return 0; }
RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; }
void closeStream( void ) {}
void startStream( void ) {}
void stopStream( void ) {}
void abortStream( void ) {}


private: private:


bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
RtAudio::StreamOptions *options ) { return false; };
bool probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
RtAudio::StreamOptions * /*options*/ ) { return false; }
}; };


#endif #endif


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

@@ -32,7 +32,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
<TD>RtApiPulse</TD> <TD>RtApiPulse</TD>
<TD>__LINUX_PULSE__</TD> <TD>__LINUX_PULSE__</TD>
<TD><TT>pthread</TT></TD> <TD><TT>pthread</TT></TD>
<TD><TT>g++ -Wall -D__LINUX_PULSE__ -o audioprobe audioprobe.cpp RtAudio.cpp -lpthread</TT></TD>
<TD><TT>g++ -Wall -D__LINUX_PULSE__ -o audioprobe audioprobe.cpp RtAudio.cpp -lpthread -lpulse-simple -lpulse</TT></TD>
</TR> </TR>
<TR> <TR>
<TD>Linux</TD> <TD>Linux</TD>


+ 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 \section download Download


Latest Release (14 June 2012): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.11.tar.gz">Version 4.0.11</A>
Latest Release (?? December 2012): <A href="http://www.music.mcgill.ca/~gary/rtaudio/release/rtaudio-4.0.12.tar.gz">Version 4.0.12</A>


\section documentation Documentation Links \section documentation Documentation Links




+ 8
- 0
doc/release.txt View File

@@ -2,6 +2,14 @@ RtAudio - a set of C++ classes that provide a common API for realtime audio inpu


By Gary P. Scavone, 2001-2012. By Gary P. Scavone, 2001-2012.


v4.0.12: (?? December 2012)
- updates to PulseAudio API support (thanks to Peter Meerwald and Tristan Matthews)
- updates for pkg-config support in configure script
- 24-bit format changed to true 24-bit format, not sub-bytes of 32-bits (thanks to Marc Britton)
- bug fixes to make sure stream status is closed if error during probeDeviceOpen
- updates / fixes to SCHED_RR code in ALSA (thanks to Marc Lindahl)
- various changes to avoid global variables (thanks to Martin Koegler)

v4.0.11: (14 June 2012) v4.0.11: (14 June 2012)
- fixes for memory leaks in ALSA (thanks to Martin Koegler) - fixes for memory leaks in ALSA (thanks to Martin Koegler)
- PulseAudio API support added (thanks to Peter Meerwald and Tristan Matthews) - PulseAudio API support added (thanks to Peter Meerwald and Tristan Matthews)


+ 1
- 1
librtaudio.pc.in View File

@@ -5,7 +5,7 @@ includedir=${prefix}/include


Name: librtaudio Name: librtaudio
Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output Description: RtAudio - a set of C++ classes that provide a common API for realtime audio input/output
Version: 4.0.11
Version: 4.0.12
Requires: @req@ Requires: @req@
Libs: -L${libdir} -lrtaudio Libs: -L${libdir} -lrtaudio
Libs.private: -lpthread Libs.private: -lpthread

Loading…
Cancel
Save