Browse Source

Add timed mutexes, hopefully solving deadlock issues in Audio Interface

tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
2bc6678ca5
1 changed files with 18 additions and 10 deletions
  1. +18
    -10
      src/core/AudioInterface.cpp

+ 18
- 10
src/core/AudioInterface.cpp View File

@@ -36,9 +36,10 @@ struct AudioInterface : Module {
int blockSize = 256; int blockSize = 256;
int numOutputs = 0; int numOutputs = 0;
int numInputs = 0; int numInputs = 0;
bool streamRunning = false;


// Used because the GUI thread and Rack thread can both interact with this class // Used because the GUI thread and Rack thread can both interact with this class
std::mutex bufferMutex;
std::timed_mutex bufferMutex;


SampleRateConverter<8> inputSrc; SampleRateConverter<8> inputSrc;
SampleRateConverter<8> outputSrc; SampleRateConverter<8> outputSrc;
@@ -117,17 +118,18 @@ struct AudioInterface : Module {
void AudioInterface::step() { void AudioInterface::step() {
// Read/write stream if we have enough input, OR the output buffer is empty if we have no input // Read/write stream if we have enough input, OR the output buffer is empty if we have no input
if (numOutputs > 0) { if (numOutputs > 0) {
while (inputSrcBuffer.size() >= blockSize && stream.isStreamRunning()) {
while (inputSrcBuffer.size() >= blockSize && streamRunning) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6)); std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
} }
} }
else if (numInputs > 0) { else if (numInputs > 0) {
while (outputBuffer.empty() && stream.isStreamRunning()) {
while (outputBuffer.empty() && streamRunning) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6)); std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
} }
} }


std::lock_guard<std::mutex> lock(bufferMutex);
if (!bufferMutex.try_lock_for(std::chrono::duration<float>(10e-3)))
return;


// Get input and pass it through the sample rate converter // Get input and pass it through the sample rate converter
if (numOutputs > 0) { if (numOutputs > 0) {
@@ -158,6 +160,8 @@ void AudioInterface::step() {
outputs[AUDIO1_OUTPUT + i].value = 10.0 * f.samples[i]; outputs[AUDIO1_OUTPUT + i].value = 10.0 * f.samples[i];
} }
} }

bufferMutex.unlock();
} }


void AudioInterface::stepStream(const float *input, float *output, int numFrames) { void AudioInterface::stepStream(const float *input, float *output, int numFrames) {
@@ -168,14 +172,14 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames


if (numOutputs > 0) { if (numOutputs > 0) {
// Wait for enough input before proceeding // Wait for enough input before proceeding
while (inputSrcBuffer.size() < numFrames) {
if (!stream.isStreamRunning())
return;
while (inputSrcBuffer.size() < numFrames && streamRunning) {
std::this_thread::sleep_for(std::chrono::duration<float>(100e-6)); std::this_thread::sleep_for(std::chrono::duration<float>(100e-6));
} }
} }


std::lock_guard<std::mutex> lock(bufferMutex);
if (!bufferMutex.try_lock_for(std::chrono::duration<float>(10e-3)))
return;

// input stream -> output buffer // input stream -> output buffer
if (numInputs > 0) { if (numInputs > 0) {
Frame<8> inputFrames[numFrames]; Frame<8> inputFrames[numFrames];
@@ -204,6 +208,7 @@ void AudioInterface::stepStream(const float *input, float *output, int numFrames
} }
} }
} }
bufferMutex.unlock();
} }


int AudioInterface::getDeviceCount() { int AudioInterface::getDeviceCount() {
@@ -233,7 +238,7 @@ static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrame


void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) { void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
closeDevice(); closeDevice();
std::lock_guard<std::mutex> lock(bufferMutex);
std::lock_guard<std::timed_mutex> lock(bufferMutex);


this->sampleRate = sampleRate; this->sampleRate = sampleRate;
this->blockSize = blockSize; this->blockSize = blockSize;
@@ -276,6 +281,8 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
return; return;
} }


streamRunning = true;

try { try {
debug("Starting audio stream %d", deviceId); debug("Starting audio stream %d", deviceId);
stream.startStream(); stream.startStream();
@@ -291,9 +298,10 @@ void AudioInterface::openDevice(int deviceId, float sampleRate, int blockSize) {
} }


void AudioInterface::closeDevice() { void AudioInterface::closeDevice() {
std::lock_guard<std::mutex> lock(bufferMutex);
std::lock_guard<std::timed_mutex> lock(bufferMutex);


if (stream.isStreamOpen()) { if (stream.isStreamOpen()) {
streamRunning = false;
try { try {
debug("Aborting audio stream %d", deviceId); debug("Aborting audio stream %d", deviceId);
stream.abortStream(); stream.abortStream();


Loading…
Cancel
Save