summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Scavone <gary@music.mcgill.ca>2013-04-15 15:30:29 +0000
committerStephen Sinclair <sinclair@music.mcgill.ca>2013-10-11 01:38:32 +0200
commit906e5ba67f7c253655b7f1a29b832bb7852e1126 (patch)
treeb899f73ee2d17304989e93d09dbbe43b8738de41
parentbee81ff356bbec279facb50dab5e6069c6475fcc (diff)
Various updates for pulse audio, preparation for release 4.0.12, error callback addition (GS).
-rw-r--r--Makefile.in2
-rw-r--r--RtAudio.cpp233
-rw-r--r--RtAudio.h71
-rw-r--r--doc/doxygen/compiling.txt2
-rw-r--r--doc/doxygen/tutorial.txt2
-rw-r--r--doc/release.txt8
-rw-r--r--librtaudio.pc.in2
7 files changed, 212 insertions, 108 deletions
diff --git a/Makefile.in b/Makefile.in
index af5c957..41685e5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -8,7 +8,7 @@ OBJECTS = RtAudio.o @objects@
STATIC = librtaudio.a
SHARED = @sharedlib@
-RELEASE = 4.0.11
+RELEASE = 4.0.12
MAJOR = 4
LIBRARIES = $(STATIC) $(SHARED)
diff --git a/RtAudio.cpp b/RtAudio.cpp
index 70414a6..3563151 100644
--- a/RtAudio.cpp
+++ b/RtAudio.cpp
@@ -38,7 +38,7 @@
*/
/************************************************************************/
-// RtAudio: Version 4.0.11
+// RtAudio: Version 4.0.12
#include "RtAudio.h"
#include <iostream>
@@ -189,11 +189,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
return rtapi_->openStream( outputParameters, inputParameters, format,
sampleRate, bufferFrames, callback,
- userData, options );
+ userData, options, errorCallback );
}
// *************************************************** //
@@ -224,31 +225,37 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames,
RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options )
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
{
if ( stream_.state != STREAM_CLOSED ) {
errorText_ = "RtApi::openStream: a stream is already open!";
error( RtError::INVALID_USE );
+ return;
}
if ( oParams && oParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
error( RtError::INVALID_USE );
+ return;
}
if ( iParams && iParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
error( RtError::INVALID_USE );
+ return;
}
if ( oParams == NULL && iParams == NULL ) {
errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
error( RtError::INVALID_USE );
+ return;
}
if ( formatBytes(format) == 0 ) {
errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
error( RtError::INVALID_USE );
+ return;
}
unsigned int nDevices = getDeviceCount();
@@ -258,6 +265,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
if ( oParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: output device parameter value is invalid.";
error( RtError::INVALID_USE );
+ return;
}
}
@@ -267,6 +275,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
if ( iParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: input device parameter value is invalid.";
error( RtError::INVALID_USE );
+ return;
}
}
@@ -277,7 +286,10 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
sampleRate, format, bufferFrames, options );
- if ( result == false ) error( RtError::SYSTEM_ERROR );
+ if ( result == false ) {
+ error( RtError::SYSTEM_ERROR );
+ return;
+ }
}
if ( iChannels > 0 ) {
@@ -287,11 +299,13 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
if ( result == false ) {
if ( oChannels > 0 ) closeStream();
error( RtError::SYSTEM_ERROR );
+ return;
}
}
stream_.callbackInfo.callback = (void *) callback;
stream_.callbackInfo.userData = userData;
+ stream_.callbackInfo.errorCallback = (void *) errorCallback;
if ( options ) options->numberOfBuffers = stream_.nBuffers;
stream_.state = STREAM_STOPPED;
@@ -315,10 +329,10 @@ void RtApi :: closeStream( void )
return;
}
-bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
+ unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
+ RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
+ RtAudio::StreamOptions * /*options*/ )
{
// MUST be implemented in subclasses!
return FAILURE;
@@ -423,8 +437,6 @@ struct CoreHandle {
:deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
};
-ThreadHandle threadId;
-
RtApiCore:: RtApiCore()
{
#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )
@@ -543,11 +555,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
if ( nDevices == 0 ) {
errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
AudioDeviceID deviceList[ nDevices ];
@@ -736,13 +750,13 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
return info;
}
-OSStatus callbackHandler( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* infoPointer )
+static OSStatus callbackHandler( AudioDeviceID inDevice,
+ const AudioTimeStamp* /*inNow*/,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* /*inInputTime*/,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* /*inOutputTime*/,
+ void* infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -753,10 +767,10 @@ OSStatus callbackHandler( AudioDeviceID inDevice,
return kAudioHardwareNoError;
}
-OSStatus xrunListener( AudioObjectID inDevice,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void* handlePointer )
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void* handlePointer )
{
CoreHandle *handle = (CoreHandle *) handlePointer;
for ( UInt32 i=0; i<nAddresses; i++ ) {
@@ -771,10 +785,10 @@ OSStatus xrunListener( AudioObjectID inDevice,
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;
@@ -1300,6 +1314,7 @@ bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -1459,7 +1474,7 @@ void RtApiCore :: abortStream( void )
// aborted. It is better to handle it this way because the
// callbackEvent() function probably should return before the AudioDeviceStop()
// function is called.
-extern "C" void *coreStopStream( void *ptr )
+static void *coreStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
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.
if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
stream_.state = STREAM_STOPPING;
if ( handle->internalDrain == true )
@@ -1821,8 +1837,7 @@ struct JackHandle {
:client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
};
-ThreadHandle threadId;
-void jackSilentError( const char * ) {};
+static void jackSilentError( const char * ) {};
RtApiJack :: RtApiJack()
{
@@ -1911,6 +1926,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
jack_client_close( client );
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
// Get the current jack server sample rate.
@@ -1961,7 +1977,7 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
return info;
}
-int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -1975,7 +1991,7 @@ int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
// server signals that it is shutting down. It is necessary to handle
// it this way because the jackShutdown() function must return before
// the jack_deactivate() function (in closeStream()) will return.
-extern "C" void *jackCloseStream( void *ptr )
+static void *jackCloseStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiJack *object = (RtApiJack *) info->object;
@@ -1984,7 +2000,7 @@ extern "C" void *jackCloseStream( void *ptr )
pthread_exit( NULL );
}
-void jackShutdown( void *infoPointer )
+static void jackShutdown( void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
RtApiJack *object = (RtApiJack *) info->object;
@@ -1996,11 +2012,12 @@ void jackShutdown( void *infoPointer )
// other problem occurred and we should close the stream.
if ( object->isStreamRunning() == false ) return;
+ ThreadHandle threadId;
pthread_create( &threadId, NULL, jackCloseStream, info );
std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
}
-int jackXrun( void *infoPointer )
+static int jackXrun( void *infoPointer )
{
JackHandle *handle = (JackHandle *) infoPointer;
@@ -2418,7 +2435,7 @@ void RtApiJack :: abortStream( void )
// aborted. It is necessary to handle it this way because the
// callbackEvent() function must return before the jack_deactivate()
// function will return.
-extern "C" void *jackStopStream( void *ptr )
+static void *jackStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiJack *object = (RtApiJack *) info->object;
@@ -2446,6 +2463,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
// Check if we were draining the stream and signal is finished.
if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
stream_.state = STREAM_STOPPING;
if ( handle->internalDrain == true )
@@ -2565,11 +2583,11 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
#include "asiodrivers.h"
#include <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 {
int drainCounter; // Tracks callback counts when draining
@@ -2583,8 +2601,8 @@ struct AsioHandle {
// Function declarations (definitions at end of section)
static const char* getAsioErrorString( ASIOError result );
-void sampleRateChanged( ASIOSampleRate sRate );
-long asioMessages( long selector, long value, void* message, double* opt );
+static void sampleRateChanged( ASIOSampleRate sRate );
+static long asioMessages( long selector, long value, void* message, double* opt );
RtApiAsio :: RtApiAsio()
{
@@ -2627,11 +2645,13 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
if ( nDevices == 0 ) {
errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
@@ -2730,7 +2750,7 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
return info;
}
-void bufferSwitch( long index, ASIOBool processNow )
+static void bufferSwitch( long index, ASIOBool processNow )
{
RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
object->callbackEvent( index );
@@ -3230,7 +3250,7 @@ void RtApiAsio :: abortStream()
// aborted. It is necessary to handle it this way because the
// callbackEvent() function must return before the ASIOStop()
// function will return.
-extern "C" unsigned __stdcall asioStopStream( void *ptr )
+static unsigned __stdcall asioStopStream( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiAsio *object = (RtApiAsio *) info->object;
@@ -3393,7 +3413,7 @@ bool RtApiAsio :: callbackEvent( long bufferIndex )
return SUCCESS;
}
-void sampleRateChanged( ASIOSampleRate sRate )
+static void sampleRateChanged( ASIOSampleRate sRate )
{
// The ASIO documentation says that this usually only happens during
// external sync. Audio processing is not stopped by the driver,
@@ -3413,7 +3433,7 @@ void sampleRateChanged( ASIOSampleRate sRate )
std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
}
-long asioMessages( long selector, long value, void* message, double* opt )
+static long asioMessages( long selector, long value, void* message, double* opt )
{
long ret = 0;
@@ -3491,7 +3511,7 @@ static const char* getAsioErrorString( ASIOError result )
const char*message;
};
- static Messages m[] =
+ static const Messages m[] =
{
{ ASE_NotPresent, "Hardware input or output is not present or available." },
{ ASE_HWMalfunction, "Hardware is malfunctioning." },
@@ -3572,7 +3592,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
static const char* getErrorString( int code );
-extern "C" unsigned __stdcall callbackHandler( void *ptr );
+static unsigned __stdcall callbackHandler( void *ptr );
struct DsDevice {
LPGUID id[2];
@@ -3584,7 +3604,10 @@ struct DsDevice {
: found(false) { validId[0] = false; validId[1] = false; }
};
-std::vector< DsDevice > dsDevices;
+struct DsProbeData {
+ bool isInput;
+ std::vector<struct DsDevice>* dsDevices;
+};
RtApiDs :: RtApiDs()
{
@@ -3622,8 +3645,10 @@ unsigned int RtApiDs :: getDeviceCount( void )
dsDevices[i].found = false;
// Query DirectSound devices.
- bool isInput = false;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );
+ struct DsProbeData probeInfo;
+ probeInfo.isInput = false;
+ probeInfo.dsDevices = &dsDevices;
+ HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
errorText_ = errorStream_.str();
@@ -3631,8 +3656,8 @@ unsigned int RtApiDs :: getDeviceCount( void )
}
// Query DirectSoundCapture devices.
- isInput = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );
+ probeInfo.isInput = true;
+ result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
errorText_ = errorStream_.str();
@@ -3661,12 +3686,14 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
if ( dsDevices.size() == 0 ) {
errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
}
if ( device >= dsDevices.size() ) {
errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
HRESULT result;
@@ -4321,6 +4348,7 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -4642,12 +4670,14 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
while ( true ) {
result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
@@ -4655,12 +4685,14 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
if ( FAILED( result ) ) {
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
Sleep( 1 );
@@ -4681,6 +4713,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
@@ -4731,6 +4764,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
// We will copy our output buffer into the region between
@@ -4771,6 +4805,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
// Copy our buffer into the DS buffer
@@ -4783,6 +4818,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
handle->bufferPointer[0] = nextWritePointer;
@@ -4817,6 +4853,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
@@ -4877,6 +4914,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
@@ -4890,6 +4928,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
if ( duplexPrerollBytes <= 0 ) {
@@ -4910,6 +4949,7 @@ void RtApiDs :: callbackEvent()
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
errorText_ = errorStream_.str();
error( RtError::SYSTEM_ERROR );
+ return;
}
handle->bufferPointer[1] = nextReadPointer;
@@ -4931,7 +4971,7 @@ void RtApiDs :: callbackEvent()
// Definitions for utility functions and callbacks
// specific to the DirectSound implementation.
-extern "C" unsigned __stdcall callbackHandler( void *ptr )
+static unsigned __stdcall callbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiDs *object = (RtApiDs *) info->object;
@@ -4947,7 +4987,7 @@ extern "C" unsigned __stdcall callbackHandler( void *ptr )
#include "tchar.h"
-std::string convertTChar( LPCTSTR name )
+static std::string convertTChar( LPCTSTR name )
{
#if defined( UNICODE ) || defined( _UNICODE )
int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
@@ -4965,11 +5005,12 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
LPCTSTR module,
LPVOID lpContext )
{
- bool *isInput = (bool *) lpContext;
+ struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
+ std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
HRESULT hr;
bool validDevice = false;
- if ( *isInput == true ) {
+ if ( probeInfo.isInput == true ) {
DSCCAPS caps;
LPDIRECTSOUNDCAPTURE object;
@@ -5001,13 +5042,14 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
// If good device, then save its name and guid.
std::string name = convertTChar( description );
- if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
+ //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
+ if ( lpguid == NULL )
name = "Default Device";
if ( validDevice ) {
for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
if ( dsDevices[i].name == name ) {
dsDevices[i].found = true;
- if ( *isInput ) {
+ if ( probeInfo.isInput ) {
dsDevices[i].id[1] = lpguid;
dsDevices[i].validId[1] = true;
}
@@ -5022,7 +5064,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
DsDevice device;
device.name = name;
device.found = true;
- if ( *isInput ) {
+ if ( probeInfo.isInput ) {
device.id[1] = lpguid;
device.validId[1] = true;
}
@@ -5111,7 +5153,7 @@ struct AlsaHandle {
:synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
};
-extern "C" void *alsaCallbackHandler( void * ptr );
+static void *alsaCallbackHandler( void * ptr );
RtApiAlsa :: RtApiAlsa()
{
@@ -5224,11 +5266,13 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
if ( nDevices == 0 ) {
errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
foundDevice:
@@ -5961,6 +6005,7 @@ bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
@@ -6335,7 +6380,7 @@ void RtApiAlsa :: callbackEvent()
if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *alsaCallbackHandler( void *ptr )
+static void *alsaCallbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiAlsa *object = (RtApiAlsa *) info->object;
@@ -6369,9 +6414,8 @@ extern "C" void *alsaCallbackHandler( void *ptr )
#include <pulse/simple.h>
#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 {
RtAudioFormat rtaudio_format;
@@ -6423,7 +6467,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int device )
return info;
}
-extern "C" void *pulseaudio_callback( void * user )
+static void *pulseaudio_callback( void * user )
{
CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
@@ -6618,6 +6662,7 @@ void RtApiPulse::stopStream( void )
errorText_ = errorStream_.str();
MUTEX_UNLOCK( &stream_.mutex );
error( RtError::SYSTEM_ERROR );
+ return;
}
}
@@ -6651,6 +6696,7 @@ void RtApiPulse::abortStream( void )
errorText_ = errorStream_.str();
MUTEX_UNLOCK( &stream_.mutex );
error( RtError::SYSTEM_ERROR );
+ return;
}
}
@@ -6748,9 +6794,8 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
}
}
}
-
+
stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
// Setup the buffer conversion information structure.
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
@@ -6797,8 +6842,6 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
else
stream_.mode = DUPLEX;
- stream_.state = STREAM_STOPPED;
-
if ( !stream_.callbackInfo.isRunning ) {
stream_.callbackInfo.object = this;
stream_.callbackInfo.isRunning = true;
@@ -6807,11 +6850,30 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
goto error;
}
}
+
+ stream_.state = STREAM_STOPPED;
return true;
error:
- closeStream();
- return false;
+ if ( pah && stream_.callbackInfo.isRunning ) {
+ pthread_cond_destroy( &pah->runnable_cv );
+ delete pah;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ return FAILURE;
}
//******************** End of __LINUX_PULSE__ *********************//
@@ -6827,7 +6889,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
#include <errno.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
// implementation.
@@ -6898,12 +6960,14 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
error( RtError::INVALID_USE );
+ return info;
}
if ( device >= nDevices ) {
close( mixerfd );
errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
error( RtError::INVALID_USE );
+ return info;
}
oss_audioinfo ainfo;
@@ -7734,7 +7798,7 @@ void RtApiOss :: callbackEvent()
if ( doStopStream == 1 ) this->stopStream();
}
-extern "C" void *ossCallbackHandler( void *ptr )
+static void *ossCallbackHandler( void *ptr )
{
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiOss *object = (RtApiOss *) info->object;
@@ -7763,6 +7827,28 @@ extern "C" void *ossCallbackHandler( void *ptr )
void RtApi :: error( RtError::Type type )
{
errorStream_.str(""); // clear the ostringstream
+
+ RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;
+ if ( errorCallback ) {
+ // abortStream() can generate new error messages. Ignore them. Just keep original one.
+ static bool firstErrorOccured = false;
+
+ if ( firstErrorOccured )
+ return;
+
+ firstErrorOccured = true;
+ const std::string errorMessage = errorText_;
+
+ if ( type != RtError::WARNING && stream_.state != STREAM_STOPPED) {
+ stream_.callbackInfo.isRunning = false; // exit from the thread
+ abortStream();
+ }
+
+ errorCallback( type, errorMessage );
+ firstErrorOccured = false;
+ return;
+ }
+
if ( type == RtError::WARNING && showWarnings_ == true )
std::cerr << '\n' << errorText_ << "\n\n";
else if ( type != RtError::WARNING )
@@ -7792,6 +7878,7 @@ void RtApi :: clearStreamInfo()
stream_.callbackInfo.callback = 0;
stream_.callbackInfo.userData = 0;
stream_.callbackInfo.isRunning = false;
+ stream_.callbackInfo.errorCallback = 0;
for ( int i=0; i<2; i++ ) {
stream_.device[i] = 11111;
stream_.doConvertBuffer[i] = false;
diff --git a/RtAudio.h b/RtAudio.h
index 4a0b9f3..8d827e3 100644
--- a/RtAudio.h
+++ b/RtAudio.h
@@ -42,7 +42,7 @@
\file RtAudio.h
*/
-// RtAudio: Version 4.0.11
+// RtAudio: Version 4.0.12
#ifndef __RTAUDIO_H
#define __RTAUDIO_H
@@ -59,12 +59,10 @@
internal routines will automatically take care of any necessary
byte-swapping between the host format and the soundcard. Thus,
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_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_FLOAT32: Normalized between plus/minus 1.0.
- \e RTAUDIO_FLOAT64: Normalized between plus/minus 1.0.
@@ -72,7 +70,7 @@
typedef unsigned long RtAudioFormat;
static const RtAudioFormat RTAUDIO_SINT8 = 0x1; // 8-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_FLOAT32 = 0x10; // 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,
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
lowest allowable value is used. The actual value used is
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,
RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate,
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.
/*!
@@ -535,6 +541,7 @@ struct CallbackInfo {
ThreadHandle thread;
void *callback;
void *userData;
+ void *errorCallback;
void *apiInfo; // void pointer for API specific callback information
bool isRunning;
bool doRealtime;
@@ -542,7 +549,7 @@ struct CallbackInfo {
// Default constructor.
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,
RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback,
- void *userData, RtAudio::StreamOptions *options );
+ void *userData, RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback );
virtual void closeStream( void );
virtual void startStream( void ) = 0;
virtual void stopStream( void ) = 0;
@@ -618,9 +626,9 @@ public:
long getStreamLatency( void );
unsigned int getStreamSampleRate( 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:
@@ -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 :: 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 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 ); }
@@ -775,7 +783,7 @@ public:
RtApiCore();
~RtApiCore();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
unsigned int getDefaultOutputDevice( void );
@@ -813,7 +821,7 @@ public:
RtApiJack();
~RtApiJack();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -846,7 +854,7 @@ public:
RtApiAsio();
~RtApiAsio();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -882,7 +890,7 @@ public:
RtApiDs();
~RtApiDs();
- RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; };
+ RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; }
unsigned int getDeviceCount( void );
unsigned int getDefaultOutputDevice( void );
unsigned int getDefaultInputDevice( void );
@@ -904,6 +912,7 @@ public:
bool coInitialized_;
bool buffersRolling;
long duplexPrerollBytes;
+ std::vector<struct DsDevice> dsDevices;
bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
unsigned int firstChannel, unsigned int sampleRate,
RtAudioFormat format, unsigned int *bufferSize,
@@ -920,7 +929,7 @@ public:
RtApiAlsa();
~RtApiAlsa();
- RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; };
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -952,7 +961,7 @@ class RtApiPulse: public RtApi
{
public:
~RtApiPulse();
- RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; };
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -986,7 +995,7 @@ public:
RtApiOss();
~RtApiOss();
- RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; };
+ RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; }
unsigned int getDeviceCount( void );
RtAudio::DeviceInfo getDeviceInfo( unsigned int device );
void closeStream( void );
@@ -1016,21 +1025,21 @@ class RtApiDummy: public RtApi
{
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:
- 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
diff --git a/doc/doxygen/compiling.txt b/doc/doxygen/compiling.txt
index d9884d0..c1f83e4 100644
--- a/doc/doxygen/compiling.txt
+++ b/doc/doxygen/compiling.txt
@@ -32,7 +32,7 @@ In order to compile RtAudio for a specific OS and audio API, it is necessary to
<TD>RtApiPulse</TD>
<TD>__LINUX_PULSE__</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>
<TD>Linux</TD>
diff --git a/doc/doxygen/tutorial.txt b/doc/doxygen/tutorial.txt
index 19ed170..cbd4e21 100644
--- a/doc/doxygen/tutorial.txt
+++ b/doc/doxygen/tutorial.txt
@@ -32,7 +32,7 @@ Devices are now re-enumerated every time the RtAudio::getDeviceCount(), RtAudio:
\section download Download
-Latest Release (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
diff --git a/doc/release.txt b/doc/release.txt
index a29a36c..3b09e89 100644
--- a/doc/release.txt
+++ b/doc/release.txt
@@ -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.
+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)
- fixes for memory leaks in ALSA (thanks to Martin Koegler)
- PulseAudio API support added (thanks to Peter Meerwald and Tristan Matthews)
diff --git a/librtaudio.pc.in b/librtaudio.pc.in
index e80da3c..d7591a7 100644
--- a/librtaudio.pc.in
+++ b/librtaudio.pc.in
@@ -5,7 +5,7 @@ includedir=${prefix}/include
Name: librtaudio
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@
Libs: -L${libdir} -lrtaudio
Libs.private: -lpthread