@@ -1,6 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include <vector> | #include <vector> | ||||
#include <set> | #include <set> | ||||
#include <mutex> | |||||
#include <jansson.h> | #include <jansson.h> | ||||
@@ -72,6 +73,9 @@ Methods throw `rack::Exception` if the driver API has an exception. | |||||
*/ | */ | ||||
struct Device { | struct Device { | ||||
std::set<Port*> subscribed; | std::set<Port*> subscribed; | ||||
/** Ensures that ports do not subscribe/unsubscribe while processBuffer() is called. */ | |||||
std::mutex processMutex; | |||||
virtual ~Device() {} | virtual ~Device() {} | ||||
virtual std::string getName() { | virtual std::string getName() { | ||||
@@ -19,10 +19,12 @@ static std::vector<std::pair<int, Driver*>> drivers; | |||||
//////////////////// | //////////////////// | ||||
void Device::subscribe(Port* port) { | void Device::subscribe(Port* port) { | ||||
std::lock_guard<std::mutex> lock(processMutex); | |||||
subscribed.insert(port); | subscribed.insert(port); | ||||
} | } | ||||
void Device::unsubscribe(Port* port) { | void Device::unsubscribe(Port* port) { | ||||
std::lock_guard<std::mutex> lock(processMutex); | |||||
auto it = subscribed.find(port); | auto it = subscribed.find(port); | ||||
if (it != subscribed.end()) | if (it != subscribed.end()) | ||||
subscribed.erase(it); | subscribed.erase(it); | ||||
@@ -32,6 +34,7 @@ void Device::processBuffer(const float* input, int inputStride, float* output, i | |||||
// Zero output in case no Port writes values to it. | // Zero output in case no Port writes values to it. | ||||
std::memset(output, 0, frames * outputStride * sizeof(float)); | std::memset(output, 0, frames * outputStride * sizeof(float)); | ||||
std::lock_guard<std::mutex> lock(processMutex); | |||||
for (Port* port : subscribed) { | for (Port* port : subscribed) { | ||||
// Setting the thread context should probably be the responsibility of Port, but because processInput() etc are overridden, this is the only good place for it. | // Setting the thread context should probably be the responsibility of Port, but because processInput() etc are overridden, this is the only good place for it. | ||||
contextSet(port->context); | contextSet(port->context); | ||||
@@ -1,6 +1,5 @@ | |||||
#include <map> | #include <map> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <mutex> | |||||
#pragma GCC diagnostic push | #pragma GCC diagnostic push | ||||
#ifndef __clang__ | #ifndef __clang__ | ||||
@@ -43,8 +42,6 @@ struct RtAudioDevice : audio::Device { | |||||
RtAudio::StreamOptions options; | RtAudio::StreamOptions options; | ||||
int blockSize = 0; | int blockSize = 0; | ||||
float sampleRate = 0; | float sampleRate = 0; | ||||
/** Ensures that ports do not subscribe/unsubscribe while processBuffer() is called. */ | |||||
std::mutex processMutex; | |||||
RtAudioDevice(RtAudio::Api api, int deviceId) { | RtAudioDevice(RtAudio::Api api, int deviceId) { | ||||
this->api = api; | this->api = api; | ||||
@@ -212,16 +209,6 @@ struct RtAudioDevice : audio::Device { | |||||
openStream(); | openStream(); | ||||
} | } | ||||
void subscribe(audio::Port* port) override { | |||||
std::lock_guard<std::mutex> lock(processMutex); | |||||
Device::subscribe(port); | |||||
} | |||||
void unsubscribe(audio::Port* port) override { | |||||
std::lock_guard<std::mutex> lock(processMutex); | |||||
Device::unsubscribe(port); | |||||
} | |||||
static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) { | static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) { | ||||
// fprintf(stderr, "."); | // fprintf(stderr, "."); | ||||
// fflush(stderr); | // fflush(stderr); | ||||
@@ -229,8 +216,6 @@ struct RtAudioDevice : audio::Device { | |||||
RtAudioDevice* that = (RtAudioDevice*) userData; | RtAudioDevice* that = (RtAudioDevice*) userData; | ||||
assert(that); | assert(that); | ||||
std::lock_guard<std::mutex> lock(that->processMutex); | |||||
system::setThreadName("RtAudio"); | system::setThreadName("RtAudio"); | ||||
int inputStride = that->getNumInputs(); | int inputStride = that->getNumInputs(); | ||||