Browse Source

RtAudio: handle buffer size changes in JACK driver

tags/v1.9.11
falkTX 6 years ago
parent
commit
7c16b0db07
3 changed files with 84 additions and 11 deletions
  1. +32
    -3
      source/backend/engine/CarlaEngineRtAudio.cpp
  2. +40
    -6
      source/modules/rtaudio/RtAudio.cpp
  3. +12
    -2
      source/modules/rtaudio/RtAudio.h

+ 32
- 3
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -286,7 +286,8 @@ public:
fAudio.openStream(oParams.nChannels > 0 ? &oParams : nullptr, fAudio.openStream(oParams.nChannels > 0 ? &oParams : nullptr,
iParams.nChannels > 0 ? &iParams : nullptr, iParams.nChannels > 0 ? &iParams : nullptr,
RTAUDIO_FLOAT32, pData->options.audioSampleRate, &bufferFrames, RTAUDIO_FLOAT32, pData->options.audioSampleRate, &bufferFrames,
carla_rtaudio_process_callback, this, &rtOptions);
carla_rtaudio_process_callback, this, &rtOptions,
carla_rtaudio_buffer_size_callback);
} }
catch (const RtAudioError& e) { catch (const RtAudioError& e) {
setLastError(e.what()); setLastError(e.what());
@@ -592,8 +593,7 @@ protected:
/* */ float* const outsPtr = (float*)outputBuffer; /* */ float* const outsPtr = (float*)outputBuffer;


// assert rtaudio buffers // assert rtaudio buffers
CARLA_SAFE_ASSERT_RETURN(outputBuffer != nullptr,);
CARLA_SAFE_ASSERT_RETURN(pData->bufferSize == nframes,);
CARLA_SAFE_ASSERT_RETURN(outputBuffer != nullptr,);


// set rtaudio buffers as non-interleaved // set rtaudio buffers as non-interleaved
const float* inBuf[fAudioInCount]; const float* inBuf[fAudioInCount];
@@ -601,6 +601,7 @@ protected:


if (fAudioInterleaved) if (fAudioInterleaved)
{ {
// FIXME - this looks completely wrong!
float* inBuf2[fAudioInCount]; float* inBuf2[fAudioInCount];


for (uint i=0, count=fAudioInCount; i<count; ++i) for (uint i=0, count=fAudioInCount; i<count; ++i)
@@ -755,6 +756,28 @@ protected:
(void)streamTime; (void)status; (void)streamTime; (void)status;
} }


void handleBufferSizeCallback(const uint newBufferSize)
{
carla_stdout("bufferSize callback %u %u", pData->bufferSize, newBufferSize);
if (pData->bufferSize == newBufferSize)
return;

if (fAudioInCount > 0)
{
delete[] fAudioIntBufIn;
fAudioIntBufIn = new float[fAudioInCount*newBufferSize];
}

if (fAudioOutCount > 0)
{
delete[] fAudioIntBufOut;
fAudioIntBufOut = new float[fAudioOutCount*newBufferSize];
}

pData->bufferSize = newBufferSize;
bufferSizeChanged(newBufferSize);
}

void handleMidiCallback(double timeStamp, std::vector<uchar>* const message) void handleMidiCallback(double timeStamp, std::vector<uchar>* const message)
{ {
const size_t messageSize(message->size()); const size_t messageSize(message->size());
@@ -1056,6 +1079,12 @@ private:
return 0; return 0;
} }


static bool carla_rtaudio_buffer_size_callback(unsigned int bufferSize, void* userData)
{
handlePtr->handleBufferSizeCallback(bufferSize);
return true;
}

static void carla_rtmidi_callback(double timeStamp, std::vector<uchar>* message, void* userData) static void carla_rtmidi_callback(double timeStamp, std::vector<uchar>* message, void* userData)
{ {
handlePtr->handleMidiCallback(timeStamp, message); handlePtr->handleMidiCallback(timeStamp, message);


+ 40
- 6
source/modules/rtaudio/RtAudio.cpp View File

@@ -222,11 +222,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
unsigned int *bufferFrames, unsigned int *bufferFrames,
RtAudioCallback callback, void *userData, RtAudioCallback callback, void *userData,
RtAudio::StreamOptions *options, RtAudio::StreamOptions *options,
RtAudioBufferSizeCallback bufSizeCallback,
RtAudioErrorCallback errorCallback ) RtAudioErrorCallback errorCallback )
{ {
return rtapi_->openStream( outputParameters, inputParameters, format, return rtapi_->openStream( outputParameters, inputParameters, format,
sampleRate, bufferFrames, callback, sampleRate, bufferFrames, callback,
userData, options, errorCallback );
userData, options, bufSizeCallback, errorCallback );
} }


// *************************************************** // // *************************************************** //
@@ -259,6 +260,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,
unsigned int *bufferFrames, unsigned int *bufferFrames,
RtAudioCallback callback, void *userData, RtAudioCallback callback, void *userData,
RtAudio::StreamOptions *options, RtAudio::StreamOptions *options,
RtAudioBufferSizeCallback bufSizeCallback,
RtAudioErrorCallback errorCallback ) RtAudioErrorCallback errorCallback )
{ {
if ( stream_.state != STREAM_CLOSED ) { if ( stream_.state != STREAM_CLOSED ) {
@@ -340,6 +342,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams,


stream_.callbackInfo.callback = (void *) callback; stream_.callbackInfo.callback = (void *) callback;
stream_.callbackInfo.userData = userData; stream_.callbackInfo.userData = userData;
stream_.callbackInfo.bufSizeCallback = (void *) bufSizeCallback;
stream_.callbackInfo.errorCallback = (void *) errorCallback; stream_.callbackInfo.errorCallback = (void *) errorCallback;


if ( options ) options->numberOfBuffers = stream_.nBuffers; if ( options ) options->numberOfBuffers = stream_.nBuffers;
@@ -1983,6 +1986,16 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
return devInfo[device]; return devInfo[device];
} }


static int jackBufferSizeHandler( jack_nframes_t nframes, void *infoPointer )
{
CallbackInfo *info = (CallbackInfo *) infoPointer;

RtApiJack *object = (RtApiJack *) info->object;
if ( object->bufferSizeEvent( (unsigned long) nframes ) == false ) return 1;

return 0;
}

static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
{ {
CallbackInfo *info = (CallbackInfo *) infoPointer; CallbackInfo *info = (CallbackInfo *) infoPointer;
@@ -2134,7 +2147,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne


// Allocate necessary internal buffers. // Allocate necessary internal buffers.
unsigned long bufferBytes; 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 ); stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
if ( stream_.userBuffer[mode] == NULL ) { if ( stream_.userBuffer[mode] == NULL ) {
errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory."; errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";
@@ -2155,7 +2168,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
} }


if ( makeBuffer ) { if ( makeBuffer ) {
bufferBytes *= *bufferSize;
bufferBytes *= 8192;
if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
if ( stream_.deviceBuffer == NULL ) { if ( stream_.deviceBuffer == NULL ) {
@@ -2182,6 +2195,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
stream_.mode = DUPLEX; stream_.mode = DUPLEX;
else { else {
stream_.mode = mode; stream_.mode = mode;
jackbridge_set_buffer_size_callback( handle->client, jackBufferSizeHandler, (void *) &stream_.callbackInfo );
jackbridge_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); jackbridge_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
jackbridge_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle ); jackbridge_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle );
jackbridge_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); jackbridge_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
@@ -2419,8 +2433,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
error( RtAudioError::WARNING ); error( RtAudioError::WARNING );
return FAILURE; 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 ); error( RtAudioError::WARNING );
return FAILURE; return FAILURE;
} }
@@ -2454,7 +2468,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
handle->xrun[1] = false; handle->xrun[1] = false;
} }
int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
stream_.bufferSize, streamTime, status, info->userData );
nframes, streamTime, status, info->userData );
if ( cbReturnValue == 2 ) { if ( cbReturnValue == 2 ) {
stream_.state = STREAM_STOPPING; stream_.state = STREAM_STOPPING;
handle->drainCounter = 2; handle->drainCounter = 2;
@@ -2524,6 +2538,26 @@ bool RtApiJack :: callbackEvent( unsigned long nframes )
RtApi::tickStreamTime(); RtApi::tickStreamTime();
return SUCCESS; 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__ *********************// //******************** End of __UNIX_JACK__ *********************//
#endif #endif




+ 12
- 2
source/modules/rtaudio/RtAudio.h View File

@@ -246,6 +246,9 @@ class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error
*/ */
typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText ); 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. // RtAudio class declaration.
@@ -494,7 +497,9 @@ class RTAUDIO_DLL_PUBLIC RtAudio
RtAudio::StreamParameters *inputParameters, RtAudio::StreamParameters *inputParameters,
RtAudioFormat format, unsigned int sampleRate, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback, unsigned int *bufferFrames, RtAudioCallback callback,
void *userData = NULL, RtAudio::StreamOptions *options = NULL, 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. //! A function that closes a stream and frees any associated stream memory.
/*! /*!
@@ -611,6 +616,7 @@ struct CallbackInfo {
ThreadHandle thread; ThreadHandle thread;
void *callback; void *callback;
void *userData; void *userData;
void *bufSizeCallback;
void *errorCallback; void *errorCallback;
void *apiInfo; // void pointer for API specific callback information void *apiInfo; // void pointer for API specific callback information
bool isRunning; bool isRunning;
@@ -619,7 +625,7 @@ struct CallbackInfo {


// Default constructor. // Default constructor.
CallbackInfo() 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) {}
}; };


// **************************************************************** // // **************************************************************** //
@@ -688,6 +694,7 @@ public:
RtAudioFormat format, unsigned int sampleRate, RtAudioFormat format, unsigned int sampleRate,
unsigned int *bufferFrames, RtAudioCallback callback, unsigned int *bufferFrames, RtAudioCallback callback,
void *userData, RtAudio::StreamOptions *options, void *userData, RtAudio::StreamOptions *options,
RtAudioBufferSizeCallback bufSizeCallback,
RtAudioErrorCallback errorCallback ); RtAudioErrorCallback errorCallback );
virtual void closeStream( void ); virtual void closeStream( void );
virtual void startStream( void ) = 0; virtual void startStream( void ) = 0;
@@ -909,6 +916,9 @@ public:
// will most likely produce highly undesireable results! // will most likely produce highly undesireable results!
bool callbackEvent( unsigned long nframes ); bool callbackEvent( unsigned long nframes );


// Buffer size change callback
bool bufferSizeEvent( unsigned long nframes );

private: private:


bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,


Loading…
Cancel
Save