mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-13 22:12:51 +01:00
convert network sink to new stream system
This commit is contained in:
parent
139f63ad25
commit
cd7dabda51
@ -17,6 +17,8 @@ namespace streamsmenu {
|
|||||||
std::map<std::string, int> selectedSinkTypeId;
|
std::map<std::string, int> selectedSinkTypeId;
|
||||||
std::map<std::string, int> addSinkTypeId;
|
std::map<std::string, int> addSinkTypeId;
|
||||||
|
|
||||||
|
int addType = 0;
|
||||||
|
|
||||||
void updateSinkTypeList(const std::string& removed = "") {
|
void updateSinkTypeList(const std::string& removed = "") {
|
||||||
std::lock_guard<std::recursive_mutex> lck1(sinkTypesMtx);
|
std::lock_guard<std::recursive_mutex> lck1(sinkTypesMtx);
|
||||||
auto lck2 = sigpath::streamManager.getSinkTypesLock();
|
auto lck2 = sigpath::streamManager.getSinkTypesLock();
|
||||||
@ -32,6 +34,9 @@ namespace streamsmenu {
|
|||||||
// Update the list
|
// Update the list
|
||||||
updateSinkTypeList();
|
updateSinkTypeList();
|
||||||
|
|
||||||
|
// Update the ID of the Add dropdown
|
||||||
|
// TODO
|
||||||
|
|
||||||
// Update the selected ID of each drop down
|
// Update the selected ID of each drop down
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@ -40,6 +45,9 @@ namespace streamsmenu {
|
|||||||
// Update the list
|
// Update the list
|
||||||
updateSinkTypeList(type);
|
updateSinkTypeList(type);
|
||||||
|
|
||||||
|
// Update the ID of the Add dropdown
|
||||||
|
// TODO
|
||||||
|
|
||||||
// Update the selected ID of each drop down
|
// Update the selected ID of each drop down
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@ -137,18 +145,16 @@ namespace streamsmenu {
|
|||||||
float tableWidth = ImGui::GetContentRegionAvail().x;
|
float tableWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
int ssds = 0;
|
|
||||||
int startCur = ImGui::GetCursorPosX();
|
int startCur = ImGui::GetCursorPosX();
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lck(sinkTypesMtx);
|
std::lock_guard<std::recursive_mutex> lck(sinkTypesMtx);
|
||||||
ImGui::Combo(CONCAT("##sdrpp_streams_add_type_", name), &ssds, sinkTypes.txt);
|
ImGui::Combo(CONCAT("##sdrpp_streams_add_type_", name), &addType, sinkTypes.txt);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(CONCAT("Add##sdrpp_streams_add_btn_", name), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
|
||||||
|
stream->addSink(sinkTypes.value(addType));
|
||||||
|
}
|
||||||
|
ImGui::Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button(CONCAT("Add##sdrpp_streams_add_btn_", name), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
|
|
||||||
stream->addSink("Audio");
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ SDRPP_MOD_INFO{
|
|||||||
/* Name: */ "audio_sink",
|
/* Name: */ "audio_sink",
|
||||||
/* Description: */ "Audio sink module for SDR++",
|
/* Description: */ "Audio sink module for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ 0, 1, 0,
|
/* Version: */ 0, 2, 0,
|
||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
#include <module.h>
|
#include <module.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <signal_path/signal_path.h>
|
#include <signal_path/signal_path.h>
|
||||||
#include <signal_path/sink.h>
|
#include <signal_path/stream.h>
|
||||||
#include <dsp/buffer/packer.h>
|
#include <dsp/buffer/packer.h>
|
||||||
#include <dsp/convert/stereo_to_mono.h>
|
#include <dsp/convert/stereo_to_mono.h>
|
||||||
#include <dsp/sink/handler_sink.h>
|
#include <dsp/sink/handler_sink.h>
|
||||||
#include <utils/flog.h>
|
#include <utils/flog.h>
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <gui/style.h>
|
#include <gui/style.h>
|
||||||
|
#include <utils/optionlist.h>
|
||||||
#include <core.h>
|
#include <core.h>
|
||||||
|
|
||||||
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
#define CONCAT(a, b) ((std::string(a) + b).c_str())
|
||||||
@ -18,84 +19,97 @@ SDRPP_MOD_INFO{
|
|||||||
/* Name: */ "network_sink",
|
/* Name: */ "network_sink",
|
||||||
/* Description: */ "Network sink module for SDR++",
|
/* Description: */ "Network sink module for SDR++",
|
||||||
/* Author: */ "Ryzerth",
|
/* Author: */ "Ryzerth",
|
||||||
/* Version: */ 0, 1, 0,
|
/* Version: */ 0, 2, 0,
|
||||||
/* Max instances */ 1
|
/* Max instances */ 1
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigManager config;
|
ConfigManager config;
|
||||||
|
|
||||||
enum {
|
enum SinkMode {
|
||||||
SINK_MODE_TCP,
|
SINK_MODE_TCP,
|
||||||
SINK_MODE_UDP
|
SINK_MODE_UDP
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* sinkModesTxt = "TCP\0UDP\0";
|
const char* sinkModesTxt = "TCP\0UDP\0";
|
||||||
|
|
||||||
class NetworkSink : SinkManager::Sink {
|
class NetworkSink : public Sink {
|
||||||
public:
|
public:
|
||||||
NetworkSink(SinkManager::Stream* stream, std::string streamName) {
|
NetworkSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) :
|
||||||
_stream = stream;
|
Sink(entry, stream, name, id, stringId)
|
||||||
_streamName = streamName;
|
{
|
||||||
|
// Define modes
|
||||||
|
modes.define("TCP", SINK_MODE_TCP);
|
||||||
|
modes.define("UDP", SINK_MODE_UDP);
|
||||||
|
|
||||||
// Load config
|
// Create a list of sample rates
|
||||||
config.acquire();
|
std::vector<int> srList;
|
||||||
if (!config.conf.contains(_streamName)) {
|
for (int sr = 12000; sr <= 200000; sr += 12000) {
|
||||||
config.conf[_streamName]["hostname"] = "localhost";
|
srList.push_back(sr);
|
||||||
config.conf[_streamName]["port"] = 7355;
|
}
|
||||||
config.conf[_streamName]["protocol"] = SINK_MODE_UDP; // UDP
|
for (int sr = 11025; sr <= 192000; sr += 11025) {
|
||||||
config.conf[_streamName]["sampleRate"] = 48000.0;
|
srList.push_back(sr);
|
||||||
config.conf[_streamName]["stereo"] = false;
|
|
||||||
config.conf[_streamName]["listening"] = false;
|
|
||||||
}
|
}
|
||||||
std::string host = config.conf[_streamName]["hostname"];
|
|
||||||
strcpy(hostname, host.c_str());
|
|
||||||
port = config.conf[_streamName]["port"];
|
|
||||||
modeId = config.conf[_streamName]["protocol"];
|
|
||||||
sampleRate = config.conf[_streamName]["sampleRate"];
|
|
||||||
stereo = config.conf[_streamName]["stereo"];
|
|
||||||
bool startNow = config.conf[_streamName]["listening"];
|
|
||||||
config.release(true);
|
|
||||||
|
|
||||||
|
// Sort sample rate list
|
||||||
|
std::sort(srList.begin(), srList.end(), [](double a, double b) { return (a < b); });
|
||||||
|
|
||||||
|
// Define samplerate options
|
||||||
|
for (int sr : srList) {
|
||||||
|
char buf[16];
|
||||||
|
sprintf(buf, "%d", sr);
|
||||||
|
samplerates.define(sr, buf, sr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate buffer
|
||||||
netBuf = new int16_t[STREAM_BUFFER_SIZE];
|
netBuf = new int16_t[STREAM_BUFFER_SIZE];
|
||||||
|
|
||||||
packer.init(_stream->sinkOut, 512);
|
// Init DSP
|
||||||
|
packer.init(stream, 512);
|
||||||
s2m.init(&packer.out);
|
s2m.init(&packer.out);
|
||||||
monoSink.init(&s2m.out, monoHandler, this);
|
monoSink.init(&s2m.out, monoHandler, this);
|
||||||
stereoSink.init(&packer.out, stereoHandler, this);
|
stereoSink.init(&packer.out, stereoHandler, this);
|
||||||
|
|
||||||
|
// Load config
|
||||||
// Create a list of sample rates
|
config.acquire();
|
||||||
for (int sr = 12000; sr < 200000; sr += 12000) {
|
bool startNow = false;
|
||||||
sampleRates.push_back(sr);
|
if (config.conf[stringId].contains("hostname")) {
|
||||||
|
std::string host = config.conf[stringId]["hostname"];
|
||||||
|
strcpy(hostname, host.c_str());
|
||||||
}
|
}
|
||||||
for (int sr = 11025; sr < 192000; sr += 11025) {
|
if (config.conf[stringId].contains("port")) {
|
||||||
sampleRates.push_back(sr);
|
port = config.conf[stringId]["port"];
|
||||||
}
|
}
|
||||||
|
if (config.conf[stringId].contains("mode")) {
|
||||||
// Sort sample rate list
|
std::string modeStr = config.conf[stringId]["mode"];
|
||||||
std::sort(sampleRates.begin(), sampleRates.end(), [](double a, double b) { return (a < b); });
|
if (modes.keyExists(modeStr)) {
|
||||||
|
mode = modes.value(modes.keyId(modeStr));
|
||||||
// Generate text list for UI
|
}
|
||||||
char buffer[128];
|
else {
|
||||||
int id = 0;
|
mode = SINK_MODE_TCP;
|
||||||
int _48kId;
|
|
||||||
bool found = false;
|
|
||||||
for (auto sr : sampleRates) {
|
|
||||||
sprintf(buffer, "%d", (int)sr);
|
|
||||||
sampleRatesTxt += buffer;
|
|
||||||
sampleRatesTxt += '\0';
|
|
||||||
if (sr == sampleRate) {
|
|
||||||
srId = id;
|
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
if (sr == 48000.0) { _48kId = id; }
|
|
||||||
id++;
|
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (config.conf[stringId].contains("samplerate")) {
|
||||||
srId = _48kId;
|
int nSr = config.conf[stringId]["samplerate"];
|
||||||
sampleRate = 48000.0;
|
if (samplerates.keyExists(nSr)) {
|
||||||
|
sampleRate = samplerates.value(samplerates.keyId(nSr));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sampleRate = 48000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_stream->setSampleRate(sampleRate);
|
if (config.conf[stringId].contains("stereo")) {
|
||||||
|
stereo = config.conf[stringId]["stereo"];
|
||||||
|
}
|
||||||
|
if (config.conf[stringId].contains("running")) {
|
||||||
|
startNow = config.conf[stringId]["running"];
|
||||||
|
}
|
||||||
|
config.release();
|
||||||
|
|
||||||
|
// Set mode ID
|
||||||
|
modeId = modes.valueId(mode);
|
||||||
|
|
||||||
|
// Set samplerate ID
|
||||||
|
srId = samplerates.valueId(sampleRate);
|
||||||
|
|
||||||
// Start if needed
|
// Start if needed
|
||||||
if (startNow) { startServer(); }
|
if (startNow) { startServer(); }
|
||||||
@ -122,30 +136,30 @@ public:
|
|||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler() {
|
void showMenu() {
|
||||||
float menuWidth = ImGui::GetContentRegionAvail().x;
|
float menuWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
|
||||||
bool listening = (listener && listener->isListening()) || (conn && conn->isOpen());
|
bool listening = (listener && listener->isListening()) || (conn && conn->isOpen());
|
||||||
|
|
||||||
if (listening) { style::beginDisabled(); }
|
if (listening) { style::beginDisabled(); }
|
||||||
if (ImGui::InputText(CONCAT("##_network_sink_host_", _streamName), hostname, 1023)) {
|
if (ImGui::InputText(CONCAT("##_network_sink_host_", stringId), hostname, 1023)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["hostname"] = hostname;
|
config.conf[stringId]["hostname"] = hostname;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::InputInt(CONCAT("##_network_sink_port_", _streamName), &port, 0, 0)) {
|
if (ImGui::InputInt(CONCAT("##_network_sink_port_", stringId), &port, 0, 0)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["port"] = port;
|
config.conf[stringId]["port"] = port;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::LeftLabel("Protocol");
|
ImGui::LeftLabel("Protocol");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo(CONCAT("##_network_sink_mode_", _streamName), &modeId, sinkModesTxt)) {
|
if (ImGui::Combo(CONCAT("##_network_sink_mode_", stringId), &modeId, sinkModesTxt)) {
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["protocol"] = modeId;
|
config.conf[stringId]["mode"] = modeId;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,33 +167,33 @@ public:
|
|||||||
|
|
||||||
ImGui::LeftLabel("Samplerate");
|
ImGui::LeftLabel("Samplerate");
|
||||||
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
|
||||||
if (ImGui::Combo(CONCAT("##_network_sink_sr_", _streamName), &srId, sampleRatesTxt.c_str())) {
|
if (ImGui::Combo(CONCAT("##_network_sink_sr_", stringId), &srId, samplerates.txt)) {
|
||||||
sampleRate = sampleRates[srId];
|
sampleRate = samplerates.value(srId);
|
||||||
_stream->setSampleRate(sampleRate);
|
entry->setSamplerate(sampleRate);
|
||||||
packer.setSampleCount(sampleRate / 60);
|
packer.setSampleCount(sampleRate / 60);
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["sampleRate"] = sampleRate;
|
config.conf[stringId]["samplerate"] = sampleRate;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", _streamName), &stereo)) {
|
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", stringId), &stereo)) {
|
||||||
stop();
|
stop();
|
||||||
start();
|
start();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["stereo"] = stereo;
|
config.conf[stringId]["stereo"] = stereo;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
|
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
|
||||||
stopServer();
|
stopServer();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["listening"] = false;
|
config.conf[stringId]["running"] = false;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
|
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
|
||||||
startServer();
|
startServer();
|
||||||
config.acquire();
|
config.acquire();
|
||||||
config.conf[_streamName]["listening"] = true;
|
config.conf[stringId]["running"] = true;
|
||||||
config.release(true);
|
config.release(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,47 +285,40 @@ private:
|
|||||||
_this->listener->acceptAsync(clientHandler, _this);
|
_this->listener->acceptAsync(clientHandler, _this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SinkManager::Stream* _stream;
|
// DSP
|
||||||
dsp::buffer::Packer<dsp::stereo_t> packer;
|
dsp::buffer::Packer<dsp::stereo_t> packer;
|
||||||
dsp::convert::StereoToMono s2m;
|
dsp::convert::StereoToMono s2m;
|
||||||
dsp::sink::Handler<float> monoSink;
|
dsp::sink::Handler<float> monoSink;
|
||||||
dsp::sink::Handler<dsp::stereo_t> stereoSink;
|
dsp::sink::Handler<dsp::stereo_t> stereoSink;
|
||||||
|
|
||||||
std::string _streamName;
|
OptionList<std::string, SinkMode> modes;
|
||||||
|
OptionList<int, double> samplerates;
|
||||||
int srId = 0;
|
|
||||||
bool running = false;
|
|
||||||
|
|
||||||
char hostname[1024];
|
char hostname[1024];
|
||||||
int port = 4242;
|
int port = 7355;
|
||||||
|
SinkMode mode = SINK_MODE_TCP;
|
||||||
int modeId = 1;
|
int modeId;
|
||||||
|
int sampleRate = 48000;
|
||||||
std::vector<unsigned int> sampleRates;
|
int srId;
|
||||||
std::string sampleRatesTxt;
|
|
||||||
unsigned int sampleRate = 48000;
|
|
||||||
bool stereo = false;
|
bool stereo = false;
|
||||||
|
bool running = false;
|
||||||
|
|
||||||
int16_t* netBuf;
|
int16_t* netBuf;
|
||||||
|
|
||||||
net::Listener listener;
|
net::Listener listener;
|
||||||
net::Conn conn;
|
net::Conn conn;
|
||||||
std::mutex connMtx;
|
std::mutex connMtx;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkSinkModule : public ModuleManager::Instance {
|
class NetworkSinkModule : public ModuleManager::Instance, SinkProvider {
|
||||||
public:
|
public:
|
||||||
NetworkSinkModule(std::string name) {
|
NetworkSinkModule(std::string name) {
|
||||||
this->name = name;
|
// Register self as provider
|
||||||
provider.create = create_sink;
|
sigpath::streamManager.registerSinkProvider("Network", this);
|
||||||
provider.ctx = this;
|
|
||||||
|
|
||||||
sigpath::sinkManager.registerSinkProvider("Network", provider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~NetworkSinkModule() {
|
~NetworkSinkModule() {
|
||||||
// Unregister sink, this will automatically stop and delete all instances of the audio sink
|
// Unregister self
|
||||||
sigpath::sinkManager.unregisterSinkProvider("Network");
|
sigpath::streamManager.unregisterSinkProvider(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void postInit() {}
|
void postInit() {}
|
||||||
@ -328,14 +335,13 @@ public:
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
std::unique_ptr<Sink> createSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) {
|
||||||
static SinkManager::Sink* create_sink(SinkManager::Stream* stream, std::string streamName, void* ctx) {
|
return std::make_unique<NetworkSink>(entry, stream, name, id, stringId);
|
||||||
return (SinkManager::Sink*)(new NetworkSink(stream, streamName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
SinkManager::SinkProvider provider;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MOD_EXPORT void _INIT_() {
|
MOD_EXPORT void _INIT_() {
|
||||||
|
Loading…
Reference in New Issue
Block a user