*/
/************************************************************************/
-// RtAudio: Version 5.1.0
+// RtAudio: Version 6.0.0beta1
#include "RtAudio.h"
#include <iostream>
#endif
}
-RtAudio :: RtAudio( RtAudio::Api api )
+RtAudio :: RtAudio( RtAudio::Api api, RtAudioErrorCallback errorCallback )
{
rtapi_ = 0;
-
+
+ std::string errorMessage;
if ( api != UNSPECIFIED ) {
// Attempt to open the specified API.
openRtApi( api );
- if ( rtapi_ ) return;
- // No compiled support for specified API value. Issue a debug
- // warning and continue as if no API was specified.
- std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;
+ if ( rtapi_ ) {
+ if ( errorCallback ) rtapi_->setErrorCallback( errorCallback );
+ return;
+ }
+
+ // No compiled support for specified API value. Issue a warning
+ // and continue as if no API was specified.
+ errorMessage = "RtAudio: no compiled support for specified API argument!";
+ if ( errorCallback )
+ errorCallback( RTAUDIO_INVALID_USE, errorMessage );
+ else
+ std::cerr << '\n' << errorMessage << '\n' << std::endl;
}
// Iterate through the compiled APIs and return as soon as we find
if ( rtapi_ && rtapi_->getDeviceCount() ) break;
}
- if ( rtapi_ ) return;
+ if ( rtapi_ ) {
+ if ( errorCallback ) rtapi_->setErrorCallback( errorCallback );
+ return;
+ }
// It should not be possible to get here because the preprocessor
// definition __RTAUDIO_DUMMY__ is automatically defined in RtAudio.h
// if no API-specific definitions are passed to the compiler. But just
- // in case something weird happens, we'll throw an error.
- std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";
- throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
+ // in case something weird happens, issue an error message and abort.
+ errorMessage = "RtAudio: no compiled API support found ... critical error!";
+ if ( errorCallback )
+ errorCallback( RTAUDIO_INVALID_USE, errorMessage );
+ else
+ std::cerr << '\n' << errorMessage << '\n' << std::endl;
+ abort();
}
RtAudio :: ~RtAudio()
delete rtapi_;
}
-//void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
-RtAudioError::Type RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
- RtAudio::StreamParameters *inputParameters,
- RtAudioFormat format, unsigned int sampleRate,
- unsigned int *bufferFrames,
- RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options ) //, RtAudioErrorCallback errorCallback )
+RtAudioErrorType RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
+ RtAudio::StreamParameters *inputParameters,
+ RtAudioFormat format, unsigned int sampleRate,
+ unsigned int *bufferFrames,
+ RtAudioCallback callback, void *userData,
+ RtAudio::StreamOptions *options )
{
return rtapi_->openStream( outputParameters, inputParameters, format,
sampleRate, bufferFrames, callback,
- userData, options ); //, errorCallback );
+ userData, options );
}
// *************************************************** //
MUTEX_INITIALIZE( &stream_.mutex );
errorCallback_ = 0;
showWarnings_ = true;
- //firstErrorOccurred_ = false;
}
RtApi :: ~RtApi()
MUTEX_DESTROY( &stream_.mutex );
}
-//void RtApi :: openStream( RtAudio::StreamParameters *oParams,
-RtAudioError::Type RtApi :: openStream( RtAudio::StreamParameters *oParams,
- RtAudio::StreamParameters *iParams,
- RtAudioFormat format, unsigned int sampleRate,
- unsigned int *bufferFrames,
- RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options ) //, RtAudioErrorCallback errorCallback )
+RtAudioErrorType RtApi :: openStream( RtAudio::StreamParameters *oParams,
+ RtAudio::StreamParameters *iParams,
+ RtAudioFormat format, unsigned int sampleRate,
+ unsigned int *bufferFrames,
+ RtAudioCallback callback, void *userData,
+ RtAudio::StreamOptions *options )
{
- //RtAudioError::Type type = RtAudioError::NO_ERROR;
if ( stream_.state != STREAM_CLOSED ) {
- //type = RtAudioError::INVALID_USE;
errorText_ = "RtApi::openStream: a stream is already open!";
- return error( RtAudioError::INVALID_USE );
+ return error( RTAUDIO_INVALID_USE );
}
// Clear stream information potentially left from a previously open stream.
if ( oParams && oParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
if ( iParams && iParams->nChannels < 1 ) {
errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
if ( oParams == NULL && iParams == NULL ) {
errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
if ( formatBytes(format) == 0 ) {
errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
unsigned int nDevices = getDeviceCount();
oChannels = oParams->nChannels;
if ( oParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: output device parameter value is invalid.";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
}
iChannels = iParams->nChannels;
if ( iParams->deviceId >= nDevices ) {
errorText_ = "RtApi::openStream: input device parameter value is invalid.";
- return error( RtAudioError::INVALID_USE );
- //return;
+ return error( RTAUDIO_INVALID_USE );
}
}
result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
sampleRate, format, bufferFrames, options );
if ( result == false ) {
- return error( RtAudioError::SYSTEM_ERROR );
- //return;
+ return error( RTAUDIO_SYSTEM_ERROR );
}
}
result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,
sampleRate, format, bufferFrames, options );
if ( result == false ) {
- if ( oChannels > 0 ) closeStream();
- return error( RtAudioError::SYSTEM_ERROR );
- //return;
+ return error( RTAUDIO_SYSTEM_ERROR );
}
}
stream_.callbackInfo.callback = (void *) callback;
stream_.callbackInfo.userData = userData;
- //stream_.callbackInfo.errorCallback = (void *) errorCallback;
if ( options ) options->numberOfBuffers = stream_.nBuffers;
stream_.state = STREAM_STOPPED;
- return RtAudioError::NO_ERROR;
+ return RTAUDIO_NO_ERROR;
}
unsigned int RtApi :: getDefaultInputDevice( void )
void RtApi :: setStreamTime( double time )
{
- // verifyStream();
-
if ( time >= 0.0 )
stream_.streamTime = time;
/*
unsigned int RtApi :: getStreamSampleRate( void )
{
- //verifyStream();
if ( isStreamOpen() ) return stream_.sampleRate;
else return 0;
}
pthread_cond_t condition;
int drainCounter; // Tracks callback counts when draining
bool internalDrain; // Indicates if stop is initiated from callback or not.
+ bool xrunListenerAdded[2];
+ bool disconnectListenerAdded[2];
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; procId[0] = 0; procId[1] = 0; xrun[0] = false; xrun[1] = false; xrunListenerAdded[0] = false; xrunListenerAdded[1] = false; disconnectListenerAdded[0] = false; disconnectListenerAdded[1] = false; }
};
RtApiCore:: RtApiCore()
OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
if ( result != noErr ) {
errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
}
#endif
}
OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
return 0;
}
OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
return 0;
}
result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
return 0;
}
if ( id == deviceList[i] ) return i;
errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return 0;
}
OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
return 0;
}
result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_SYSTEM_ERROR );
return 0;
}
if ( id == deviceList[i] ) return i;
errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return 0;
}
unsigned int nDevices = getDeviceCount();
if ( nDevices == 0 ) {
errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
+ error( RTAUDIO_INVALID_USE );
return info;
}
if ( device >= nDevices ) {
errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
+ error( RTAUDIO_INVALID_USE );
return info;
}
0, NULL, &dataSize, (void *) &deviceList );
if ( result != noErr ) {
errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != noErr ) {
errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != noErr ) {
errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != noErr || dataSize == 0 ) {
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
bufferList = (AudioBufferList *) malloc( dataSize );
if ( bufferList == NULL ) {
errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
free( bufferList );
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != noErr || dataSize == 0 ) {
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
bufferList = (AudioBufferList *) malloc( dataSize );
if ( bufferList == NULL ) {
errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
free( bufferList );
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != kAudioHardwareNoError || dataSize == 0 ) {
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( result != kAudioHardwareNoError ) {
errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( info.sampleRates.size() == 0 ) {
errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
else {
errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";
errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
}
}
}
if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )
- // Only one callback procedure per device.
+ // Only one callback procedure and property listener per device.
stream_.mode = DUPLEX;
else {
#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
stream_.mode = DUPLEX;
else
stream_.mode = mode;
- }
- // Setup the device property listener for over/underload.
- property.mSelector = kAudioDeviceProcessorOverload;
- property.mScope = kAudioObjectPropertyScopeGlobal;
- result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
+ // Setup the device property listener for over/underload.
+ property.mSelector = kAudioDeviceProcessorOverload;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error setting xrun listener for device (" << device << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error setting xrun listener for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ handle->xrunListenerAdded[mode] = true;
- // Setup a listener to detect a possible device disconnect.
- property.mSelector = kAudioDevicePropertyDeviceIsAlive;
- result = AudioObjectAddPropertyListener( id , &property, disconnectListener, (void *) &stream_.callbackInfo );
- if ( result != noErr ) {
- AudioObjectRemovePropertyListener( id, &property, xrunListener, (void *) handle );
- errorStream_ << "RtApiCore::probeDeviceOpen: system error setting disconnect listener for device (" << device << ").";
- errorText_ = errorStream_.str();
- goto error;
+ // Setup a listener to detect a possible device disconnect.
+ property.mSelector = kAudioDevicePropertyDeviceIsAlive;
+ result = AudioObjectAddPropertyListener( id , &property, disconnectListener, (void *) &stream_.callbackInfo );
+ if ( result != noErr ) {
+ AudioObjectRemovePropertyListener( id, &property, xrunListener, (void *) handle );
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error setting disconnect listener for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ handle->disconnectListenerAdded[mode] = true;
}
return SUCCESS;
error:
- if ( handle ) {
- pthread_cond_destroy( &handle->condition );
- delete handle;
- 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;
- }
-
- clearStreamInfo();
- //stream_.state = STREAM_CLOSED;
+ closeStream(); // this should safely clear out procedures, listeners and memory, even for duplex stream
return FAILURE;
}
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiCore::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return;
}
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if (handle) {
+ if ( handle ) {
AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
- property.mSelector = kAudioDeviceProcessorOverload;
- if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing xrun property listener!";
- error( RtAudioError::WARNING );
+ if ( handle->xrunListenerAdded[0] ) {
+ property.mSelector = kAudioDeviceProcessorOverload;
+ if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing xrun property listener!";
+ error( RTAUDIO_WARNING );
+ }
}
- property.mSelector = kAudioDevicePropertyDeviceIsAlive;
- if (AudioObjectRemovePropertyListener( handle->id[0], &property, disconnectListener, (void *) &stream_.callbackInfo ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing disconnect property listener!";
- error( RtAudioError::WARNING );
+ if ( handle->disconnectListenerAdded[0] ) {
+ property.mSelector = kAudioDevicePropertyDeviceIsAlive;
+ if (AudioObjectRemovePropertyListener( handle->id[0], &property, disconnectListener, (void *) &stream_.callbackInfo ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing disconnect property listener!";
+ error( RTAUDIO_WARNING );
+ }
}
- }
- if ( stream_.state == STREAM_RUNNING )
- AudioDeviceStop( handle->id[0], callbackHandler );
+
#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
-#else
- // deprecated in favor of AudioDeviceDestroyIOProcID()
- AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
+ if ( handle->procId[0] ) {
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[0], handle-procId[0] );
+ AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
+ }
+#else // deprecated behaviour
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[0], callbackHandler );
+ AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
#endif
+ }
+ }
}
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
- if (handle) {
+ if ( handle ) {
AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
- property.mSelector = kAudioDeviceProcessorOverload;
- if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing xrun property listener!";
- error( RtAudioError::WARNING );
+ if ( handle->xrunListenerAdded[1] ) {
+ property.mSelector = kAudioDeviceProcessorOverload;
+ if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing xrun property listener!";
+ error( RTAUDIO_WARNING );
+ }
}
- property.mSelector = kAudioDevicePropertyDeviceIsAlive;
- if (AudioObjectRemovePropertyListener( handle->id[1], &property, disconnectListener, (void *) &stream_.callbackInfo ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing disconnect property listener!";
- error( RtAudioError::WARNING );
+
+ if ( handle->disconnectListenerAdded[0] ) {
+ property.mSelector = kAudioDevicePropertyDeviceIsAlive;
+ if (AudioObjectRemovePropertyListener( handle->id[1], &property, disconnectListener, (void *) &stream_.callbackInfo ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing disconnect property listener!";
+ error( RTAUDIO_WARNING );
+ }
}
- }
- if ( stream_.state == STREAM_RUNNING )
- AudioDeviceStop( handle->id[1], callbackHandler );
+
#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
-#else
- // deprecated in favor of AudioDeviceDestroyIOProcID()
- AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
+ if ( handle->procId[1] ) {
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[1], handle->procId[1] );
+ AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
+ }
+#else // deprecated behaviour
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[1], callbackHandler );
+ AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
#endif
+ }
}
for ( int i=0; i<2; i++ ) {
CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
if ( info->deviceDisconnected ) {
errorText_ = "RtApiCore: the stream device was disconnected (and closed)!";
- error( RtAudioError::DEVICE_DISCONNECT );
+ error( RTAUDIO_DEVICE_DISCONNECT );
}
clearStreamInfo();
//stream_.state = STREAM_CLOSED;
}
-//void RtApiCore :: startStream( void )
-RtAudioError::Type RtApiCore :: startStream( void )
+RtAudioErrorType RtApiCore :: startStream( void )
{
- //verifyStream();
if ( stream_.state != STREAM_STOPPED ) {
if ( stream_.state == STREAM_RUNNING )
errorText_ = "RtApiCore::startStream(): the stream is already running!";
else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED )
errorText_ = "RtApiCore::startStream(): the stream is stopping or closed!";
- return error( RtAudioError::WARNING );
- //return;
+ return error( RTAUDIO_WARNING );
}
/*
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- result = AudioDeviceStart( handle->id[0], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceStart( handle->id[0], handle->procId[0] );
+#else // deprecated behaviour
+ result = AudioDeviceStart( handle->id[0], callbackHandler );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";
errorText_ = errorStream_.str();
bufferBytes = stream_.nUserChannels[1] * stream_.bufferSize * formatBytes( stream_.userFormat );
memset( stream_.userBuffer[1], 0, bufferBytes * sizeof(char) );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceStart( handle->id[1], handle->procId[1] );
+#else // deprecated behaviour
result = AudioDeviceStart( handle->id[1], callbackHandler );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";
errorText_ = errorStream_.str();
}
}
- // set stream time to zero?
handle->drainCounter = 0;
handle->internalDrain = false;
stream_.state = STREAM_RUNNING;
unlock:
- if ( result == noErr ) return RtAudioError::NO_ERROR;
- return error( RtAudioError::SYSTEM_ERROR );
+ if ( result == noErr ) return RTAUDIO_NO_ERROR;
+ return error( RTAUDIO_SYSTEM_ERROR );
}
-//void RtApiCore :: stopStream( void )
-RtAudioError::Type RtApiCore :: stopStream( void )
+RtAudioErrorType RtApiCore :: stopStream( void )
{
- //verifyStream();
if ( stream_.state != STREAM_RUNNING && stream_.state != STREAM_STOPPING ) {
if ( stream_.state == STREAM_STOPPED )
errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
else if ( stream_.state == STREAM_CLOSED )
errorText_ = "RtApiCore::stopStream(): the stream is closed!";
- return error( RtAudioError::WARNING );
- //return;
+ return error( RTAUDIO_WARNING );
}
OSStatus result = noErr;
pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
}
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceStop( handle->id[0], handle->procId[0] );
+#else
result = AudioDeviceStop( handle->id[0], callbackHandler );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";
errorText_ = errorStream_.str();
}
if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
-
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceStop( handle->id[1], handle->procId[1] );
+#else
result = AudioDeviceStop( handle->id[1], callbackHandler );
+#endif
if ( result != noErr ) {
errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";
errorText_ = errorStream_.str();
stream_.state = STREAM_STOPPED;
unlock:
- if ( result == noErr ) return RtAudioError::NO_ERROR;
- return error( RtAudioError::SYSTEM_ERROR );
+ if ( result == noErr ) return RTAUDIO_NO_ERROR;
+ return error( RTAUDIO_SYSTEM_ERROR );
}
-//void RtApiCore :: abortStream( void )
-RtAudioError::Type RtApiCore :: abortStream( void )
+RtAudioErrorType RtApiCore :: abortStream( void )
{
- //verifyStream();
if ( stream_.state != STREAM_RUNNING ) {
if ( stream_.state == STREAM_STOPPED )
errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED )
errorText_ = "RtApiCore::abortStream(): the stream is stopping or closed!";
- return error( RtAudioError::WARNING );
+ return error( RTAUDIO_WARNING );
//return;
}
if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return FAILURE;
}
unlock:
// Make sure to only tick duplex stream time once if using two devices
- if ( stream_.mode != DUPLEX || (stream_.mode == DUPLEX && handle->id[0] != handle->id[1] && deviceId == handle->id[0] ) )
- RtApi::tickStreamTime();
+ if ( stream_.mode == DUPLEX ) {
+ if ( handle->id[0] == handle->id[1] ) // same device, only one callback
+ RtApi::tickStreamTime();
+ else if ( deviceId == handle->id[0] )
+ RtApi::tickStreamTime(); // two devices, only tick on the output callback
+ } else
+ RtApi::tickStreamTime(); // input or output stream only
return SUCCESS;
}
#if defined(__UNIX_JACK__)
// JACK is a low-latency audio server, originally written for the
-// GNU/Linux operating system and now also ported to OS-X. It can
-// connect a number of different applications to an audio device, as
-// well as allowing them to share audio between themselves.
+// GNU/Linux operating system and now also ported to OS-X and
+// Windows. It can connect a number of different applications to an
+// audio device, as well as allowing them to share audio between
+// themselves.
//
// When using JACK with RtAudio, "devices" refer to JACK clients that
// have ports connected to the server. The JACK server is typically
jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
if ( device >= nDevices ) {
jack_client_close( client );
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
+ error( RTAUDIO_INVALID_USE );
return info;
}
if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
jack_client_close(client);
errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return info;
}
CallbackInfo *info = (CallbackInfo *) ptr;
RtApiJack *object = (RtApiJack *) info->object;
+ info->deviceDisconnected = true;
object->closeStream();
-
pthread_exit( NULL );
}
+
static void jackShutdown( void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;
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;
}
static int jackXrun( void *infoPointer )
client = jack_client_open( "RtApiJack", jackoptions, status );
if ( client == 0 ) {
errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return FAILURE;
}
}
{
if ( stream_.state == STREAM_CLOSED ) {
errorText_ = "RtApiJack::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return;
}
JackHandle *handle = (JackHandle *) stream_.apiHandle;
if ( handle ) {
-
if ( stream_.state == STREAM_RUNNING )
jack_deactivate( handle->client );
stream_.apiHandle = 0;
}
+ CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+ if ( info->deviceDisconnected ) {
+ errorText_ = "RtApiJack: the Jack server is shutting down this client ... stream stopped and closed!";
+ error( RTAUDIO_DEVICE_DISCONNECT );
+ }
+
for ( int i=0; i<2; i++ ) {
if ( stream_.userBuffer[i] ) {
free( stream_.userBuffer[i] );
stream_.deviceBuffer = 0;
}
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
+ clearStreamInfo();
+ //stream_.mode = UNINITIALIZED;
+ //stream_.state = STREAM_CLOSED;
}
-void RtApiJack :: startStream( void )
+RtAudioErrorType RtApiJack :: startStream( void )
{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiJack::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
+ if ( stream_.state != STREAM_STOPPED ) {
+ if ( stream_.state == STREAM_RUNNING )
+ errorText_ = "RtApiJack::startStream(): the stream is already running!";
+ else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED )
+ errorText_ = "RtApiJack::startStream(): the stream is stopping or closed!";
+ return error( RTAUDIO_WARNING );
}
+ /*
#if defined( HAVE_GETTIMEOFDAY )
gettimeofday( &stream_.lastTickTimestamp, NULL );
#endif
+ */
JackHandle *handle = (JackHandle *) stream_.apiHandle;
int result = jack_activate( handle->client );
stream_.state = STREAM_RUNNING;
unlock:
- if ( result == 0 ) return;
- error( RtAudioError::SYSTEM_ERROR );
+ if ( result == 0 ) return RTAUDIO_NO_ERROR;
+ return error( RTAUDIO_SYSTEM_ERROR );
}
-void RtApiJack :: stopStream( void )
+RtAudioErrorType RtApiJack :: stopStream( void )
{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
+ if ( stream_.state != STREAM_RUNNING && stream_.state != STREAM_STOPPING ) {
+ if ( stream_.state == STREAM_STOPPED )
+ errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
+ else if ( stream_.state == STREAM_CLOSED )
+ errorText_ = "RtApiJack::stopStream(): the stream is closed!";
+ return error( RTAUDIO_WARNING );
}
JackHandle *handle = (JackHandle *) stream_.apiHandle;
jack_deactivate( handle->client );
stream_.state = STREAM_STOPPED;
+ return RTAUDIO_NO_ERROR;
}
-void RtApiJack :: abortStream( void )
+RtAudioErrorType RtApiJack :: abortStream( void )
{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
+ if ( stream_.state != STREAM_RUNNING ) {
+ if ( stream_.state == STREAM_STOPPED )
+ errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
+ else if ( stream_.state == STREAM_STOPPING || stream_.state == STREAM_CLOSED )
+ errorText_ = "RtApiJack::abortStream(): the stream is stopping or closed!";
+ return error( RTAUDIO_WARNING );
}
JackHandle *handle = (JackHandle *) stream_.apiHandle;
handle->drainCounter = 2;
- stopStream();
+ return stopStream();
}
// This function will be called by a spawned thread when the user
{
if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
+ errorText_ = "RtApiJack::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RTAUDIO_WARNING );
return FAILURE;
}
if ( stream_.bufferSize != nframes ) {
- errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
- error( RtAudioError::WARNING );
+ errorText_ = "RtApiJack::callbackEvent(): the JACK buffer size has changed ... cannot process!";
+ error( RTAUDIO_WARNING );
return FAILURE;
}
stream_.state = STREAM_STOPPING;
if ( handle->internalDrain == true )
pthread_create( &threadId, NULL, jackStopStream, info );
- else
+ else // external call to stopStream()
pthread_cond_signal( &handle->condition );
return SUCCESS;
}
stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
- if ( pah && pah->s_play ) {
- int pa_error;
- if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
+ if ( pah } {
+ pah->runnable = false;
+ if ( pah->s_play ) {
+ int pa_error;
+ if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
}
}
stream_.state = STREAM_STOPPED;
MUTEX_LOCK( &stream_.mutex );
- if ( pah && pah->s_play ) {
- int pa_error;
- if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
+ if ( pah ) {
+ pah->runnable = false;
+ if ( pah->s_play ) {
+ int pa_error;
+ if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
}
}
// This method can be modified to control the behavior of error
// message printing.
-//void RtApi :: error( RtAudioError::Type type )
-RtAudioError::Type RtApi :: error( RtAudioError::Type type )
+RtAudioErrorType RtApi :: error( RtAudioErrorType type )
{
errorStream_.str(""); // clear the ostringstream to avoid repeated messages
// Don't output warnings if showWarnings_ is false
- if ( type == RtAudioError::WARNING && showWarnings_ == false ) return type;
+ if ( type == RTAUDIO_WARNING && showWarnings_ == false ) return type;
if ( errorCallback_ ) {
const std::string errorMessage = errorText_;
stream_.callbackInfo.callback = 0;
stream_.callbackInfo.userData = 0;
stream_.callbackInfo.isRunning = false;
- //stream_.callbackInfo.errorCallback = 0;
+ stream_.callbackInfo.deviceDisconnected = false;
for ( int i=0; i<2; i++ ) {
stream_.device[i] = 11111;
stream_.doConvertBuffer[i] = false;
return 1;
errorText_ = "RtApi::formatBytes: undefined format.";
- error( RtAudioError::WARNING );
+ error( RTAUDIO_WARNING );
return 0;
}