TH_CLEAN_3: Use of non-blocking try_pop() when possible,

AudioThread concurrent access hardening and simplified,
and misc.
This commit is contained in:
vsonnier 2016-07-05 21:43:45 +02:00
parent 3bf17d0f40
commit b495b388c9
16 changed files with 223 additions and 149 deletions

View File

@ -806,11 +806,11 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
#endif #endif
else if (event.GetId() == wxID_SDR_START_STOP) { else if (event.GetId() == wxID_SDR_START_STOP) {
if (!wxGetApp().getSDRThread()->isTerminated()) { if (!wxGetApp().getSDRThread()->isTerminated()) {
wxGetApp().stopDevice(true); wxGetApp().stopDevice(true, 2000);
} else { } else {
SDRDeviceInfo *dev = wxGetApp().getDevice(); SDRDeviceInfo *dev = wxGetApp().getDevice();
if (dev != nullptr) { if (dev != nullptr) {
wxGetApp().setDevice(dev); wxGetApp().setDevice(dev, 0);
} }
} }
} else if (event.GetId() == wxID_LOW_PERF) { } else if (event.GetId() == wxID_LOW_PERF) {

View File

@ -133,8 +133,8 @@ long long strToFrequency(std::string freqStr) {
} }
CubicSDR::CubicSDR() : appframe(NULL), m_glContext(NULL), frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE), CubicSDR::CubicSDR() : frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFAULT_SAMPLE_RATE),agcMode(false)
sdrThread(NULL), sdrPostThread(NULL), spectrumVisualThread(NULL), demodVisualThread(NULL), pipeSDRIQData(NULL), pipeIQVisualData(NULL), pipeAudioVisualData(NULL), t_SDR(NULL), t_PostSDR(NULL) { {
sampleRateInitialized.store(false); sampleRateInitialized.store(false);
agcMode.store(true); agcMode.store(true);
soloMode.store(false); soloMode.store(false);
@ -290,11 +290,10 @@ int CubicSDR::OnExit() {
} }
#endif #endif
demodMgr.terminateAll(); //The thread feeding them all should be terminated first, so:
std::cout << "Terminating SDR thread.." << std::endl; std::cout << "Terminating SDR thread.." << std::endl;
sdrThread->terminate(); sdrThread->terminate();
sdrThread->isTerminated(1000); sdrThread->isTerminated(3000);
if (t_SDR) { if (t_SDR) {
t_SDR->join(); t_SDR->join();
@ -305,6 +304,9 @@ int CubicSDR::OnExit() {
std::cout << "Terminating SDR post-processing thread.." << std::endl; std::cout << "Terminating SDR post-processing thread.." << std::endl;
sdrPostThread->terminate(); sdrPostThread->terminate();
std::cout << "Terminating All Demodulators.." << std::endl;
demodMgr.terminateAll();
std::cout << "Terminating Visual Processor threads.." << std::endl; std::cout << "Terminating Visual Processor threads.." << std::endl;
spectrumVisualThread->terminate(); spectrumVisualThread->terminate();
demodVisualThread->terminate(); demodVisualThread->terminate();
@ -542,16 +544,11 @@ void CubicSDR::setSampleRate(long long rate_in) {
} }
} }
void CubicSDR::stopDevice(bool store) { void CubicSDR::stopDevice(bool store, int waitMsForTermination) {
if (store) {
stoppedDev = sdrThread->getDevice();
} else {
stoppedDev = nullptr;
}
sdrThread->setDevice(nullptr);
//Firt we must stop the threads
sdrThread->terminate(); sdrThread->terminate();
sdrThread->isTerminated(1000); sdrThread->isTerminated(waitMsForTermination);
if (t_SDR) { if (t_SDR) {
t_SDR->join(); t_SDR->join();
@ -559,6 +556,15 @@ void CubicSDR::stopDevice(bool store) {
t_SDR = nullptr; t_SDR = nullptr;
} }
//Only now we can nullify devices
if (store) {
stoppedDev = sdrThread->getDevice();
}
else {
stoppedDev = nullptr;
}
sdrThread->setDevice(nullptr);
} }
void CubicSDR::reEnumerateDevices() { void CubicSDR::reEnumerateDevices() {
@ -568,10 +574,10 @@ void CubicSDR::reEnumerateDevices() {
t_SDREnum = new std::thread(&SDREnumerator::threadMain, sdrEnum); t_SDREnum = new std::thread(&SDREnumerator::threadMain, sdrEnum);
} }
void CubicSDR::setDevice(SDRDeviceInfo *dev) { void CubicSDR::setDevice(SDRDeviceInfo *dev, int waitMsForTermination) {
sdrThread->terminate(); sdrThread->terminate();
sdrThread->isTerminated(1000); sdrThread->isTerminated(waitMsForTermination);
if (t_SDR) { if (t_SDR) {
t_SDR->join(); t_SDR->join();

View File

@ -98,8 +98,8 @@ public:
long long getSampleRate(); long long getSampleRate();
std::vector<SDRDeviceInfo *> *getDevices(); std::vector<SDRDeviceInfo *> *getDevices();
void setDevice(SDRDeviceInfo *dev); void setDevice(SDRDeviceInfo *dev, int waitMsForTermination);
void stopDevice(bool store); void stopDevice(bool store, int waitMsForTermination);
SDRDeviceInfo * getDevice(); SDRDeviceInfo * getDevice();
ScopeVisualProcessor *getScopeProcessor(); ScopeVisualProcessor *getScopeProcessor();
@ -173,10 +173,10 @@ public:
private: private:
int FilterEvent(wxEvent& event); int FilterEvent(wxEvent& event);
AppFrame *appframe; AppFrame *appframe = nullptr;
AppConfig config; AppConfig config;
PrimaryGLContext *m_glContext; PrimaryGLContext *m_glContext = nullptr;
std::vector<SDRDeviceInfo *> *devs; std::vector<SDRDeviceInfo *> *devs = nullptr;
DemodulatorMgr demodMgr; DemodulatorMgr demodMgr;
@ -186,27 +186,31 @@ private:
std::atomic_llong sampleRate; std::atomic_llong sampleRate;
std::atomic_bool agcMode; std::atomic_bool agcMode;
SDRThread *sdrThread; SDRThread *sdrThread = nullptr;
SDREnumerator *sdrEnum; SDREnumerator *sdrEnum = nullptr;
SDRPostThread *sdrPostThread; SDRPostThread *sdrPostThread = nullptr;
SpectrumVisualDataThread *spectrumVisualThread; SpectrumVisualDataThread *spectrumVisualThread = nullptr;
SpectrumVisualDataThread *demodVisualThread; SpectrumVisualDataThread *demodVisualThread = nullptr;
SDRThreadIQDataQueue* pipeSDRIQData; SDRThreadIQDataQueue* pipeSDRIQData = nullptr;
DemodulatorThreadInputQueue* pipeIQVisualData; DemodulatorThreadInputQueue* pipeIQVisualData = nullptr;
DemodulatorThreadOutputQueue* pipeAudioVisualData; DemodulatorThreadOutputQueue* pipeAudioVisualData = nullptr;
DemodulatorThreadInputQueue* pipeDemodIQVisualData; DemodulatorThreadInputQueue* pipeDemodIQVisualData = nullptr;
DemodulatorThreadInputQueue* pipeWaterfallIQVisualData; DemodulatorThreadInputQueue* pipeWaterfallIQVisualData = nullptr;
DemodulatorThreadInputQueue* pipeActiveDemodIQVisualData; DemodulatorThreadInputQueue* pipeActiveDemodIQVisualData = nullptr;
ScopeVisualProcessor scopeProcessor; ScopeVisualProcessor scopeProcessor;
SDRDevicesDialog *deviceSelectorDialog; SDRDevicesDialog *deviceSelectorDialog = nullptr;
SoapySDR::Kwargs streamArgs; SoapySDR::Kwargs streamArgs;
SoapySDR::Kwargs settingArgs; SoapySDR::Kwargs settingArgs;
std::thread *t_SDR, *t_SDREnum, *t_PostSDR, *t_SpectrumVisual, *t_DemodVisual; std::thread *t_SDR = nullptr;
std::thread *t_SDREnum = nullptr;
std::thread *t_PostSDR = nullptr;
std::thread *t_SpectrumVisual = nullptr;
std::thread *t_DemodVisual = nullptr;
std::atomic_bool devicesReady; std::atomic_bool devicesReady;
std::atomic_bool devicesFailed; std::atomic_bool devicesFailed;
std::atomic_bool deviceSelectorOpen; std::atomic_bool deviceSelectorOpen;
@ -224,8 +228,8 @@ private:
std::atomic_bool soloMode; std::atomic_bool soloMode;
SDRDeviceInfo *stoppedDev; SDRDeviceInfo *stoppedDev;
#ifdef USE_HAMLIB #ifdef USE_HAMLIB
RigThread* rigThread; RigThread* rigThread = nullptr;
std::thread *t_Rig; std::thread *t_Rig = nullptr;
#endif #endif
}; };

View File

@ -6,13 +6,14 @@
#include "DemodulatorThread.h" #include "DemodulatorThread.h"
#include "DemodulatorInstance.h" #include "DemodulatorInstance.h"
#include <memory.h> #include <memory.h>
#include <mutex>
std::map<int, AudioThread *> AudioThread::deviceController; 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;
AudioThread::AudioThread() : IOThread(), AudioThread::AudioThread() : IOThread(),
currentInput(NULL), inputQueue(NULL), nBufferFrames(1024), sampleRate(0) { currentInput(nullptr), inputQueue(nullptr), nBufferFrames(1024), sampleRate(0) {
audioQueuePtr.store(0); audioQueuePtr.store(0);
underflowCount.store(0); underflowCount.store(0);
@ -29,13 +30,24 @@ AudioThread::~AudioThread() {
delete vBoundThreads; delete vBoundThreads;
} }
std::recursive_mutex & AudioThread::getMutex()
{
return m_mutex;
}
void AudioThread::bindThread(AudioThread *other) { void AudioThread::bindThread(AudioThread *other) {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if (std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other) == boundThreads.load()->end()) { if (std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other) == boundThreads.load()->end()) {
boundThreads.load()->push_back(other); boundThreads.load()->push_back(other);
} }
} }
void AudioThread::removeThread(AudioThread *other) { void AudioThread::removeThread(AudioThread *other) {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::vector<AudioThread *>::iterator i; std::vector<AudioThread *>::iterator i;
i = std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other); i = std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other);
if (i != boundThreads.load()->end()) { if (i != boundThreads.load()->end()) {
@ -44,6 +56,7 @@ void AudioThread::removeThread(AudioThread *other) {
} }
void AudioThread::deviceCleanup() { void AudioThread::deviceCleanup() {
std::map<int, AudioThread *>::iterator i; std::map<int, AudioThread *>::iterator i;
for (i = deviceController.begin(); i != deviceController.end(); i++) { for (i = deviceController.begin(); i != deviceController.end(); i++) {
@ -53,10 +66,17 @@ void AudioThread::deviceCleanup() {
static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned int nBufferFrames, double /* streamTime */, RtAudioStreamStatus status, static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned int nBufferFrames, double /* streamTime */, RtAudioStreamStatus status,
void *userData) { void *userData) {
AudioThread *src = (AudioThread *) userData;
float *out = (float*)outputBuffer; float *out = (float*)outputBuffer;
//Zero output buffer in all cases: this allow to mute audio if no AudioThread data is
//actually active.
memset(out, 0, nBufferFrames * 2 * sizeof(float)); memset(out, 0, nBufferFrames * 2 * sizeof(float));
AudioThread *src = (AudioThread *) userData;
std::lock_guard<std::recursive_mutex> lock(src->getMutex());
if (src->isTerminated()) { if (src->isTerminated()) {
return 1; return 1;
} }
@ -69,37 +89,44 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
return 0; return 0;
} }
float peak = 0.0;
double peak = 0.0;
//for all boundThreads
for (size_t j = 0; j < src->boundThreads.load()->size(); j++) { for (size_t j = 0; j < src->boundThreads.load()->size(); j++) {
AudioThread *srcmix = (*(src->boundThreads.load()))[j]; AudioThread *srcmix = (*(src->boundThreads.load()))[j];
//lock every single boundThread srcmix in succession the time we process
//its audio samples.
std::lock_guard<std::recursive_mutex> lock(srcmix->getMutex());
if (srcmix->isTerminated() || !srcmix->inputQueue || srcmix->inputQueue->empty() || !srcmix->isActive()) { if (srcmix->isTerminated() || !srcmix->inputQueue || srcmix->inputQueue->empty() || !srcmix->isActive()) {
continue; continue;
} }
if (!srcmix->currentInput) { if (!srcmix->currentInput) {
srcmix->audioQueuePtr = 0; srcmix->audioQueuePtr = 0;
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
continue; if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
}
srcmix->inputQueue->pop(srcmix->currentInput);
if (srcmix->isTerminated()) {
continue; continue;
} }
continue; continue;
} }
if (srcmix->currentInput->sampleRate != src->getSampleRate()) { if (srcmix->currentInput->sampleRate != src->getSampleRate()) {
while (srcmix->inputQueue->size()) {
srcmix->inputQueue->pop(srcmix->currentInput); while (srcmix->inputQueue->try_pop(srcmix->currentInput)) {
if (srcmix->currentInput) { if (srcmix->currentInput) {
if (srcmix->currentInput->sampleRate == src->getSampleRate()) { if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
break; break;
} }
srcmix->currentInput->decRefCount(); srcmix->currentInput->decRefCount();
} }
srcmix->currentInput = NULL; srcmix->currentInput = nullptr;
} } //end while
srcmix->audioQueuePtr = 0; srcmix->audioQueuePtr = 0;
@ -114,37 +141,35 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
srcmix->audioQueuePtr = 0; srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) { if (srcmix->currentInput) {
srcmix->currentInput->decRefCount(); srcmix->currentInput->decRefCount();
srcmix->currentInput = NULL; srcmix->currentInput = nullptr;
} }
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
continue; if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
}
srcmix->inputQueue->pop(srcmix->currentInput);
if (srcmix->isTerminated()) {
continue; continue;
} }
} }
continue; continue;
} }
float mixPeak = srcmix->currentInput->peak * srcmix->gain; double mixPeak = srcmix->currentInput->peak * srcmix->gain;
if (srcmix->currentInput->channels == 1) { if (srcmix->currentInput->channels == 1) {
for (unsigned int i = 0; i < nBufferFrames; i++) { for (unsigned int i = 0; i < nBufferFrames; i++) {
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) { if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
srcmix->audioQueuePtr = 0; srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) { if (srcmix->currentInput) {
srcmix->currentInput->decRefCount(); srcmix->currentInput->decRefCount();
srcmix->currentInput = NULL; srcmix->currentInput = nullptr;
} }
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
break; break;
} }
srcmix->inputQueue->pop(srcmix->currentInput);
if (srcmix->isTerminated()) {
break; double srcPeak = srcmix->currentInput->peak * srcmix->gain;
}
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
if (mixPeak < srcPeak) { if (mixPeak < srcPeak) {
mixPeak = srcPeak; mixPeak = srcPeak;
} }
@ -158,25 +183,25 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
} }
} else { } else {
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) { for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) { if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
srcmix->audioQueuePtr = 0; srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) { if (srcmix->currentInput) {
srcmix->currentInput->decRefCount(); srcmix->currentInput->decRefCount();
srcmix->currentInput = NULL; srcmix->currentInput = nullptr;
} }
if (srcmix->isTerminated() || srcmix->inputQueue->empty()) {
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
break; break;
} }
srcmix->inputQueue->pop(srcmix->currentInput);
if (srcmix->isTerminated()) { double srcPeak = srcmix->currentInput->peak * srcmix->gain;
break;
}
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
if (mixPeak < srcPeak) { if (mixPeak < srcPeak) {
mixPeak = srcPeak; mixPeak = srcPeak;
} }
} }
if (srcmix->currentInput && srcmix->currentInput->data.size()) { if (srcmix->currentInput && srcmix->currentInput->data.size()) {
out[i] = out[i] + srcmix->currentInput->data[srcmix->audioQueuePtr] * srcmix->gain; out[i] = out[i] + srcmix->currentInput->data[srcmix->audioQueuePtr] * srcmix->gain;
} }
srcmix->audioQueuePtr++; srcmix->audioQueuePtr++;
@ -186,11 +211,15 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
peak += mixPeak; peak += mixPeak;
} }
//normalize volume
if (peak > 1.0) { if (peak > 1.0) {
float invPeak = (float)(1.0 / peak);
for (unsigned int i = 0; i < nBufferFrames * 2; i++) { for (unsigned int i = 0; i < nBufferFrames * 2; i++) {
out[i] /= peak; out[i] *= invPeak;
} }
} }
return 0; return 0;
} }
@ -247,6 +276,7 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
} }
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) { void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
if (deviceController.find(deviceId) != deviceController.end()) { if (deviceController.find(deviceId) != deviceController.end()) {
AudioThreadCommand refreshDevice; AudioThreadCommand refreshDevice;
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE; refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
@ -262,6 +292,8 @@ void AudioThread::setSampleRate(int sampleRate) {
dac.stopStream(); dac.stopStream();
dac.closeStream(); dac.closeStream();
std::lock_guard<std::recursive_mutex> lock(m_mutex);
for (size_t j = 0; j < boundThreads.load()->size(); j++) { for (size_t j = 0; j < boundThreads.load()->size(); j++) {
AudioThread *srcmix = (*(boundThreads.load()))[j]; AudioThread *srcmix = (*(boundThreads.load()))[j];
srcmix->setSampleRate(sampleRate); srcmix->setSampleRate(sampleRate);
@ -323,6 +355,7 @@ void AudioThread::setupDevice(int deviceId) {
deviceThread[parameters.deviceId] = new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]); deviceThread[parameters.deviceId] = new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]);
} else if (deviceController[parameters.deviceId] == this) { } else if (deviceController[parameters.deviceId] == this) {
//Attach callback
dac.openStream(&parameters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *) this, &opts); dac.openStream(&parameters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *) this, &opts);
dac.startStream(); dac.startStream();
} else { } else {
@ -379,6 +412,7 @@ void AudioThread::run() {
inputQueue = static_cast<AudioThreadInputQueue *>(getInputQueue("AudioDataInput")); inputQueue = static_cast<AudioThreadInputQueue *>(getInputQueue("AudioDataInput"));
//Infinite loop, witing for commands or for termination
while (!stopping) { while (!stopping) {
AudioThreadCommand command; AudioThreadCommand command;
cmdQueue.pop(command); cmdQueue.pop(command);
@ -391,20 +425,26 @@ void AudioThread::run() {
} }
} }
// Drain any remaining inputs //Thread termination, prevent fancy things to happen, lock the whole thing:
if (inputQueue) while (!inputQueue->empty()) { //This way audioThreadCallback is rightly protected from thread termination
std::lock_guard<std::recursive_mutex> lock(m_mutex);
// Drain any remaining inputs, with a non-blocking pop
AudioThreadInput *ref; AudioThreadInput *ref;
inputQueue->pop(ref); while (inputQueue && inputQueue->try_pop(ref)) {
if (ref) { if (ref) {
ref->decRefCount(); ref->decRefCount();
} }
} } //end while
//Nullify currentInput...
if (currentInput) { if (currentInput) {
currentInput->setRefCount(0); currentInput->setRefCount(0);
currentInput = nullptr; currentInput = nullptr;
} }
//Stop
if (deviceController[parameters.deviceId] != this) { if (deviceController[parameters.deviceId] != this) {
deviceController[parameters.deviceId]->removeThread(this); deviceController[parameters.deviceId]->removeThread(this);
} else { } else {
@ -444,8 +484,9 @@ void AudioThread::setActive(bool state) {
// Activity state changing, clear any inputs // Activity state changing, clear any inputs
if(inputQueue) { if(inputQueue) {
while (!inputQueue->empty()) { // flush queue
inputQueue->pop(dummy); while (inputQueue->try_pop(dummy)) { // flush queue, non-blocking pop
if (dummy) { if (dummy) {
dummy->decRefCount(); dummy->decRefCount();
} }

View File

@ -88,7 +88,13 @@ private:
AudioThreadCommandQueue cmdQueue; AudioThreadCommandQueue cmdQueue;
int sampleRate; int sampleRate;
//The own m_mutex protecting this AudioThread
std::recursive_mutex m_mutex;
public: public:
//give access to the this AudioThread lock
std::recursive_mutex& getMutex();
void bindThread(AudioThread *other); void bindThread(AudioThread *other);
void removeThread(AudioThread *other); void removeThread(AudioThread *other);

View File

@ -210,10 +210,9 @@ void DemodulatorPreThread::run() {
inp->decRefCount(); inp->decRefCount();
if (!stopping && !workerResults->empty()) {
while (!workerResults->empty()) {
DemodulatorWorkerThreadResult result; DemodulatorWorkerThreadResult result;
workerResults->pop(result); //process all worker results until
while (!stopping && workerResults->try_pop(result)) {
switch (result.cmd) { switch (result.cmd) {
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS: case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
@ -259,19 +258,18 @@ void DemodulatorPreThread::run() {
default: default:
break; break;
} }
} } //end while
}
if ((cModem != nullptr) && modemSettingsChanged.load()) { if ((cModem != nullptr) && modemSettingsChanged.load()) {
cModem->writeSettings(modemSettingsBuffered); cModem->writeSettings(modemSettingsBuffered);
modemSettingsBuffered.clear(); modemSettingsBuffered.clear();
modemSettingsChanged.store(false); modemSettingsChanged.store(false);
} }
} } //end while stopping
while (!iqOutputQueue->empty()) {
DemodulatorThreadPostIQData *tmp; DemodulatorThreadPostIQData *tmp;
iqOutputQueue->pop(tmp); while (iqOutputQueue->try_pop(tmp)) {
tmp->decRefCount(); tmp->decRefCount();
} }
buffers.purge(); buffers.purge();

View File

@ -250,10 +250,10 @@ void DemodulatorThread::run() {
} }
} }
if (!threadQueueControl->empty()) {
while (!threadQueueControl->empty()) {
DemodulatorThreadControlCommand command; DemodulatorThreadControlCommand command;
threadQueueControl->pop(command);
//empty command queue, execute commands
while (threadQueueControl->try_pop(command)) {
switch (command.cmd) { switch (command.cmd) {
case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_ON: case DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_ON:
@ -266,27 +266,29 @@ void DemodulatorThread::run() {
break; break;
} }
} }
}
inp->decRefCount(); inp->decRefCount();
} }
// end while !stopping // end while !stopping
// Purge any unused inputs // Purge any unused inputs, with a non-blocking pop
while (!iqInputQueue->empty()) {
DemodulatorThreadPostIQData *ref; DemodulatorThreadPostIQData *ref;
iqInputQueue->pop(ref); while (iqInputQueue->try_pop(ref)) {
if (ref) { // May have other consumers; just decrement if (ref) { // May have other consumers; just decrement
ref->decRefCount(); ref->decRefCount();
} }
} }
while (!audioOutputQueue->empty()) {
AudioThreadInput *ref; AudioThreadInput *ref_audio;
audioOutputQueue->pop(ref); while (audioOutputQueue->try_pop(ref_audio)) {
if (ref) { // Originated here; set RefCount to 0
ref->setRefCount(0); if (ref_audio) { // Originated here; set RefCount to 0
ref_audio->setRefCount(0);
} }
} }
outputBuffers.purge(); outputBuffers.purge();
// std::cout << "Demodulator thread done." << std::endl; // std::cout << "Demodulator thread done." << std::endl;

View File

@ -24,8 +24,12 @@ void DemodulatorWorkerThread::run() {
DemodulatorWorkerThreadCommand command; DemodulatorWorkerThreadCommand command;
bool done = false; bool done = false;
//Beware of the subtility here,
//we are waiting for the first command to show up (blocking!)
//then consuming the commands until done.
while (!done) { while (!done) {
commandQueue->pop(command); commandQueue->pop(command);
switch (command.cmd) { switch (command.cmd) {
case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS: case DemodulatorWorkerThreadCommand::DEMOD_WORKER_THREAD_CMD_BUILD_FILTERS:
filterChanged = true; filterChanged = true;

View File

@ -314,7 +314,7 @@ void SDRDevicesDialog::OnUseSelected( wxMouseEvent& event) {
devConfig->setStreamOpts(streamArgs); devConfig->setStreamOpts(streamArgs);
wxGetApp().setDeviceArgs(settingArgs); wxGetApp().setDeviceArgs(settingArgs);
wxGetApp().setStreamArgs(streamArgs); wxGetApp().setStreamArgs(streamArgs);
wxGetApp().setDevice(dev); wxGetApp().setDevice(dev,0);
Close(); Close();
} }
@ -483,7 +483,7 @@ void SDRDevicesDialog::doRefreshDevices() {
editId = nullptr; editId = nullptr;
removeId = nullptr; removeId = nullptr;
dev = nullptr; dev = nullptr;
wxGetApp().stopDevice(false); wxGetApp().stopDevice(false, 2000);
devTree->DeleteAllItems(); devTree->DeleteAllItems();
devTree->Disable(); devTree->Disable();
m_propertyGrid->Clear(); m_propertyGrid->Clear();

View File

@ -17,6 +17,7 @@ unsigned int FFTDataDistributor::getLinesPerSecond() {
} }
void FFTDataDistributor::process() { void FFTDataDistributor::process() {
while (!input->empty()) { while (!input->empty()) {
if (!isAnyOutputEmpty()) { if (!isAnyOutputEmpty()) {
return; return;

View File

@ -68,9 +68,9 @@ void ScopeVisualProcessor::process() {
if (!isOutputEmpty()) { if (!isOutputEmpty()) {
return; return;
} }
if (!input->empty()) {
AudioThreadInput *audioInputData; AudioThreadInput *audioInputData;
input->pop(audioInputData);
if (input->try_pop(audioInputData)) {
if (!audioInputData) { if (!audioInputData) {
return; return;
@ -271,5 +271,5 @@ void ScopeVisualProcessor::process() {
} else { } else {
delete audioInputData; //->decRefCount(); delete audioInputData; //->decRefCount();
} }
} } //end if try_pop()
} }

View File

@ -215,11 +215,14 @@ void SDRPostThread::run() {
if (doUpdate) { if (doUpdate) {
updateActiveDemodulators(); updateActiveDemodulators();
} }
} } //end while
if (iqVisualQueue && !iqVisualQueue->empty()) { //TODO: Why only 1 element was removed before ?
DemodulatorThreadIQData *visualDataDummy; DemodulatorThreadIQData *visualDataDummy;
iqVisualQueue->pop(visualDataDummy); while (iqVisualQueue && iqVisualQueue->try_pop(visualDataDummy)) {
//nothing
//TODO: What about the refcounts ?
} }
// buffers.purge(); // buffers.purge();

View File

@ -162,6 +162,7 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
int nElems = numElems.load(); int nElems = numElems.load();
int mtElems = mtuElems.load(); int mtElems = mtuElems.load();
//If overflow occured on the previous readStream(), transfer it in inpBuffer now
if (numOverflow > 0) { if (numOverflow > 0) {
int n_overflow = numOverflow; int n_overflow = numOverflow;
if (n_overflow > nElems) { if (n_overflow > nElems) {
@ -176,9 +177,18 @@ void SDRThread::readStream(SDRThreadIQDataQueue* iqDataOutQueue) {
} }
} }
//attempt readStream() at most nElems, by mtElems-sized chunks, append inpBuffer.
while (n_read < nElems && !stopping) { while (n_read < nElems && !stopping) {
int n_requested = nElems-n_read; int n_requested = nElems-n_read;
int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs); int n_stream_read = device->readStream(stream, buffs, mtElems, flags, timeNs);
//if the n_stream_read <= 0, bail out from reading.
if (n_stream_read <= 0) {
break;
}
//sucess read beyond nElems, with overflow
if ((n_read + n_stream_read) > nElems) { if ((n_read + n_stream_read) > nElems) {
memcpy(&inpBuffer.data[n_read], buffs[0], n_requested * sizeof(float) * 2); memcpy(&inpBuffer.data[n_read], buffs[0], n_requested * sizeof(float) * 2);
numOverflow = n_stream_read-n_requested; numOverflow = n_stream_read-n_requested;

View File

@ -98,9 +98,8 @@ void ScopeCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
wxPaintDC dc(this); wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
while (!inputData.empty()) {
ScopeRenderData *avData; ScopeRenderData *avData;
inputData.pop(avData); while (inputData.try_pop(avData)) {
if (!avData->spectrum) { if (!avData->spectrum) {

View File

@ -51,10 +51,8 @@ void SpectrumCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {
wxPaintDC dc(this); wxPaintDC dc(this);
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
if (!visualDataQueue.empty()) {
SpectrumVisualData *vData; SpectrumVisualData *vData;
if (visualDataQueue.try_pop(vData)) {
visualDataQueue.pop(vData);
if (vData) { if (vData) {
spectrumPanel.setPoints(vData->spectrum_points); spectrumPanel.setPoints(vData->spectrum_points);

View File

@ -95,8 +95,8 @@ void WaterfallCanvas::processInputQueue() {
if (lpsIndex >= targetVis) { if (lpsIndex >= targetVis) {
while (lpsIndex >= targetVis) { while (lpsIndex >= targetVis) {
SpectrumVisualData *vData; SpectrumVisualData *vData;
if (!visualDataQueue.empty()) {
visualDataQueue.pop(vData); if (visualDataQueue.try_pop(vData)) {
if (vData) { if (vData) {
if (vData->spectrum_points.size() == fft_size * 2) { if (vData->spectrum_points.size() == fft_size * 2) {
@ -912,10 +912,12 @@ void WaterfallCanvas::updateCenterFrequency(long long freq) {
void WaterfallCanvas::setLinesPerSecond(int lps) { void WaterfallCanvas::setLinesPerSecond(int lps) {
std::lock_guard < std::mutex > lock(tex_update); std::lock_guard < std::mutex > lock(tex_update);
linesPerSecond = lps; linesPerSecond = lps;
while (!visualDataQueue.empty()) {
//empty all
SpectrumVisualData *vData; SpectrumVisualData *vData;
visualDataQueue.pop(vData); while (visualDataQueue.try_pop(vData)) {
if (vData) { if (vData) {
vData->decRefCount(); vData->decRefCount();