Commit 683a207e authored by Andreas Bombe's avatar Andreas Bombe

New upstream version 0.2.4+dfsg

parent 5c6e0ed7
......@@ -6,7 +6,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
SET(CUBICSDR_VERSION_MAJOR "0")
SET(CUBICSDR_VERSION_MINOR "2")
SET(CUBICSDR_VERSION_PATCH "3")
SET(CUBICSDR_VERSION_PATCH "4")
SET(CUBICSDR_VERSION_SUFFIX "")
SET(CUBICSDR_VERSION "${CUBICSDR_VERSION_MAJOR}.${CUBICSDR_VERSION_MINOR}.${CUBICSDR_VERSION_PATCH}${CUBICSDR_VERSION_SUFFIX}")
......
......@@ -22,7 +22,7 @@ Utilizes:
Optional Libs:
--------
- FFTW3 (can be compiled into liquid-dsp if desired) (http://www.fftw.org/ -- https://github.com/FFTW/fftw3)
- hamlib (https://sourceforge.net/p/hamlib/wiki/Hamlib/ -- https://sourceforge.net/p/hamlib/code/ci/master/tree/)
- hamlib (https://github.com/Hamlib/Hamlib)
Features and Status:
--------------------
......
......@@ -88,10 +88,10 @@ AppFrame::AppFrame() :
wxBoxSizer *demodScopeTray = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *demodTunerTray = new wxBoxSizer(wxHORIZONTAL);
std::vector<int> attribList = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
//wxGLAttributes attribList;
//attribList.PlatformDefaults().RGBA().DoubleBuffer().EndList();
//attribList.PlatformDefaults().MinRGBA(8, 8, 8, 8).DoubleBuffer().Depth(16).EndList();
// OpenGL settings:
//deprecated format: std::vector<int> attribList = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0 };
wxGLAttributes attribList;
attribList.PlatformDefaults().RGBA().MinRGBA(8, 8, 8, 8).DoubleBuffer().EndList();
mainSplitter = new wxSplitterWindow( this, wxID_MAIN_SPLITTER, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH | wxSP_LIVE_UPDATE );
mainSplitter->SetSashGravity(10.0f / 37.0f);
......@@ -2971,26 +2971,28 @@ void AppFrame::toggleAllActiveDemodRecording() {
return;
}
auto activeDemods = wxGetApp().getDemodMgr().getDemodulators();
// All demods, irrespective of their active state:
// recording will start eventually when a demod come in range.
auto allDemods = wxGetApp().getDemodMgr().getDemodulators();
//by default, do a false => true for all:
bool stateToSet = true;
for (auto i : activeDemods) {
if (i->isActive() && i->isRecording()) {
for (auto i : allDemods) {
if (i->isRecording()) {
stateToSet = false;
break;
}
}
for (auto i : activeDemods) {
if (i->isActive() && i->isRecording() != stateToSet) {
i->setRecording(stateToSet);
}
for (auto i : allDemods) {
i->setRecording(stateToSet);
}
//this effectively refresh the BookmarkView buttons, including Recording buttons.
wxGetApp().getBookmarkMgr().updateActiveList();
}
void AppFrame::setWaterfallLinesPerSecond(int lps) {
waterfallSpeedMeter->setUserInputValue(sqrt(lps));
}
......
......@@ -15,12 +15,11 @@ BookmarkEntry::~BookmarkEntry() {
BookmarkMgr::BookmarkMgr() {
rangesSorted = false;
}
//represents an empty BookMarkList that is returned by reference by some functions.
const BookmarkList BookmarkMgr::emptyResults;
//
void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup, bool useFullpath) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
DataTree s("cubicsdr_bookmarks");
DataNode *header = s.rootNode()->newChild("header");
header->newChild("version")->element()->set(wxString(CUBICSDR_VERSION).ToStdWstring());
......@@ -100,6 +99,8 @@ void BookmarkMgr::saveToFile(std::string bookmarkFn, bool backup, bool useFullpa
}
bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFullpath) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
wxFileName loadFile;
wxFileName failFile;
......@@ -129,7 +130,7 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFull
// New instance of bookmark savefiles
if (backup && !loadFile.FileExists() && !lastLoaded.FileExists() && !backupFile.FileExists()) {
wxGetApp().getAppFrame()->getBookmarkView()->loadDefaultRanges();
loadDefaultRanges();
return true;
}
......@@ -145,8 +146,8 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFull
// Clear any active data
bmData.clear();
clearRecents();
clearRanges();
recents.clear();
ranges.clear();
bmDataSorted.clear();
if (s.rootNode()->hasAnother("branches")) {
......@@ -238,15 +239,31 @@ bool BookmarkMgr::loadFromFile(std::string bookmarkFn, bool backup, bool useFull
return loadStatusOk;
}
void BookmarkMgr::loadDefaultRanges() {
addRange(std::make_shared<BookmarkRangeEntry>(L"160 Meters", 1900000, 1800000, 2000000));
addRange(std::make_shared<BookmarkRangeEntry>(L"80 Meters", 3750000, 3500000, 4000000));
addRange(std::make_shared<BookmarkRangeEntry>(L"60 Meters", 5368500, 5332000, 5405000));
addRange(std::make_shared<BookmarkRangeEntry>(L"40 Meters", 7150000, 7000000, 7300000));
addRange(std::make_shared<BookmarkRangeEntry>(L"30 Meters", 10125000, 10100000, 10150000));
addRange(std::make_shared<BookmarkRangeEntry>(L"20 Meters", 14175000, 14000000, 14350000));
addRange(std::make_shared<BookmarkRangeEntry>(L"17 Meters", 18068180, 17044180, 19092180));
addRange(std::make_shared<BookmarkRangeEntry>(L"15 Meters", 21225000, 21000000, 21450000));
addRange(std::make_shared<BookmarkRangeEntry>(L"12 Meters", 24940000, 24890000, 24990000));
addRange(std::make_shared<BookmarkRangeEntry>(L"10 Meters", 28850000, 28000000, 29700000));
}
void BookmarkMgr::resetBookmarks() {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
// Clear any active data
bmData.clear();
clearRecents();
clearRanges();
recents.clear();
ranges.clear();
bmDataSorted.clear();
wxGetApp().getAppFrame()->getBookmarkView()->loadDefaultRanges();
loadDefaultRanges();
}
......@@ -280,9 +297,8 @@ void BookmarkMgr::addBookmark(std::string group, BookmarkEntryPtr be) {
void BookmarkMgr::removeBookmark(std::string group, BookmarkEntryPtr be) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
std::lock_guard < std::mutex > lockEnt(be->busy_lock);
std::lock_guard < std::recursive_mutex > lock(busy_lock);
if (bmData.find(group) == bmData.end()) {
return;
}
......@@ -296,8 +312,7 @@ void BookmarkMgr::removeBookmark(std::string group, BookmarkEntryPtr be) {
}
void BookmarkMgr::removeBookmark(BookmarkEntryPtr be) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
std::lock_guard < std::mutex > lockEnt(be->busy_lock);
std::lock_guard < std::recursive_mutex > lock(busy_lock);
for (auto &bmd_i : bmData) {
BookmarkList::iterator i = std::find(bmd_i.second.begin(), bmd_i.second.end(), be);
......@@ -308,8 +323,7 @@ void BookmarkMgr::removeBookmark(BookmarkEntryPtr be) {
}
void BookmarkMgr::moveBookmark(BookmarkEntryPtr be, std::string group) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
std::lock_guard < std::mutex > lockEnt(be->busy_lock);
std::lock_guard < std::recursive_mutex > lock(busy_lock);
for (auto &bmd_i : bmData) {
BookmarkList::iterator i = std::find(bmd_i.second.begin(), bmd_i.second.end(), be);
......@@ -367,11 +381,11 @@ void BookmarkMgr::renameGroup(std::string group, std::string ngroup) {
}
}
const BookmarkList& BookmarkMgr::getBookmarks(std::string group) {
BookmarkList BookmarkMgr::getBookmarks(std::string group) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
if (bmData.find(group) == bmData.end()) {
return emptyResults;
return BookmarkList();
}
if (!bmDataSorted[group]) {
......@@ -384,7 +398,7 @@ const BookmarkList& BookmarkMgr::getBookmarks(std::string group) {
void BookmarkMgr::getGroups(BookmarkNames &arr) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
std::lock_guard < std::recursive_mutex > lock(busy_lock);
for (BookmarkMap::iterator i = bmData.begin(); i!= bmData.end(); ++i) {
arr.push_back(i->first);
......@@ -392,7 +406,7 @@ void BookmarkMgr::getGroups(BookmarkNames &arr) {
}
void BookmarkMgr::getGroups(wxArrayString &arr) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
std::lock_guard < std::recursive_mutex > lock(busy_lock);
for (BookmarkMap::iterator i = bmData.begin(); i!= bmData.end(); ++i) {
arr.push_back(i->first);
......@@ -401,11 +415,16 @@ void BookmarkMgr::getGroups(wxArrayString &arr) {
void BookmarkMgr::setExpandState(std::string groupName, bool state) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
expandState[groupName] = state;
}
bool BookmarkMgr::getExpandState(std::string groupName) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
if (expandState.find(groupName) == expandState.end()) {
return true;
}
......@@ -415,8 +434,6 @@ bool BookmarkMgr::getExpandState(std::string groupName) {
void BookmarkMgr::updateActiveList() {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
if (wxGetApp().isShuttingDown()) {
return;
}
......@@ -430,8 +447,6 @@ void BookmarkMgr::updateActiveList() {
void BookmarkMgr::updateBookmarks() {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
BookmarkView *bmv = wxGetApp().getAppFrame()->getBookmarkView();
if (bmv) {
......@@ -441,8 +456,6 @@ void BookmarkMgr::updateBookmarks() {
void BookmarkMgr::updateBookmarks(std::string group) {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
BookmarkView *bmv = wxGetApp().getAppFrame()->getBookmarkView();
if (bmv) {
......@@ -480,9 +493,10 @@ void BookmarkMgr::removeRecent(BookmarkEntryPtr be) {
}
const BookmarkList& BookmarkMgr::getRecents() {
std::lock_guard < std::recursive_mutex > lockData(busy_lock);
return recents;
BookmarkList BookmarkMgr::getRecents() {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
//return a copy
return recents;
}
......@@ -508,8 +522,6 @@ void BookmarkMgr::addRange(BookmarkRangeEntryPtr re) {
rangesSorted = false;
}
void BookmarkMgr::removeRange(BookmarkRangeEntryPtr re) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
......@@ -522,7 +534,7 @@ void BookmarkMgr::removeRange(BookmarkRangeEntryPtr re) {
}
const BookmarkRangeList& BookmarkMgr::getRanges() {
BookmarkRangeList BookmarkMgr::getRanges() {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
if (!rangesSorted) {
......@@ -610,8 +622,6 @@ std::wstring BookmarkMgr::getActiveDisplayName(DemodulatorInstancePtr demod) {
void BookmarkMgr::removeActive(DemodulatorInstancePtr demod) {
std::lock_guard < std::recursive_mutex > lock(busy_lock);
if (demod == nullptr) {
return;
}
......
......@@ -16,8 +16,7 @@ class DataNode;
class BookmarkEntry {
public:
std::mutex busy_lock;
std::string type;
//maps on the Demod user label.
std::wstring label;
......@@ -38,9 +37,7 @@ public:
}
BookmarkRangeEntry(std::wstring label, long long freq, long long startFreq, long long endFreq) : label(label), freq(freq), startFreq(startFreq), endFreq(endFreq) {
}
std::mutex busy_lock;
std::wstring label;
long long freq;
......@@ -97,7 +94,9 @@ public:
void addGroup(std::string group);
void removeGroup(std::string group);
void renameGroup(std::string group, std::string ngroup);
const BookmarkList& getBookmarks(std::string group);
//return an independent copy on purpose
BookmarkList getBookmarks(std::string group);
void getGroups(BookmarkNames &arr);
void getGroups(wxArrayString &arr);
......@@ -111,22 +110,29 @@ public:
void addRecent(DemodulatorInstancePtr demod);
void addRecent(BookmarkEntryPtr be);
void removeRecent(BookmarkEntryPtr be);
const BookmarkList& getRecents();
//return an independent copy on purpose
BookmarkList getRecents();
void clearRecents();
void removeActive(DemodulatorInstancePtr demod);
void addRange(BookmarkRangeEntryPtr re);
void removeRange(BookmarkRangeEntryPtr re);
const BookmarkRangeList& getRanges();
void clearRanges();
//return an independent copy on purpose
BookmarkRangeList getRanges();
void clearRanges();
static std::wstring getBookmarkEntryDisplayName(BookmarkEntryPtr bmEnt);
static std::wstring getActiveDisplayName(DemodulatorInstancePtr demod);
protected:
void trimRecents();
void loadDefaultRanges();
BookmarkEntryPtr demodToBookmarkEntry(DemodulatorInstancePtr demod);
BookmarkEntryPtr nodeToBookmark(DataNode *node);
......@@ -136,10 +142,8 @@ protected:
BookmarkList recents;
BookmarkRangeList ranges;
bool rangesSorted;
std::recursive_mutex busy_lock;
BookmarkExpandState expandState;
//represents an empty BookMarkList that is returned by reference by some functions.
static const BookmarkList emptyResults;
};
......@@ -206,6 +206,14 @@ CubicSDR::CubicSDR() : frequency(0), offset(0), ppm(0), snap(1), sampleRate(DEFA
shuttingDown.store(false);
fdlgTarget = FrequencyDialog::FDIALOG_TARGET_DEFAULT;
stoppedDev = nullptr;
//set OpenGL configuration:
m_glContextAttributes = new wxGLContextAttrs();
wxGLContextAttrs glSettings;
glSettings.PlatformDefaults().EndList();
*m_glContextAttributes = glSettings;
}
bool CubicSDR::OnInit() {
......@@ -484,11 +492,10 @@ int CubicSDR::OnExit() {
delete m_glContext;
m_glContext = nullptr;
std::cout << "Application termination complete." << std::endl << std::flush;
#ifdef __APPLE__
//
AudioThread::deviceCleanup();
#endif
std::cout << "Application termination complete." << std::endl << std::flush;
return wxApp::OnExit();
}
......@@ -496,13 +503,18 @@ int CubicSDR::OnExit() {
PrimaryGLContext& CubicSDR::GetContext(wxGLCanvas *canvas) {
PrimaryGLContext *glContext;
if (!m_glContext) {
m_glContext = new PrimaryGLContext(canvas, NULL);
m_glContext = new PrimaryGLContext(canvas, NULL, GetContextAttributes());
}
glContext = m_glContext;
return *glContext;
}
wxGLContextAttrs* CubicSDR::GetContextAttributes() {
return m_glContextAttributes;
}
void CubicSDR::OnInitCmdLine(wxCmdLineParser& parser) {
parser.SetDesc (commandLineInfo);
parser.SetSwitchChars (wxT("-"));
......
......@@ -71,6 +71,7 @@ public:
CubicSDR();
PrimaryGLContext &GetContext(wxGLCanvas *canvas);
wxGLContextAttrs* GetContextAttributes();
virtual bool OnInit();
virtual int OnExit();
......@@ -94,9 +95,7 @@ public:
void setAntennaName(const std::string& name);
const std::string& getAntennaName();
void setDBOffset(int ofs);
int getDBOffset();
void setSampleRate(long long rate_in);
long long getSampleRate();
......@@ -114,7 +113,7 @@ public:
DemodulatorThreadOutputQueuePtr getAudioVisualQueue();
DemodulatorThreadInputQueuePtr getIQVisualQueue();
DemodulatorThreadInputQueuePtr getWaterfallVisualQueue();
DemodulatorThreadInputQueuePtr getActiveDemodVisualQueue();
DemodulatorMgr &getDemodMgr();
BookmarkMgr &getBookmarkMgr();
......@@ -186,6 +185,8 @@ private:
AppFrame *appframe = nullptr;
AppConfig config;
PrimaryGLContext *m_glContext = nullptr;
wxGLContextAttrs *m_glContextAttributes = nullptr;
std::vector<SDRDeviceInfo *> *devs = nullptr;
DemodulatorMgr demodMgr;
......
......@@ -106,7 +106,7 @@ bool AudioFileWAV::closeFile()
// Fix the data chunk header to contain the data size
outputFileStream.seekp(dataChunkPos + 4);
write_word(outputFileStream, file_length - dataChunkPos + 8);
write_word(outputFileStream, file_length - (dataChunkPos + 8), 4);
// Fix the file header to contain the proper RIFF chunk size, which is (file size - 8) bytes
outputFileStream.seekp(0 + 4);
......
......@@ -14,23 +14,35 @@
//50 ms
#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000)
std::map<int, AudioThread *> AudioThread::deviceController;
std::map<int, AudioThread* > AudioThread::deviceController;
std::map<int, int> AudioThread::deviceSampleRate;
std::map<int, std::thread *> AudioThread::deviceThread;
std::recursive_mutex AudioThread::m_device_mutex;
AudioThread::AudioThread() : IOThread(), nBufferFrames(1024), sampleRate(0) {
AudioThread::AudioThread() : IOThread(), nBufferFrames(1024), sampleRate(0), controllerThread(nullptr) {
audioQueuePtr = 0;
underflowCount = 0;
active.store(false);
outputDevice.store(-1);
audioQueuePtr = 0;
underflowCount = 0;
active.store(false);
outputDevice.store(-1);
gain = 1.0;
}
AudioThread::~AudioThread() {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if (controllerThread != nullptr) {
//
//NOT PROTECTED by m_mutex on purpose, to prevent deadlocks with controllerThread
// it doesn't matter, it is only called when all "normal" audio threads are detached from the controller.
//
terminate();
controllerThread->join();
delete controllerThread;
controllerThread = nullptr;
}
}
std::recursive_mutex & AudioThread::getMutex()
......@@ -38,6 +50,11 @@ std::recursive_mutex & AudioThread::getMutex()
return m_mutex;
}
void AudioThread::attachControllerThread(std::thread* controllerThread_in) {
controllerThread = controllerThread_in;
}
void AudioThread::bindThread(AudioThread *other) {
std::lock_guard<std::recursive_mutex> lock(m_mutex);
......@@ -48,8 +65,8 @@ void AudioThread::bindThread(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);
......@@ -59,16 +76,20 @@ void AudioThread::removeThread(AudioThread *other) {
}
void AudioThread::deviceCleanup() {
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
//
//NOT PROTECTED by m_device_mutex on purpose, to prevent deadlocks with i->second->controllerThread
// it doesn't matter, it is only called when all "normal" audio threads are detached from the controller.
//
for (auto i = deviceController.begin(); i != deviceController.end(); i++) {
i->second->terminate();
delete i->second;
}
deviceController.clear();
}
static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned int nBufferFrames, double /* streamTime */, RtAudioStreamStatus status,
void *userData) {
void *userData) {
float *out = (float*)outputBuffer;
......@@ -76,8 +97,10 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
//actually active.
::memset(out, 0, nBufferFrames * 2 * sizeof(float));
AudioThread *src = (AudioThread *) userData;
//src in the controller thread:
AudioThread *src = (AudioThread *)userData;
//by construction, src is a controller thread, from deviceController:
std::lock_guard<std::recursive_mutex> lock(src->getMutex());
if (src->isTerminated()) {
......@@ -85,17 +108,12 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
}
if (status) {
std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush;
}
if (src->boundThreads.empty()) {
return 0;
std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl << std::flush;
}
double peak = 0.0;
//for all boundThreads
//Process the bound threads audio:
for (size_t j = 0; j < src->boundThreads.size(); j++) {
AudioThread *srcmix = src->boundThreads[j];
......@@ -110,23 +128,23 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
if (!srcmix->currentInput) {
srcmix->audioQueuePtr = 0;
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
continue;
}
continue;
}
if (srcmix->currentInput->sampleRate != src->getSampleRate()) {
while (srcmix->inputQueue->try_pop(srcmix->currentInput)) {
if (srcmix->currentInput) {
if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
break;
}
}
srcmix->currentInput = nullptr;
} //end while
......@@ -143,13 +161,13 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
if (!srcmix->inputQueue->empty()) {
srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) {
srcmix->currentInput = nullptr;
}
if (!srcmix->inputQueue->try_pop(srcmix->currentInput)) {
continue;
}
}
}
continue;
}
......@@ -163,7 +181,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) {
srcmix->currentInput = nullptr;
}
......@@ -171,7 +189,7 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
break;
}
double srcPeak = srcmix->currentInput->peak * srcmix->gain;
if (mixPeak < srcPeak) {
mixPeak = srcPeak;
......@@ -184,13 +202,14 @@ static int audioCallback(void *outputBuffer, void * /* inputBuffer */, unsigned
}
srcmix->audioQueuePtr++;
}
} else {
}
else {
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
srcmix->audioQueuePtr = 0;
if (srcmix->currentInput) {
srcmix->currentInput = nullptr;
}
......@@ -279,54 +298,55 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
}
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
AudioThread* matchingAudioThread = nullptr;
//scope lock here to minimize the common unique static lock contention
{
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
AudioThread* matchingControllerThread = nullptr;
if (deviceController.find(deviceId) != deviceController.end()) {
//scope lock here to minimize the common unique static lock contention
{
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
matchingAudioThread = deviceController[deviceId];
}
}
if (deviceController.find(deviceId) != deviceController.end()) {
//out-of-lock test
if (matchingAudioThread != nullptr) {
matchingControllerThread = deviceController[deviceId];
}
}
AudioThreadCommand refreshDevice;
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
refreshDevice.int_value = sampleRate;
//VSO : blocking push !
matchingAudioThread->getCommandQueue()->push(refreshDevice);
}
//out-of-lock test
if (matchingControllerThread != nullptr) {
AudioThreadCommand refreshDevice;
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
refreshDevice.int_value = sampleRate;
//VSO : blocking push !
matchingControllerThread->getCommandQueue()->push(refreshDevice);
}
}
void AudioThread::setSampleRate(int sampleRate) {
bool outputIsThis = false;
bool thisIsAController = false;
//scope lock here to minimize the common unique static lock contention
{
std::lock_guard<std::recursive_mutex> lock(m_device_mutex);
//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;
}
}
if (deviceController[outputDevice.load()] == this) {