Permalink
Browse files

Initial AudioSink thread base and recoring preference

  • Loading branch information...
cjcliffe committed Sep 25, 2017
1 parent 927d727 commit a398bc57f18784718d821798627691e28455eb7d
Showing with 150 additions and 1 deletion.
  1. +2 −0 CMakeLists.txt
  2. +20 −0 src/AppConfig.cpp
  3. +3 −0 src/AppConfig.h
  4. +12 −0 src/AppFrame.cpp
  5. +1 −0 src/AppFrame.h
  6. +83 −0 src/audio/AudioSinkThread.cpp
  7. +28 −0 src/audio/AudioSinkThread.h
  8. +1 −1 src/audio/AudioThread.h
View
@@ -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
@@ -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
@@ -138,6 +138,8 @@ class AppConfig {
void setBookmarksVisible(bool state);
bool getBookmarksVisible();
void setRecordingPath(std::string recPath);
std::string getRecordingPath();
#if USE_HAMLIB
int getRigModel();
@@ -185,6 +187,7 @@ class AppConfig {
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
@@ -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
@@ -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
@@ -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();

This comment has been minimized.

Show comment
Hide comment
@vsonnier

vsonnier Sep 26, 2017

Collaborator

@cjcliffe Hi! The idea is to put also inputQueuePtr->flush() in the terminate call, so that any waiting push() by another thread is unblocked.

@vsonnier

vsonnier Sep 26, 2017

Collaborator

@cjcliffe Hi! The idea is to put also inputQueuePtr->flush() in the terminate call, so that any waiting push() by another thread is unblocked.

This comment has been minimized.

Show comment
Hide comment
@cjcliffe

cjcliffe Sep 27, 2017

Owner

@vsonnier gotcha, thanks -- I copied that one from the AudioThread by mistake instead of a simpler case.

@cjcliffe

cjcliffe Sep 27, 2017

Owner

@vsonnier gotcha, thanks -- I copied that one from the AudioThread by mistake instead of a simpler case.

}
void AudioSinkThread::sink(AudioThreadInputPtr * input)

This comment has been minimized.

Show comment
Hide comment
@vsonnier

vsonnier Sep 26, 2017

Collaborator

@cjcliffe Simply AudioThreadInputPtr and not AudioThreadInputPtr * is the right syntax here. The std::shared_ptr is naturally handled using a pass-by-value sementic so that the assignment and copy constructors works correctly to reference count the underlaying resource.

@vsonnier

vsonnier Sep 26, 2017

Collaborator

@cjcliffe Simply AudioThreadInputPtr and not AudioThreadInputPtr * is the right syntax here. The std::shared_ptr is naturally handled using a pass-by-value sementic so that the assignment and copy constructors works correctly to reference count the underlaying resource.

This comment has been minimized.

Show comment
Hide comment
@cjcliffe

cjcliffe Sep 27, 2017

Owner

@vsonnier Ah, that makes sense -- didn't catch that but it seems like it would have worked somehow since there wasn't a compile error -- but I might have hit some problems once I implement an AudioSink subclass 👍

@cjcliffe

cjcliffe Sep 27, 2017

Owner

@vsonnier Ah, that makes sense -- didn't catch that but it seems like it would have worked somehow since there wasn't a compile error -- but I might have hit some problems once I implement an AudioSink subclass 👍

{
// 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;
}
@@ -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
@@ -24,7 +24,7 @@ class AudioThreadInput {
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) {
}

1 comment on commit a398bc5

@parkerlreed

This comment has been minimized.

Show comment
Hide comment
@parkerlreed

parkerlreed Sep 26, 2017

👍 :D I was just thinking about this the other day.

parkerlreed commented on a398bc5 Sep 26, 2017

👍 :D I was just thinking about this the other day.

Please sign in to comment.