diff --git a/RtAudio.cpp b/RtAudio.cpp index 2ac2179..5fce9b2 100644 --- a/RtAudio.cpp +++ b/RtAudio.cpp @@ -76,7 +76,7 @@ const unsigned int RtApi::SAMPLE_RATES[] = { return s; } -#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) +#elif defined(__LINUX_ALSA__) || defined(__UNIX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) || defined(__HAIKU__) // pthread API #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) #define MUTEX_DESTROY(A) pthread_mutex_destroy(A) @@ -110,8 +110,8 @@ void RtAudio :: getCompiledApi( std::vector &apis ) #if defined(__LINUX_ALSA__) apis.push_back( LINUX_ALSA ); #endif -#if defined(__LINUX_PULSE__) - apis.push_back( LINUX_PULSE ); +#if defined(__UNIX_PULSE__) + apis.push_back( UNIX_PULSE ); #endif #if defined(__LINUX_OSS__) apis.push_back( LINUX_OSS ); @@ -147,8 +147,8 @@ void RtAudio :: openRtApi( RtAudio::Api api ) if ( api == LINUX_ALSA ) rtapi_ = new RtApiAlsa(); #endif -#if defined(__LINUX_PULSE__) - if ( api == LINUX_PULSE ) +#if defined(__UNIX_PULSE__) + if ( api == UNIX_PULSE ) rtapi_ = new RtApiPulse(); #endif #if defined(__LINUX_OSS__) @@ -222,11 +222,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, + RtAudioBufferSizeCallback bufSizeCallback, RtAudioErrorCallback errorCallback ) { return rtapi_->openStream( outputParameters, inputParameters, format, sampleRate, bufferFrames, callback, - userData, options, errorCallback ); + userData, options, bufSizeCallback, errorCallback ); } // *************************************************** // @@ -259,6 +260,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, + RtAudioBufferSizeCallback bufSizeCallback, RtAudioErrorCallback errorCallback ) { if ( stream_.state != STREAM_CLOSED ) { @@ -282,7 +284,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, return; } - if ( oParams == NULL && iParams == NULL ) { + if ( oParams == NULL && iParams == NULL && getCurrentApi() != RtAudio::RTAUDIO_DUMMY ) { errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!"; error( RtAudioError::INVALID_USE ); return; @@ -340,6 +342,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.userData = userData; + stream_.callbackInfo.bufSizeCallback = (void *) bufSizeCallback; stream_.callbackInfo.errorCallback = (void *) errorCallback; if ( options ) options->numberOfBuffers = stream_.nBuffers; @@ -1587,6 +1590,8 @@ static void *coreStopStream( void *ptr ) object->stopStream(); pthread_exit( NULL ); + + return NULL; } bool RtApiCore :: callbackEvent( AudioDeviceID deviceId, @@ -1925,7 +1930,7 @@ const char* RtApiCore :: getErrorCode( OSStatus code ) // devices are available (i.e., the JACK server is not running), a // stream cannot be opened. -#include +#include "jackbridge/JackBridge.hpp" #include #include @@ -1934,7 +1939,6 @@ const char* RtApiCore :: getErrorCode( OSStatus code ) struct JackHandle { jack_client_t *client; jack_port_t **ports[2]; - std::string deviceName[2]; bool xrun[2]; pthread_cond_t condition; int drainCounter; // Tracks callback counts when draining @@ -1944,17 +1948,9 @@ struct JackHandle { :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; } }; -#if !defined(__RTAUDIO_DEBUG__) -static void jackSilentError( const char * ) {}; -#endif - RtApiJack :: RtApiJack() :shouldAutoconnect_(true) { // Nothing to do here. -#if !defined(__RTAUDIO_DEBUG__) - // Turn off Jack's internal error reporting. - jack_set_error_function( &jackSilentError ); -#endif } RtApiJack :: ~RtApiJack() @@ -1964,128 +1960,40 @@ RtApiJack :: ~RtApiJack() unsigned int RtApiJack :: getDeviceCount( void ) { - // See if we can become a jack client. - jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption; - jack_status_t *status = NULL; - jack_client_t *client = jack_client_open( "RtApiJackCount", options, status ); - if ( client == 0 ) return 0; - - const char **ports; - std::string port, previousPort; - unsigned int nChannels = 0, nDevices = 0; - ports = jack_get_ports( client, NULL, NULL, 0 ); - if ( ports ) { - // Parse the port names up to the first colon (:). - size_t iColon = 0; - do { - port = (char *) ports[ nChannels ]; - iColon = port.find(":"); - if ( iColon != std::string::npos ) { - port = port.substr( 0, iColon + 1 ); - if ( port != previousPort ) { - nDevices++; - previousPort = port; - } - } - } while ( ports[++nChannels] ); - free( ports ); - } - - jack_client_close( client ); - return nDevices; + return 2; } RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) { - RtAudio::DeviceInfo info; - info.probed = false; + static RtAudio::DeviceInfo devInfo[3]; - jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption - jack_status_t *status = NULL; - jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status ); - if ( client == 0 ) { - errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!"; - error( RtAudioError::WARNING ); - return info; - } - - const char **ports; - std::string port, previousPort; - unsigned int nPorts = 0, nDevices = 0; - ports = jack_get_ports( client, NULL, NULL, 0 ); - if ( ports ) { - // Parse the port names up to the first colon (:). - size_t iColon = 0; - do { - port = (char *) ports[ nPorts ]; - iColon = port.find(":"); - if ( iColon != std::string::npos ) { - port = port.substr( 0, iColon ); - if ( port != previousPort ) { - if ( nDevices == device ) info.name = port; - nDevices++; - previousPort = port; - } - } - } while ( ports[++nPorts] ); - free( ports ); - } - - if ( device >= nDevices ) { - jack_client_close( client ); - errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; - error( RtAudioError::INVALID_USE ); - return info; - } - - // Get the current jack server sample rate. - info.sampleRates.clear(); - - info.preferredSampleRate = jack_get_sample_rate( client ); - info.sampleRates.push_back( info.preferredSampleRate ); - - // Count the available ports containing the client name as device - // channels. Jack "input ports" equal RtAudio output channels. - unsigned int nChannels = 0; - ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput ); - if ( ports ) { - while ( ports[ nChannels ] ) nChannels++; - free( ports ); - info.outputChannels = nChannels; - } - - // Jack "output ports" equal RtAudio input channels. - nChannels = 0; - ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput ); - if ( ports ) { - while ( ports[ nChannels ] ) nChannels++; - free( ports ); - info.inputChannels = nChannels; + if (! devInfo[0].probed) + { + devInfo[0].probed = devInfo[1].probed = true; + devInfo[0].outputChannels = devInfo[1].outputChannels = 2; + devInfo[0].inputChannels = devInfo[1].inputChannels = 2; + devInfo[0].duplexChannels = devInfo[1].duplexChannels = 2; + devInfo[0].isDefaultOutput = devInfo[1].isDefaultOutput = true; + devInfo[0].isDefaultInput = devInfo[1].isDefaultInput = true; + devInfo[0].nativeFormats = devInfo[1].nativeFormats = RTAUDIO_FLOAT32; + devInfo[0].name = "Auto-connect ON"; + devInfo[1].name = "Auto-connect OFF"; } - if ( info.outputChannels == 0 && info.inputChannels == 0 ) { - jack_client_close(client); - errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!"; - error( RtAudioError::WARNING ); - return info; - } + if (device > 2) + device = 2; - // If device opens for both playback and capture, we determine the channels. - if ( info.outputChannels > 0 && info.inputChannels > 0 ) - info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; + return devInfo[device]; +} - // Jack always uses 32-bit floats. - info.nativeFormats = RTAUDIO_FLOAT32; +static int jackBufferSizeHandler( jack_nframes_t nframes, void *infoPointer ) +{ + CallbackInfo *info = (CallbackInfo *) infoPointer; - // Jack doesn't provide default devices so we'll use the first available one. - if ( device == 0 && info.outputChannels > 0 ) - info.isDefaultOutput = true; - if ( device == 0 && info.inputChannels > 0 ) - info.isDefaultInput = true; + RtApiJack *object = (RtApiJack *) info->object; + if ( object->bufferSizeEvent( (unsigned long) nframes ) == false ) return 1; - jack_client_close(client); - info.probed = true; - return info; + return 0; } static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) @@ -2101,7 +2009,7 @@ static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) // This function will be called by a spawned thread when the Jack // 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. +// the jackbridge_deactivate() function (in closeStream()) will return. static void *jackCloseStream( void *ptr ) { CallbackInfo *info = (CallbackInfo *) ptr; @@ -2110,6 +2018,8 @@ static void *jackCloseStream( void *ptr ) object->closeStream(); pthread_exit( NULL ); + + return NULL; } static void jackShutdown( void *infoPointer ) { @@ -2139,7 +2049,7 @@ static int jackXrun( void *infoPointer ) } bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, - unsigned int firstChannel, unsigned int sampleRate, + unsigned int firstChannel, unsigned int, RtAudioFormat format, unsigned int *bufferSize, RtAudio::StreamOptions *options ) { @@ -2151,9 +2061,9 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption; jack_status_t *status = NULL; if ( options && !options->streamName.empty() ) - client = jack_client_open( options->streamName.c_str(), jackoptions, status ); + client = jackbridge_client_open( options->streamName.c_str(), jackoptions, status ); else - client = jack_client_open( "RtApiJack", jackoptions, status ); + client = jackbridge_client_open( "Carla", jackoptions, status ); if ( client == 0 ) { errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!"; error( RtAudioError::WARNING ); @@ -2165,75 +2075,24 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne client = handle->client; } - const char **ports; - std::string port, previousPort, deviceName; - unsigned int nPorts = 0, nDevices = 0; - ports = jack_get_ports( client, NULL, NULL, 0 ); - if ( ports ) { - // Parse the port names up to the first colon (:). - size_t iColon = 0; - do { - port = (char *) ports[ nPorts ]; - iColon = port.find(":"); - if ( iColon != std::string::npos ) { - port = port.substr( 0, iColon ); - if ( port != previousPort ) { - if ( nDevices == device ) deviceName = port; - nDevices++; - previousPort = port; - } - } - } while ( ports[++nPorts] ); - free( ports ); - } - - if ( device >= nDevices ) { - errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!"; - return FAILURE; - } - - // Count the available ports containing the client name as device - // channels. Jack "input ports" equal RtAudio output channels. - unsigned int nChannels = 0; - unsigned long flag = JackPortIsInput; - if ( mode == INPUT ) flag = JackPortIsOutput; - ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); - if ( ports ) { - while ( ports[ nChannels ] ) nChannels++; - free( ports ); - } - - // Compare the jack ports for specified client to the requested number of channels. - if ( nChannels < (channels + firstChannel) ) { - errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ")."; - errorText_ = errorStream_.str(); - return FAILURE; - } - // Check the jack server sample rate. - unsigned int jackRate = jack_get_sample_rate( client ); - if ( sampleRate != jackRate ) { - jack_client_close( client ); - errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ")."; - errorText_ = errorStream_.str(); - return FAILURE; - } - stream_.sampleRate = jackRate; + stream_.sampleRate = jackbridge_get_sample_rate( client ); // Get the latency of the JACK port. - ports = jack_get_ports( client, deviceName.c_str(), NULL, flag ); + const char **ports; + ports = jackbridge_get_ports( client, "system:", NULL, JackPortIsInput ); if ( ports[ firstChannel ] ) { // Added by Ge Wang jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency); // the range (usually the min and max are equal) jack_latency_range_t latrange; latrange.min = latrange.max = 0; // get the latency range - jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange ); + jackbridge_port_get_latency_range( jackbridge_port_by_name( client, ports[firstChannel] ), cbmode, &latrange ); // be optimistic, use the min! stream_.latency[mode] = latrange.min; - //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) ); + //stream_.latency[mode] = jack_port_get_latency( jackbridge_port_by_name( client, ports[ firstChannel ] ) ); } - free( ports ); + jackbridge_free( ports ); // The jack server always uses 32-bit floating-point data. stream_.deviceFormat[mode] = RTAUDIO_FLOAT32; @@ -2250,7 +2109,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne // Get the buffer size. The buffer size and number of buffers // (periods) is set when the jack server is started. - stream_.bufferSize = (int) jack_get_buffer_size( client ); + stream_.bufferSize = (int) jackbridge_get_buffer_size( client ); *bufferSize = stream_.bufferSize; stream_.nDeviceChannels[mode] = channels; @@ -2281,11 +2140,10 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.apiHandle = (void *) handle; handle->client = client; } - handle->deviceName[mode] = deviceName; // Allocate necessary internal buffers. unsigned long bufferBytes; - bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); + bufferBytes = stream_.nUserChannels[mode] * 8192 * formatBytes( stream_.userFormat ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); if ( stream_.userBuffer[mode] == NULL ) { errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory."; @@ -2306,7 +2164,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne } if ( makeBuffer ) { - bufferBytes *= *bufferSize; + bufferBytes *= 8192; if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); if ( stream_.deviceBuffer == NULL ) { @@ -2333,28 +2191,34 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne stream_.mode = DUPLEX; else { stream_.mode = mode; - jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); - jack_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle ); - jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); + jackbridge_set_buffer_size_callback( handle->client, jackBufferSizeHandler, (void *) &stream_.callbackInfo ); + jackbridge_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); + jackbridge_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle ); + jackbridge_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); } // Register our ports. char label[64]; if ( mode == OUTPUT ) { for ( unsigned int i=0; iports[0][i] = jack_port_register( handle->client, (const char *)label, + snprintf( label, 64, "audio-out%d", i+1 ); + handle->ports[0][i] = jackbridge_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); } } else { for ( unsigned int i=0; iports[1][i] = jack_port_register( handle->client, (const char *)label, + snprintf( label, 64, "audio-in%d", i+1 ); + handle->ports[1][i] = jackbridge_port_register( handle->client, (const char *)label, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); } } + // auto-connect-off "device" is at index 1 + shouldAutoconnect_ = (device != 1 && + std::getenv("LADISH_APP_NAME") == nullptr && + std::getenv("NSM_URL") == nullptr); + // Setup the buffer conversion information structure. We don't use // buffers to do channel offsets, so we override that parameter // here. @@ -2367,7 +2231,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne error: if ( handle ) { pthread_cond_destroy( &handle->condition ); - jack_client_close( handle->client ); + jackbridge_client_close( handle->client ); if ( handle->ports[0] ) free( handle->ports[0] ); if ( handle->ports[1] ) free( handle->ports[1] ); @@ -2403,9 +2267,9 @@ void RtApiJack :: closeStream( void ) if ( handle ) { if ( stream_.state == STREAM_RUNNING ) - jack_deactivate( handle->client ); + jackbridge_deactivate( handle->client ); - jack_client_close( handle->client ); + jackbridge_client_close( handle->client ); } if ( handle ) { @@ -2442,8 +2306,8 @@ void RtApiJack :: startStream( void ) } JackHandle *handle = (JackHandle *) stream_.apiHandle; - int result = jack_activate( handle->client ); - if ( result ) { + bool result = jackbridge_activate( handle->client ); + if ( ! result ) { errorText_ = "RtApiJack::startStream(): unable to activate JACK client!"; goto unlock; } @@ -2452,8 +2316,8 @@ void RtApiJack :: startStream( void ) // Get the list of available ports. if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) { - result = 1; - ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput); + result = false; + ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsInput); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!"; goto unlock; @@ -2463,21 +2327,21 @@ void RtApiJack :: startStream( void ) // allow the user to select particular channels of a device, we'll // just open the first "nChannels" ports with offset. for ( unsigned int i=0; iclient, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] ); - if ( result ) { - free( ports ); + result = jackbridge_connect( handle->client, jackbridge_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] ); + if ( ! result ) { + jackbridge_free( ports ); errorText_ = "RtApiJack::startStream(): error connecting output ports!"; goto unlock; } } - free(ports); + jackbridge_free(ports); } if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) { - result = 1; - ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput ); + result = false; + ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsOutput ); if ( ports == NULL) { errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!"; goto unlock; @@ -2485,16 +2349,16 @@ void RtApiJack :: startStream( void ) // Now make the port connections. See note above. for ( unsigned int i=0; iclient, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) ); - if ( result ) { - free( ports ); + result = jackbridge_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jackbridge_port_name( handle->ports[1][i] ) ); + if ( ! result ) { + jackbridge_free( ports ); errorText_ = "RtApiJack::startStream(): error connecting input ports!"; goto unlock; } } - free(ports); + jackbridge_free(ports); } handle->drainCounter = 0; @@ -2502,7 +2366,7 @@ void RtApiJack :: startStream( void ) stream_.state = STREAM_RUNNING; unlock: - if ( result == 0 ) return; + if ( result ) return; error( RtAudioError::SYSTEM_ERROR ); } @@ -2524,7 +2388,7 @@ void RtApiJack :: stopStream( void ) } } - jack_deactivate( handle->client ); + jackbridge_deactivate( handle->client ); stream_.state = STREAM_STOPPED; } @@ -2546,7 +2410,7 @@ void RtApiJack :: abortStream( void ) // This function will be called by a spawned thread when the user // callback function signals that the stream should be stopped or // aborted. It is necessary to handle it this way because the -// callbackEvent() function must return before the jack_deactivate() +// callbackEvent() function must return before the jackbridge_deactivate() // function will return. static void *jackStopStream( void *ptr ) { @@ -2555,6 +2419,8 @@ static void *jackStopStream( void *ptr ) object->stopStream(); pthread_exit( NULL ); + + return NULL; } bool RtApiJack :: callbackEvent( unsigned long nframes ) @@ -2565,8 +2431,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) error( RtAudioError::WARNING ); return FAILURE; } - if ( stream_.bufferSize != nframes ) { - errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!"; + if ( nframes > 8192 ) { + errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!"; error( RtAudioError::WARNING ); return FAILURE; } @@ -2600,7 +2466,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) handle->xrun[1] = false; } int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], - stream_.bufferSize, streamTime, status, info->userData ); + nframes, streamTime, status, info->userData ); if ( cbReturnValue == 2 ) { stream_.state = STREAM_STOPPING; handle->drainCounter = 2; @@ -2621,7 +2487,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) if ( handle->drainCounter > 1 ) { // write zeros to the output stream for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes ); memset( jackbuffer, 0, bufferBytes ); } @@ -2631,13 +2497,13 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] ); for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes ); } } else { // no buffer conversion for ( unsigned int i=0; iports[0][i], (jack_nframes_t) nframes ); + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes ); memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes ); } } @@ -2653,14 +2519,14 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) if ( stream_.doConvertBuffer[1] ) { for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes ); } convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] ); } else { // no buffer conversion for ( unsigned int i=0; iports[1][i], (jack_nframes_t) nframes ); + jackbuffer = (jack_default_audio_sample_t *) jackbridge_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes ); memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes ); } } @@ -2670,6 +2536,26 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) RtApi::tickStreamTime(); return SUCCESS; } + +bool RtApiJack :: bufferSizeEvent( unsigned long nframes ) +{ + 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 ); + return FAILURE; + } + if ( nframes > 8192 ) { + errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!"; + error( RtAudioError::WARNING ); + return FAILURE; + } + + CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; + + RtAudioBufferSizeCallback callback = (RtAudioBufferSizeCallback) info->bufSizeCallback; + return callback( nframes, info->userData ); +} //******************** End of __UNIX_JACK__ *********************// #endif @@ -2691,10 +2577,10 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) // on information found in // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html. -#include "asiosys.h" -#include "asio.h" -#include "iasiothiscallresolver.h" -#include "asiodrivers.h" +#include "asio.cpp" +#include "asiodrivers.cpp" +#include "asiolist.cpp" +#include "iasiothiscallresolver.cpp" #include static AsioDrivers drivers; @@ -5487,8 +5373,8 @@ bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned // two. This is a judgement call and a value of two is probably too // low for capture, but it should work for playback. int nBuffers = 0; - if ( options ) nBuffers = options->numberOfBuffers; if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2; + if ( options && options->numberOfBuffers > 0 ) nBuffers = options->numberOfBuffers; if ( nBuffers < 2 ) nBuffers = 3; // Check the lower range of the user-specified buffer size and set @@ -6795,7 +6681,9 @@ unsigned int RtApiAlsa :: getDeviceCount( void ) nDevices++; } nextcard: - snd_ctl_close( handle ); + if (result == 0) { + snd_ctl_close( handle ); + } snd_card_next( &card ); } @@ -8012,12 +7900,14 @@ static void *alsaCallbackHandler( void *ptr ) } pthread_exit( NULL ); + + return NULL; } //******************** End of __LINUX_ALSA__ *********************// #endif -#if defined(__LINUX_PULSE__) +#if defined(__UNIX_PULSE__) // Code written by Peter Meerwald, pmeerw@pmeerw.net // and Tristan Matthews. @@ -8092,6 +7982,8 @@ static void *pulseaudio_callback( void * user ) } pthread_exit( NULL ); + + return NULL; } void RtApiPulse::closeStream( void ) @@ -8502,7 +8394,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode, return FAILURE; } -//******************** End of __LINUX_PULSE__ *********************// +//******************** End of __UNIX_PULSE__ *********************// #endif #if defined(__LINUX_OSS__) @@ -9446,6 +9338,8 @@ static void *ossCallbackHandler( void *ptr ) } pthread_exit( NULL ); + + return NULL; } //******************** End of __LINUX_OSS__ *********************// diff --git a/RtAudio.h b/RtAudio.h index 34a2534..289e254 100644 --- a/RtAudio.h +++ b/RtAudio.h @@ -46,16 +46,7 @@ #define __RTAUDIO_H #define RTAUDIO_VERSION "5.0.0" - -#if defined _WIN32 || defined __CYGWIN__ - #define RTAUDIO_DLL_PUBLIC -#else - #if __GNUC__ >= 4 - #define RTAUDIO_DLL_PUBLIC __attribute__( (visibility( "default" )) ) - #else - #define RTAUDIO_DLL_PUBLIC - #endif -#endif +#define RTAUDIO_DLL_PUBLIC #include #include @@ -255,6 +246,9 @@ class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error */ typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText ); +//! RtAudio buffer size change callback. +typedef bool (*RtAudioBufferSizeCallback)( unsigned int bufferSize, void* userData ); + // **************************************************************** // // // RtAudio class declaration. @@ -278,8 +272,8 @@ class RTAUDIO_DLL_PUBLIC RtAudio enum Api { UNSPECIFIED, /*!< Search for a working compiled API. */ LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */ - LINUX_PULSE, /*!< The Linux PulseAudio API. */ LINUX_OSS, /*!< The Linux Open Sound System API. */ + UNIX_PULSE, /*!< The PulseAudio API. */ UNIX_JACK, /*!< The Jack Low-Latency Audio Server API. */ MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */ WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */ @@ -416,7 +410,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio ~RtAudio(); //! Returns the audio API specifier for the current instance of RtAudio. - RtAudio::Api getCurrentApi( void ); + RtAudio::Api getCurrentApi( void ) const; //! A public function that queries for the number of audio devices available. /*! @@ -503,7 +497,9 @@ class RTAUDIO_DLL_PUBLIC RtAudio RtAudio::StreamParameters *inputParameters, RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, - void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); + void *userData = NULL, RtAudio::StreamOptions *options = NULL, + RtAudioBufferSizeCallback bufSizeCallback = NULL, + RtAudioErrorCallback errorCallback = NULL ); //! A function that closes a stream and frees any associated stream memory. /*! @@ -597,7 +593,7 @@ class RTAUDIO_DLL_PUBLIC RtAudio typedef uintptr_t ThreadHandle; typedef CRITICAL_SECTION StreamMutex; -#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) +#elif defined(__LINUX_ALSA__) || defined(__UNIX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__) || defined(__HAIKU__) // Using pthread library for various flavors of unix. #include @@ -620,6 +616,7 @@ struct CallbackInfo { ThreadHandle thread; void *callback; void *userData; + void *bufSizeCallback; void *errorCallback; void *apiInfo; // void pointer for API specific callback information bool isRunning; @@ -628,7 +625,7 @@ struct CallbackInfo { // Default constructor. CallbackInfo() - :object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {} + :object(0), callback(0), userData(0), bufSizeCallback(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {} }; // **************************************************************** // @@ -687,7 +684,7 @@ public: RtApi(); virtual ~RtApi(); - virtual RtAudio::Api getCurrentApi( void ) = 0; + virtual RtAudio::Api getCurrentApi( void ) const = 0; virtual unsigned int getDeviceCount( void ) = 0; virtual RtAudio::DeviceInfo getDeviceInfo( unsigned int device ) = 0; virtual unsigned int getDefaultInputDevice( void ); @@ -697,6 +694,7 @@ public: RtAudioFormat format, unsigned int sampleRate, unsigned int *bufferFrames, RtAudioCallback callback, void *userData, RtAudio::StreamOptions *options, + RtAudioBufferSizeCallback bufSizeCallback, RtAudioErrorCallback errorCallback ); virtual void closeStream( void ); virtual void startStream( void ) = 0; @@ -836,7 +834,7 @@ protected: // // **************************************************************** // -inline RtAudio::Api RtAudio :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); } +inline RtAudio::Api RtAudio :: getCurrentApi( void ) const { return rtapi_->getCurrentApi(); } inline unsigned int RtAudio :: getDeviceCount( void ) { return rtapi_->getDeviceCount(); } inline RtAudio::DeviceInfo RtAudio :: getDeviceInfo( unsigned int device ) { return rtapi_->getDeviceInfo( device ); } inline unsigned int RtAudio :: getDefaultInputDevice( void ) { return rtapi_->getDefaultInputDevice(); } @@ -865,7 +863,7 @@ public: RtApiCore(); ~RtApiCore(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::MACOSX_CORE; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::MACOSX_CORE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); @@ -903,7 +901,7 @@ public: RtApiJack(); ~RtApiJack(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::UNIX_JACK; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::UNIX_JACK; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -918,6 +916,9 @@ public: // will most likely produce highly undesireable results! bool callbackEvent( unsigned long nframes ); + // Buffer size change callback + bool bufferSizeEvent( unsigned long nframes ); + private: bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, @@ -938,7 +939,7 @@ public: RtApiAsio(); ~RtApiAsio(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_ASIO; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_ASIO; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -974,7 +975,7 @@ public: RtApiDs(); ~RtApiDs(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_DS; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_DS; } unsigned int getDeviceCount( void ); unsigned int getDefaultOutputDevice( void ); unsigned int getDefaultInputDevice( void ); @@ -1015,7 +1016,7 @@ public: RtApiWasapi(); ~RtApiWasapi(); - RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::WINDOWS_WASAPI; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); unsigned int getDefaultOutputDevice( void ); @@ -1050,7 +1051,7 @@ public: RtApiAlsa(); ~RtApiAlsa(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_ALSA; } + RtAudio::Api getCurrentApi() const { return RtAudio::LINUX_ALSA; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -1076,13 +1077,13 @@ public: #endif -#if defined(__LINUX_PULSE__) +#if defined(__UNIX_PULSE__) class RtApiPulse: public RtApi { public: ~RtApiPulse(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_PULSE; } + RtAudio::Api getCurrentApi() const { return RtAudio::UNIX_PULSE; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -1116,7 +1117,7 @@ public: RtApiOss(); ~RtApiOss(); - RtAudio::Api getCurrentApi() { return RtAudio::LINUX_OSS; } + RtAudio::Api getCurrentApi() const { return RtAudio::LINUX_OSS; } unsigned int getDeviceCount( void ); RtAudio::DeviceInfo getDeviceInfo( unsigned int device ); void closeStream( void ); @@ -1147,7 +1148,7 @@ class RtApiDummy: public RtApi public: RtApiDummy() { errorText_ = "RtApiDummy: This class provides no functionality."; error( RtAudioError::WARNING ); } - RtAudio::Api getCurrentApi( void ) { return RtAudio::RTAUDIO_DUMMY; } + RtAudio::Api getCurrentApi( void ) const { return RtAudio::RTAUDIO_DUMMY; } unsigned int getDeviceCount( void ) { return 0; } RtAudio::DeviceInfo getDeviceInfo( unsigned int /*device*/ ) { RtAudio::DeviceInfo info; return info; } void closeStream( void ) {} diff --git a/include/asio.h b/include/asio.h index 8ec811f..656f681 100644 --- a/include/asio.h +++ b/include/asio.h @@ -3,11 +3,12 @@ /* Steinberg Audio Stream I/O API - (c) 1997 - 2005, Steinberg Media Technologies GmbH + (c) 1997 - 2013, Steinberg Media Technologies GmbH - ASIO Interface Specification v 2.1 + ASIO Interface Specification v 2.3 2005 - Added support for DSD sample data (in cooperation with Sony) + 2012 - Added support for drop out detection basic concept is an i/o synchronous double-buffer scheme: @@ -916,6 +917,7 @@ enum kAsioCanInputMeter, kAsioCanOutputGain, kAsioCanOutputMeter, + kAsioOptionalOne, // DSD support // The following extensions are required to allow switching @@ -923,6 +925,9 @@ enum kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ + // Extension for drop out detection + kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */ + kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */ }; typedef struct ASIOInputMonitor @@ -1003,6 +1008,14 @@ typedef struct ASIOIoFormat_s char future[512-sizeof(ASIOIoFormatType)]; } ASIOIoFormat; +// Extension for drop detection +// Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs +typedef struct ASIOInternalBufferInfo +{ + long inputSamples; // size of driver's internal input buffering which is included in getLatencies + long outputSamples; // size of driver's internal output buffering which is included in getLatencies +} ASIOInternalBufferInfo; + ASIOError ASIOOutputReady(void); /* Purpose: diff --git a/include/asiosys.h b/include/asiosys.h index 37f7a48..c974fc3 100644 --- a/include/asiosys.h +++ b/include/asiosys.h @@ -1,7 +1,7 @@ #ifndef __asiosys__ #define __asiosys__ - #ifdef WIN32 + #if defined(WIN32) || defined(_WIN64) #undef MAC #define PPC 0 #define WINDOWS 1 diff --git a/include/ginclude.h b/include/ginclude.h index b627dc2..8c609c7 100644 --- a/include/ginclude.h +++ b/include/ginclude.h @@ -8,7 +8,7 @@ // #define ASIO_BIG_ENDIAN 1 #define ASIO_CPU_MIPS 1 -#elif defined WIN32 +#elif defined(WIN32) || defined(_WIN64) #undef BEOS #undef MAC #undef SGI diff --git a/include/iasiodrv.h b/include/iasiodrv.h index 64d2dbb..860675c 100644 --- a/include/iasiodrv.h +++ b/include/iasiodrv.h @@ -1,3 +1,4 @@ +#pragma once #include "asiosys.h" #include "asio.h"