diff --git a/include/audio.hpp b/include/audio.hpp index fc116da9..558b3125 100644 --- a/include/audio.hpp +++ b/include/audio.hpp @@ -73,9 +73,6 @@ Methods throw `rack::Exception` if the driver API has an exception. struct Device { std::set subscribed; virtual ~Device() {} - // Called by Driver::subscribe(). - void subscribe(Port* port); - void unsubscribe(Port* port); virtual std::string getName() { return ""; @@ -113,6 +110,10 @@ struct Device { /** Sets the block size of the device, re-opening it if needed. */ virtual void setBlockSize(int blockSize) {} + // Called by Driver::subscribe(). + virtual void subscribe(Port* port); + virtual void unsubscribe(Port* port); + // Called by this Device class, forwards to subscribed Ports. void processBuffer(const float* input, int inputStride, float* output, int outputStride, int frames); void onStartStream(); diff --git a/src/rtaudio.cpp b/src/rtaudio.cpp index 4d3144a1..bcb08971 100644 --- a/src/rtaudio.cpp +++ b/src/rtaudio.cpp @@ -1,5 +1,6 @@ #include #include +#include #pragma GCC diagnostic push #ifndef __clang__ @@ -42,6 +43,8 @@ struct RtAudioDevice : audio::Device { RtAudio::StreamOptions options; int blockSize = 0; float sampleRate = 0; + /** Ensures that ports do not subscribe/unsubscribe while processBuffer() is called. */ + std::mutex processMutex; RtAudioDevice(RtAudio::Api api, int deviceId) { this->api = api; @@ -209,18 +212,30 @@ struct RtAudioDevice : audio::Device { openStream(); } + void subscribe(audio::Port* port) override { + std::lock_guard lock(processMutex); + Device::subscribe(port); + } + + void unsubscribe(audio::Port* port) override { + std::lock_guard lock(processMutex); + Device::unsubscribe(port); + } + static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) { // fprintf(stderr, "."); // fflush(stderr); - RtAudioDevice* device = (RtAudioDevice*) userData; - assert(device); + RtAudioDevice* that = (RtAudioDevice*) userData; + assert(that); + + std::lock_guard lock(that->processMutex); system::setThreadName("RtAudio"); - int inputStride = device->getNumInputs(); - int outputStride = device->getNumOutputs(); - device->processBuffer((const float*) inputBuffer, inputStride, (float*) outputBuffer, outputStride, nFrames); + int inputStride = that->getNumInputs(); + int outputStride = that->getNumOutputs(); + that->processBuffer((const float*) inputBuffer, inputStride, (float*) outputBuffer, outputStride, nFrames); return 0; } };