RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/\r
\r
RtAudio: realtime audio i/o C++ classes\r
- Copyright (c) 2001-2012 Gary P. Scavone\r
+ Copyright (c) 2001-2013 Gary P. Scavone\r
\r
Permission is hereby granted, free of charge, to any person\r
obtaining a copy of this software and associated documentation files\r
*/\r
/************************************************************************/\r
\r
-// RtAudio: Version 4.0.11\r
+// RtAudio: Version 4.0.12\r
\r
#include "RtAudio.h"\r
#include <iostream>\r
RtAudioFormat format, unsigned int sampleRate,\r
unsigned int *bufferFrames,\r
RtAudioCallback callback, void *userData,\r
- RtAudio::StreamOptions *options )\r
+ RtAudio::StreamOptions *options,\r
+ RtAudioErrorCallback errorCallback )\r
{\r
return rtapi_->openStream( outputParameters, inputParameters, format,\r
sampleRate, bufferFrames, callback,\r
- userData, options );\r
+ userData, options, errorCallback );\r
}\r
\r
// *************************************************** //\r
RtAudioFormat format, unsigned int sampleRate,\r
unsigned int *bufferFrames,\r
RtAudioCallback callback, void *userData,\r
- RtAudio::StreamOptions *options )\r
+ RtAudio::StreamOptions *options,\r
+ RtAudioErrorCallback errorCallback )\r
{\r
if ( stream_.state != STREAM_CLOSED ) {\r
errorText_ = "RtApi::openStream: a stream is already open!";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
\r
if ( oParams && oParams->nChannels < 1 ) {\r
errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
\r
if ( iParams && iParams->nChannels < 1 ) {\r
errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
\r
if ( oParams == NULL && iParams == NULL ) {\r
errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
\r
if ( formatBytes(format) == 0 ) {\r
errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
\r
unsigned int nDevices = getDeviceCount();\r
if ( oParams->deviceId >= nDevices ) {\r
errorText_ = "RtApi::openStream: output device parameter value is invalid.";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
}\r
\r
if ( iParams->deviceId >= nDevices ) {\r
errorText_ = "RtApi::openStream: input device parameter value is invalid.";\r
error( RtError::INVALID_USE );\r
+ return;\r
}\r
}\r
\r
\r
result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,\r
sampleRate, format, bufferFrames, options );\r
- if ( result == false ) error( RtError::SYSTEM_ERROR );\r
+ if ( result == false ) {\r
+ error( RtError::SYSTEM_ERROR );\r
+ return;\r
+ }\r
}\r
\r
if ( iChannels > 0 ) {\r
if ( result == false ) {\r
if ( oChannels > 0 ) closeStream();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
}\r
\r
stream_.callbackInfo.callback = (void *) callback;\r
stream_.callbackInfo.userData = userData;\r
+ stream_.callbackInfo.errorCallback = (void *) errorCallback;\r
\r
if ( options ) options->numberOfBuffers = stream_.nBuffers;\r
stream_.state = STREAM_STOPPED;\r
return;\r
}\r
\r
-bool RtApi :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,\r
- unsigned int firstChannel, unsigned int sampleRate,\r
- RtAudioFormat format, unsigned int *bufferSize,\r
- RtAudio::StreamOptions *options )\r
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,\r
+ unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,\r
+ RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,\r
+ RtAudio::StreamOptions * /*options*/ )\r
{\r
// MUST be implemented in subclasses!\r
return FAILURE;\r
:deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }\r
};\r
\r
-ThreadHandle threadId;\r
-\r
RtApiCore:: RtApiCore()\r
{\r
#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )\r
if ( nDevices == 0 ) {\r
errorText_ = "RtApiCore::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
if ( device >= nDevices ) {\r
errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
AudioDeviceID deviceList[ nDevices ];\r
return info;\r
}\r
\r
-OSStatus callbackHandler( AudioDeviceID inDevice,\r
- const AudioTimeStamp* inNow,\r
- const AudioBufferList* inInputData,\r
- const AudioTimeStamp* inInputTime,\r
- AudioBufferList* outOutputData,\r
- const AudioTimeStamp* inOutputTime, \r
- void* infoPointer )\r
+static OSStatus callbackHandler( AudioDeviceID inDevice,\r
+ const AudioTimeStamp* /*inNow*/,\r
+ const AudioBufferList* inInputData,\r
+ const AudioTimeStamp* /*inInputTime*/,\r
+ AudioBufferList* outOutputData,\r
+ const AudioTimeStamp* /*inOutputTime*/,\r
+ void* infoPointer )\r
{\r
CallbackInfo *info = (CallbackInfo *) infoPointer;\r
\r
return kAudioHardwareNoError;\r
}\r
\r
-OSStatus xrunListener( AudioObjectID inDevice,\r
- UInt32 nAddresses,\r
- const AudioObjectPropertyAddress properties[],\r
- void* handlePointer )\r
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,\r
+ UInt32 nAddresses,\r
+ const AudioObjectPropertyAddress properties[],\r
+ void* handlePointer )\r
{\r
CoreHandle *handle = (CoreHandle *) handlePointer;\r
for ( UInt32 i=0; i<nAddresses; i++ ) {\r
return kAudioHardwareNoError;\r
}\r
\r
-OSStatus rateListener( AudioObjectID inDevice,\r
- UInt32 nAddresses,\r
- const AudioObjectPropertyAddress properties[],\r
- void* ratePointer )\r
+static OSStatus rateListener( AudioObjectID inDevice,\r
+ UInt32 /*nAddresses*/,\r
+ const AudioObjectPropertyAddress /*properties*/[],\r
+ void* ratePointer )\r
{\r
\r
Float64 *rate = (Float64 *) ratePointer;\r
stream_.deviceBuffer = 0;\r
}\r
\r
+ stream_.state = STREAM_CLOSED;\r
return FAILURE;\r
}\r
\r
// aborted. It is better to handle it this way because the\r
// callbackEvent() function probably should return before the AudioDeviceStop()\r
// function is called.\r
-extern "C" void *coreStopStream( void *ptr )\r
+static void *coreStopStream( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiCore *object = (RtApiCore *) info->object;\r
\r
// Check if we were draining the stream and signal is finished.\r
if ( handle->drainCounter > 3 ) {\r
+ ThreadHandle threadId;\r
\r
stream_.state = STREAM_STOPPING;\r
if ( handle->internalDrain == true )\r
:client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }\r
};\r
\r
-ThreadHandle threadId;\r
-void jackSilentError( const char * ) {};\r
+static void jackSilentError( const char * ) {};\r
\r
RtApiJack :: RtApiJack()\r
{\r
jack_client_close( client );\r
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
// Get the current jack server sample rate.\r
return info;\r
}\r
\r
-int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )\r
{\r
CallbackInfo *info = (CallbackInfo *) infoPointer;\r
\r
// server signals that it is shutting down. It is necessary to handle\r
// it this way because the jackShutdown() function must return before\r
// the jack_deactivate() function (in closeStream()) will return.\r
-extern "C" void *jackCloseStream( void *ptr )\r
+static void *jackCloseStream( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiJack *object = (RtApiJack *) info->object;\r
\r
pthread_exit( NULL );\r
}\r
-void jackShutdown( void *infoPointer )\r
+static void jackShutdown( void *infoPointer )\r
{\r
CallbackInfo *info = (CallbackInfo *) infoPointer;\r
RtApiJack *object = (RtApiJack *) info->object;\r
// other problem occurred and we should close the stream.\r
if ( object->isStreamRunning() == false ) return;\r
\r
+ ThreadHandle threadId;\r
pthread_create( &threadId, NULL, jackCloseStream, info );\r
std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;\r
}\r
\r
-int jackXrun( void *infoPointer )\r
+static int jackXrun( void *infoPointer )\r
{\r
JackHandle *handle = (JackHandle *) infoPointer;\r
\r
// aborted. It is necessary to handle it this way because the\r
// callbackEvent() function must return before the jack_deactivate()\r
// function will return.\r
-extern "C" void *jackStopStream( void *ptr )\r
+static void *jackStopStream( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiJack *object = (RtApiJack *) info->object;\r
\r
// Check if we were draining the stream and signal is finished.\r
if ( handle->drainCounter > 3 ) {\r
+ ThreadHandle threadId;\r
\r
stream_.state = STREAM_STOPPING;\r
if ( handle->internalDrain == true )\r
#include "asiodrivers.h"\r
#include <cmath>\r
\r
-AsioDrivers drivers;\r
-ASIOCallbacks asioCallbacks;\r
-ASIODriverInfo driverInfo;\r
-CallbackInfo *asioCallbackInfo;\r
-bool asioXRun;\r
+static AsioDrivers drivers;\r
+static ASIOCallbacks asioCallbacks;\r
+static ASIODriverInfo driverInfo;\r
+static CallbackInfo *asioCallbackInfo;\r
+static bool asioXRun;\r
\r
struct AsioHandle {\r
int drainCounter; // Tracks callback counts when draining\r
\r
// Function declarations (definitions at end of section)\r
static const char* getAsioErrorString( ASIOError result );\r
-void sampleRateChanged( ASIOSampleRate sRate );\r
-long asioMessages( long selector, long value, void* message, double* opt );\r
+static void sampleRateChanged( ASIOSampleRate sRate );\r
+static long asioMessages( long selector, long value, void* message, double* opt );\r
\r
RtApiAsio :: RtApiAsio()\r
{\r
if ( nDevices == 0 ) {\r
errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
if ( device >= nDevices ) {\r
errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.\r
return info;\r
}\r
\r
-void bufferSwitch( long index, ASIOBool processNow )\r
+static void bufferSwitch( long index, ASIOBool processNow )\r
{\r
RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;\r
object->callbackEvent( index );\r
// aborted. It is necessary to handle it this way because the\r
// callbackEvent() function must return before the ASIOStop()\r
// function will return.\r
-extern "C" unsigned __stdcall asioStopStream( void *ptr )\r
+static unsigned __stdcall asioStopStream( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiAsio *object = (RtApiAsio *) info->object;\r
return SUCCESS;\r
}\r
\r
-void sampleRateChanged( ASIOSampleRate sRate )\r
+static void sampleRateChanged( ASIOSampleRate sRate )\r
{\r
// The ASIO documentation says that this usually only happens during\r
// external sync. Audio processing is not stopped by the driver,\r
std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;\r
}\r
\r
-long asioMessages( long selector, long value, void* message, double* opt )\r
+static long asioMessages( long selector, long value, void* message, double* opt )\r
{\r
long ret = 0;\r
\r
const char*message;\r
};\r
\r
- static Messages m[] = \r
+ static const Messages m[] = \r
{\r
{ ASE_NotPresent, "Hardware input or output is not present or available." },\r
{ ASE_HWMalfunction, "Hardware is malfunctioning." },\r
\r
static const char* getErrorString( int code );\r
\r
-extern "C" unsigned __stdcall callbackHandler( void *ptr );\r
+static unsigned __stdcall callbackHandler( void *ptr );\r
\r
struct DsDevice {\r
LPGUID id[2];\r
: found(false) { validId[0] = false; validId[1] = false; }\r
};\r
\r
-std::vector< DsDevice > dsDevices;\r
+struct DsProbeData {\r
+ bool isInput;\r
+ std::vector<struct DsDevice>* dsDevices;\r
+};\r
\r
RtApiDs :: RtApiDs()\r
{\r
dsDevices[i].found = false;\r
\r
// Query DirectSound devices.\r
- bool isInput = false;\r
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );\r
+ struct DsProbeData probeInfo;\r
+ probeInfo.isInput = false;\r
+ probeInfo.dsDevices = &dsDevices;\r
+ HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
if ( FAILED( result ) ) {\r
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";\r
errorText_ = errorStream_.str();\r
}\r
\r
// Query DirectSoundCapture devices.\r
- isInput = true;\r
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &isInput );\r
+ probeInfo.isInput = true;\r
+ result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );\r
if ( FAILED( result ) ) {\r
errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";\r
errorText_ = errorStream_.str();\r
if ( dsDevices.size() == 0 ) {\r
errorText_ = "RtApiDs::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
}\r
\r
if ( device >= dsDevices.size() ) {\r
errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
HRESULT result;\r
stream_.deviceBuffer = 0;\r
}\r
\r
+ stream_.state = STREAM_CLOSED;\r
return FAILURE;\r
}\r
\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );\r
if ( FAILED( result ) ) {\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
while ( true ) {\r
result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );\r
if ( FAILED( result ) ) {\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;\r
Sleep( 1 );\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];\r
if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
\r
// We will copy our output buffer into the region between\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
\r
// Copy our buffer into the DS buffer\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;\r
handle->bufferPointer[0] = nextWritePointer;\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
\r
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
\r
if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
\r
if ( duplexPrerollBytes <= 0 ) {\r
errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";\r
errorText_ = errorStream_.str();\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
handle->bufferPointer[1] = nextReadPointer;\r
\r
// Definitions for utility functions and callbacks\r
// specific to the DirectSound implementation.\r
\r
-extern "C" unsigned __stdcall callbackHandler( void *ptr )\r
+static unsigned __stdcall callbackHandler( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiDs *object = (RtApiDs *) info->object;\r
\r
#include "tchar.h"\r
\r
-std::string convertTChar( LPCTSTR name )\r
+static std::string convertTChar( LPCTSTR name )\r
{\r
#if defined( UNICODE ) || defined( _UNICODE )\r
int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);\r
- std::string s( length, 0 );\r
- length = WideCharToMultiByte(CP_UTF8, 0, name, wcslen(name), &s[0], length, NULL, NULL);\r
+ std::string s( length-1, '\0' );\r
+ WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);\r
#else\r
std::string s( name );\r
#endif\r
LPCTSTR module,\r
LPVOID lpContext )\r
{\r
- bool *isInput = (bool *) lpContext;\r
+ struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;\r
+ std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;\r
\r
HRESULT hr;\r
bool validDevice = false;\r
- if ( *isInput == true ) {\r
+ if ( probeInfo.isInput == true ) {\r
DSCCAPS caps;\r
LPDIRECTSOUNDCAPTURE object;\r
\r
\r
// If good device, then save its name and guid.\r
std::string name = convertTChar( description );\r
- if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
+ //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )\r
+ if ( lpguid == NULL )\r
name = "Default Device";\r
if ( validDevice ) {\r
for ( unsigned int i=0; i<dsDevices.size(); i++ ) {\r
if ( dsDevices[i].name == name ) {\r
dsDevices[i].found = true;\r
- if ( *isInput ) {\r
+ if ( probeInfo.isInput ) {\r
dsDevices[i].id[1] = lpguid;\r
dsDevices[i].validId[1] = true;\r
}\r
DsDevice device;\r
device.name = name;\r
device.found = true;\r
- if ( *isInput ) {\r
+ if ( probeInfo.isInput ) {\r
device.id[1] = lpguid;\r
device.validId[1] = true;\r
}\r
:synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }\r
};\r
\r
-extern "C" void *alsaCallbackHandler( void * ptr );\r
+static void *alsaCallbackHandler( void * ptr );\r
\r
RtApiAlsa :: RtApiAlsa()\r
{\r
if ( nDevices == 0 ) {\r
errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
if ( device >= nDevices ) {\r
errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
foundDevice:\r
stream_.deviceBuffer = 0;\r
}\r
\r
+ stream_.state = STREAM_CLOSED;\r
return FAILURE;\r
}\r
\r
if ( doStopStream == 1 ) this->stopStream();\r
}\r
\r
-extern "C" void *alsaCallbackHandler( void *ptr )\r
+static void *alsaCallbackHandler( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiAlsa *object = (RtApiAlsa *) info->object;\r
#include <pulse/simple.h>\r
#include <cstdio>\r
\r
-namespace {\r
-const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
- 44100, 48000, 96000, 0}; }\r
+static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,\r
+ 44100, 48000, 96000, 0};\r
\r
struct rtaudio_pa_format_mapping_t {\r
RtAudioFormat rtaudio_format;\r
return info;\r
}\r
\r
-extern "C" void *pulseaudio_callback( void * user )\r
+static void *pulseaudio_callback( void * user )\r
{\r
CallbackInfo *cbi = static_cast<CallbackInfo *>( user );\r
RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );\r
errorText_ = errorStream_.str();\r
MUTEX_UNLOCK( &stream_.mutex );\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
}\r
\r
errorText_ = errorStream_.str();\r
MUTEX_UNLOCK( &stream_.mutex );\r
error( RtError::SYSTEM_ERROR );\r
+ return;\r
}\r
}\r
\r
}\r
}\r
}\r
- \r
+\r
stream_.device[mode] = device;\r
- stream_.state = STREAM_STOPPED;\r
\r
// Setup the buffer conversion information structure.\r
if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );\r
else\r
stream_.mode = DUPLEX;\r
\r
- stream_.state = STREAM_STOPPED;\r
-\r
if ( !stream_.callbackInfo.isRunning ) {\r
stream_.callbackInfo.object = this;\r
stream_.callbackInfo.isRunning = true;\r
goto error;\r
}\r
}\r
+\r
+ stream_.state = STREAM_STOPPED;\r
return true;\r
\r
error:\r
- closeStream();\r
- return false;\r
+ if ( pah && stream_.callbackInfo.isRunning ) {\r
+ pthread_cond_destroy( &pah->runnable_cv );\r
+ delete pah;\r
+ stream_.apiHandle = 0;\r
+ }\r
+\r
+ for ( int i=0; i<2; i++ ) {\r
+ if ( stream_.userBuffer[i] ) {\r
+ free( stream_.userBuffer[i] );\r
+ stream_.userBuffer[i] = 0;\r
+ }\r
+ }\r
+\r
+ if ( stream_.deviceBuffer ) {\r
+ free( stream_.deviceBuffer );\r
+ stream_.deviceBuffer = 0;\r
+ }\r
+\r
+ return FAILURE;\r
}\r
\r
//******************** End of __LINUX_PULSE__ *********************//\r
#include <errno.h>\r
#include <math.h>\r
\r
-extern "C" void *ossCallbackHandler(void * ptr);\r
+static void *ossCallbackHandler(void * ptr);\r
\r
// A structure to hold various information related to the OSS API\r
// implementation.\r
close( mixerfd );\r
errorText_ = "RtApiOss::getDeviceInfo: no devices found!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
if ( device >= nDevices ) {\r
close( mixerfd );\r
errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";\r
error( RtError::INVALID_USE );\r
+ return info;\r
}\r
\r
oss_audioinfo ainfo;\r
if ( doStopStream == 1 ) this->stopStream();\r
}\r
\r
-extern "C" void *ossCallbackHandler( void *ptr )\r
+static void *ossCallbackHandler( void *ptr )\r
{\r
CallbackInfo *info = (CallbackInfo *) ptr;\r
RtApiOss *object = (RtApiOss *) info->object;\r
void RtApi :: error( RtError::Type type )\r
{\r
errorStream_.str(""); // clear the ostringstream\r
+\r
+ RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;\r
+ if ( errorCallback ) {\r
+ // abortStream() can generate new error messages. Ignore them. Just keep original one.\r
+ static bool firstErrorOccured = false;\r
+\r
+ if ( firstErrorOccured )\r
+ return;\r
+\r
+ firstErrorOccured = true;\r
+ const std::string errorMessage = errorText_;\r
+\r
+ if ( type != RtError::WARNING && stream_.state != STREAM_STOPPED) {\r
+ stream_.callbackInfo.isRunning = false; // exit from the thread\r
+ abortStream();\r
+ }\r
+\r
+ errorCallback( type, errorMessage );\r
+ firstErrorOccured = false;\r
+ return;\r
+ }\r
+\r
if ( type == RtError::WARNING && showWarnings_ == true )\r
std::cerr << '\n' << errorText_ << "\n\n";\r
else if ( type != RtError::WARNING )\r
stream_.callbackInfo.callback = 0;\r
stream_.callbackInfo.userData = 0;\r
stream_.callbackInfo.isRunning = false;\r
+ stream_.callbackInfo.errorCallback = 0;\r
for ( int i=0; i<2; i++ ) {\r
stream_.device[i] = 11111;\r
stream_.doConvertBuffer[i] = false;\r