mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-09-02 13:17:48 -04:00
AudioThread: Revised mutex usage for devices vs. AudioThread* due to erroneous implem., creating crashes in some cases
(damn those things are hard...)
This commit is contained in:
parent
950a4622b7
commit
230a87d8df
@ -1364,7 +1364,6 @@ bool AppFrame::actionOnMenuAudioSampleRate(wxCommandEvent& event) {
|
|||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,6 +18,8 @@ std::map<int, AudioThread *> AudioThread::deviceController;
|
|||||||
std::map<int, int> AudioThread::deviceSampleRate;
|
std::map<int, int> AudioThread::deviceSampleRate;
|
||||||
std::map<int, std::thread *> AudioThread::deviceThread;
|
std::map<int, std::thread *> AudioThread::deviceThread;
|
||||||
|
|
||||||
|
std::recursive_mutex AudioThread::m_device_mutex;
|
||||||
|
|
||||||
AudioThread::AudioThread() : IOThread(),
|
AudioThread::AudioThread() : IOThread(),
|
||||||
currentInput(nullptr), inputQueue(nullptr), nBufferFrames(1024), sampleRate(0) {
|
currentInput(nullptr), inputQueue(nullptr), nBufferFrames(1024), sampleRate(0) {
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ AudioThread::AudioThread() : IOThread(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
AudioThread::~AudioThread() {
|
AudioThread::~AudioThread() {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::recursive_mutex & AudioThread::getMutex()
|
std::recursive_mutex & AudioThread::getMutex()
|
||||||
@ -48,10 +50,10 @@ void AudioThread::bindThread(AudioThread *other) {
|
|||||||
|
|
||||||
void AudioThread::removeThread(AudioThread *other) {
|
void AudioThread::removeThread(AudioThread *other) {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
|
auto i = std::find(boundThreads.begin(), boundThreads.end(), other);
|
||||||
|
|
||||||
std::vector<AudioThread *>::iterator i;
|
|
||||||
i = std::find(boundThreads.begin(), boundThreads.end(), other);
|
|
||||||
if (i != boundThreads.end()) {
|
if (i != boundThreads.end()) {
|
||||||
boundThreads.erase(i);
|
boundThreads.erase(i);
|
||||||
}
|
}
|
||||||
@ -59,9 +61,9 @@ void AudioThread::removeThread(AudioThread *other) {
|
|||||||
|
|
||||||
void AudioThread::deviceCleanup() {
|
void AudioThread::deviceCleanup() {
|
||||||
|
|
||||||
std::map<int, AudioThread *>::iterator i;
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
for (i = deviceController.begin(); i != deviceController.end(); i++) {
|
for (auto i = deviceController.begin(); i != deviceController.end(); i++) {
|
||||||
i->second->terminate();
|
i->second->terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,23 +281,47 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
|||||||
|
|
||||||
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
|
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
|
||||||
|
|
||||||
|
AudioThread* matchingAudioThread = nullptr;
|
||||||
|
|
||||||
if (deviceController.find(deviceId) != deviceController.end()) {
|
//scope lock here to minimize the common unique static lock contention
|
||||||
AudioThreadCommand refreshDevice;
|
{
|
||||||
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
refreshDevice.int_value = sampleRate;
|
|
||||||
//VSO : blocking push !
|
if (deviceController.find(deviceId) != deviceController.end()) {
|
||||||
deviceController[deviceId]->getCommandQueue()->push(refreshDevice);
|
|
||||||
}
|
matchingAudioThread = deviceController[deviceId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//out-of-lock test
|
||||||
|
if (matchingAudioThread != nullptr) {
|
||||||
|
|
||||||
|
AudioThreadCommand refreshDevice;
|
||||||
|
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
|
||||||
|
refreshDevice.int_value = sampleRate;
|
||||||
|
//VSO : blocking push !
|
||||||
|
matchingAudioThread->getCommandQueue()->push(refreshDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setSampleRate(int sampleRate) {
|
void AudioThread::setSampleRate(int sampleRate) {
|
||||||
|
|
||||||
|
bool outputIsThis = false;
|
||||||
|
|
||||||
|
//scope lock here to minimize the common unique static lock contention
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
|
if (deviceController[outputDevice.load()] == this) {
|
||||||
|
outputIsThis = true;
|
||||||
|
deviceSampleRate[outputDevice.load()] = sampleRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (deviceController[outputDevice.load()] == this) {
|
if (outputIsThis) {
|
||||||
deviceSampleRate[outputDevice.load()] = sampleRate;
|
|
||||||
|
|
||||||
dac.stopStream();
|
dac.stopStream();
|
||||||
dac.closeStream();
|
dac.closeStream();
|
||||||
|
|
||||||
@ -328,7 +354,8 @@ int AudioThread::getSampleRate() {
|
|||||||
|
|
||||||
void AudioThread::setupDevice(int deviceId) {
|
void AudioThread::setupDevice(int deviceId) {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
//global lock to setup the device...
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
parameters.deviceId = deviceId;
|
parameters.deviceId = deviceId;
|
||||||
parameters.nChannels = 2;
|
parameters.nChannels = 2;
|
||||||
@ -381,6 +408,7 @@ void AudioThread::setupDevice(int deviceId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int AudioThread::getOutputDevice() {
|
int AudioThread::getOutputDevice() {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (outputDevice == -1) {
|
if (outputDevice == -1) {
|
||||||
@ -391,7 +419,8 @@ int AudioThread::getOutputDevice() {
|
|||||||
|
|
||||||
void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
//global lock
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
outputDevice = deviceId;
|
outputDevice = deviceId;
|
||||||
if (sampleRate == -1) {
|
if (sampleRate == -1) {
|
||||||
@ -453,7 +482,9 @@ void AudioThread::run() {
|
|||||||
//Nullify currentInput...
|
//Nullify currentInput...
|
||||||
currentInput = nullptr;
|
currentInput = nullptr;
|
||||||
|
|
||||||
//Stop
|
//Stop : this affects the device list , so must be protected globally.
|
||||||
|
std::lock_guard<std::recursive_mutex> global_lock(m_device_mutex);
|
||||||
|
|
||||||
if (deviceController[parameters.deviceId] != this) {
|
if (deviceController[parameters.deviceId] != this) {
|
||||||
deviceController[parameters.deviceId]->removeThread(this);
|
deviceController[parameters.deviceId]->removeThread(this);
|
||||||
} else {
|
} else {
|
||||||
@ -483,17 +514,29 @@ bool AudioThread::isActive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setActive(bool state) {
|
void AudioThread::setActive(bool state) {
|
||||||
|
|
||||||
|
AudioThread* matchingAudioThread = nullptr;
|
||||||
|
|
||||||
|
//scope lock here to minimize the common unique static lock contention
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
|
||||||
|
|
||||||
|
if (deviceController.find(parameters.deviceId) != deviceController.end()) {
|
||||||
|
|
||||||
|
matchingAudioThread = deviceController[parameters.deviceId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (deviceController[parameters.deviceId] == nullptr) {
|
if (matchingAudioThread == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state && !active && inputQueue) {
|
if (state && !active && inputQueue) {
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
matchingAudioThread->bindThread(this);
|
||||||
} else if (!state && active) {
|
} else if (!state && active) {
|
||||||
deviceController[parameters.deviceId]->removeThread(this);
|
matchingAudioThread->removeThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activity state changing, clear any inputs
|
// Activity state changing, clear any inputs
|
||||||
|
@ -122,7 +122,9 @@ private:
|
|||||||
void removeThread(AudioThread *other);
|
void removeThread(AudioThread *other);
|
||||||
|
|
||||||
static std::map<int, AudioThread *> deviceController;
|
static std::map<int, AudioThread *> deviceController;
|
||||||
|
|
||||||
static std::map<int, std::thread *> deviceThread;
|
static std::map<int, std::thread *> deviceThread;
|
||||||
|
|
||||||
|
//The mutex protecting static deviceController, deviceThread and deviceSampleRate access.
|
||||||
|
static std::recursive_mutex m_device_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user