Initial AudioSink thread base and recoring preference

This commit is contained in:
Charles J. Cliffe 2017-09-24 23:50:08 -04:00
parent 927d727a16
commit a398bc57f1
8 changed files with 150 additions and 1 deletions

View File

@ -347,6 +347,7 @@ SET (cubicsdr_sources
src/modules/modem/analog/ModemLSB.cpp
src/modules/modem/analog/ModemUSB.cpp
src/audio/AudioThread.cpp
src/audio/AudioSinkThread.cpp
src/util/Gradient.cpp
src/util/Timer.cpp
src/util/MouseTracker.cpp
@ -451,6 +452,7 @@ SET (cubicsdr_headers
src/modules/modem/analog/ModemLSB.h
src/modules/modem/analog/ModemUSB.h
src/audio/AudioThread.h
src/audio/AudioSinkThread.h
src/util/Gradient.h
src/util/Timer.h
src/util/ThreadBlockingQueue.h

View File

@ -505,6 +505,14 @@ bool AppConfig::getBookmarksVisible() {
return bookmarksVisible.load();
}
void AppConfig::setRecordingPath(std::string recPath) {
recordingPath = recPath;
}
std::string AppConfig::getRecordingPath() {
return recordingPath;
}
void AppConfig::setConfigName(std::string configName) {
this->configName = configName;
@ -559,6 +567,9 @@ bool AppConfig::save() {
*window_node->newChild("bookmark_visible") = bookmarksVisible.load();
}
DataNode *rec_node = cfg.rootNode()->newChild("recording");
*rec_node->newChild("path") = recordingPath;
DataNode *devices_node = cfg.rootNode()->newChild("devices");
std::map<std::string, DeviceConfig *>::iterator device_config_i;
@ -741,6 +752,15 @@ bool AppConfig::load() {
}
}
if (cfg.rootNode()->hasAnother("recording")) {
DataNode *rec_node = cfg.rootNode()->getNext("recording");
if (rec_node->hasAnother("path")) {
DataNode *rec_path = cfg.rootNode()->getNext("path");
recordingPath = rec_path->element()->toString();
}
}
if (cfg.rootNode()->hasAnother("devices")) {
DataNode *devices_node = cfg.rootNode()->getNext("devices");

View File

@ -138,6 +138,8 @@ public:
void setBookmarksVisible(bool state);
bool getBookmarksVisible();
void setRecordingPath(std::string recPath);
std::string getRecordingPath();
#if USE_HAMLIB
int getRigModel();
@ -185,6 +187,7 @@ private:
std::atomic_int dbOffset;
std::vector<SDRManualDef> manualDevices;
std::atomic_bool bookmarksVisible;
std::string recordingPath;
#if USE_HAMLIB
std::atomic_int rigModel, rigRate;
std::string rigPort;

View File

@ -412,6 +412,8 @@ AppFrame::AppFrame() :
menu->AppendSeparator();
menu->Append(wxID_SDR_START_STOP, "Stop / Start Device");
menu->AppendSeparator();
menu->Append(wxID_RECORDING_PATH, "Set Recording Path");
menu->AppendSeparator();
menu->Append(wxID_OPEN, "&Open Session");
menu->Append(wxID_SAVE, "&Save Session");
menu->Append(wxID_SAVEAS, "Save Session &As..");
@ -1564,6 +1566,16 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
}
}
}
else if (event.GetId() == wxID_RECORDING_PATH) {
std::string recPath = wxGetApp().getConfig()->getRecordingPath();
wxDirDialog recPathDialog(this, _("File Path for Recordings"), recPath, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if (recPathDialog.ShowModal() == wxID_CANCEL) {
return;
}
wxGetApp().getConfig()->setRecordingPath(recPathDialog.GetPath().ToStdString());
}
else if (event.GetId() == wxID_LOW_PERF) {
lowPerfMode = lowPerfMenuItem->IsChecked();
wxGetApp().getConfig()->setLowPerfMode(lowPerfMode);

View File

@ -42,6 +42,7 @@
#define wxID_LOW_PERF 2011
#define wxID_SET_DB_OFFSET 2012
#define wxID_ABOUT_CUBICSDR 2013
#define wxID_RECORDING_PATH 2014
#define wxID_MAIN_SPLITTER 2050
#define wxID_VIS_SPLITTER 2051

View File

@ -0,0 +1,83 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#include "AudioSinkThread.h"
#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000)
AudioSinkThread::AudioSinkThread()
{
inputQueuePtr = std::make_shared<AudioThreadInputQueue>();
setInputQueue("input", inputQueuePtr);
}
AudioSinkThread::~AudioSinkThread()
{
}
void AudioSinkThread::run()
{
#ifdef __APPLE__
pthread_t tID = pthread_self(); // ID of this thread
int priority = sched_get_priority_max(SCHED_RR) - 1;
sched_param prio = { priority }; // scheduling priority of thread
pthread_setschedparam(tID, SCHED_RR, &prio);
#endif
AudioThreadInputPtr inp;
AudioThreadInput inputRef;
while (!stopping) {
if (!inputQueuePtr->pop(inp, HEARTBEAT_CHECK_PERIOD_MICROS)) {
continue;
}
if (inputRef.channels != inp->channels ||
inputRef.frequency != inp->frequency ||
inputRef.inputRate != inp->inputRate ||
inputRef.sampleRate != inp->sampleRate) {
inputChanged(inputRef, inp);
inputRef.channels = inp->channels;
inputRef.frequency = inp->frequency;
inputRef.inputRate = inp->inputRate;
inputRef.sampleRate = inp->sampleRate;
}
}
//Thread termination, prevent fancy things to happen, lock the whole thing:
std::lock_guard<std::recursive_mutex> lock(m_mutex);
// Drain any remaining inputs, with a non-blocking pop
inputQueuePtr->flush();
}
void AudioSinkThread::terminate()
{
IOThread::terminate();
}
void AudioSinkThread::sink(AudioThreadInputPtr * input)
{
// do something with the audio data
}
void AudioSinkThread::inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps)
{
// handle changes in stream properties
}
void AudioSinkThread::setSinkName(std::string sinkName_in)
{
sinkName = sinkName_in;
}
std::string AudioSinkThread::getSinkName()
{
return sinkName;
}

View File

@ -0,0 +1,28 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#pragma once
#include "AudioThread.h"
class AudioSinkThread : public IOThread {
public:
AudioSinkThread();
virtual ~AudioSinkThread();
virtual void run();
virtual void terminate();
virtual void sink(AudioThreadInputPtr *input);
virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
virtual void setSinkName(std::string sinkName_in);
virtual std::string getSinkName();
protected:
std::recursive_mutex m_mutex;
AudioThreadInputQueuePtr inputQueuePtr;
std::string sinkName;
};

View File

@ -24,7 +24,7 @@ public:
std::vector<float> data;
AudioThreadInput() :
frequency(0), sampleRate(0), channels(0), peak(0) {
frequency(0), sampleRate(0), inputRate(0), channels(0), peak(0), type(0) {
}