Skip to content

Commit cd7dabd

Browse files
convert network sink to new stream system
1 parent 139f63a commit cd7dabd

File tree

3 files changed

+116
-104
lines changed

3 files changed

+116
-104
lines changed

core/src/gui/menus/streams.cpp

+14-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ namespace streamsmenu {
1717
std::map<std::string, int> selectedSinkTypeId;
1818
std::map<std::string, int> addSinkTypeId;
1919

20+
int addType = 0;
21+
2022
void updateSinkTypeList(const std::string& removed = "") {
2123
std::lock_guard<std::recursive_mutex> lck1(sinkTypesMtx);
2224
auto lck2 = sigpath::streamManager.getSinkTypesLock();
@@ -32,6 +34,9 @@ namespace streamsmenu {
3234
// Update the list
3335
updateSinkTypeList();
3436

37+
// Update the ID of the Add dropdown
38+
// TODO
39+
3540
// Update the selected ID of each drop down
3641
// TODO
3742
}
@@ -40,6 +45,9 @@ namespace streamsmenu {
4045
// Update the list
4146
updateSinkTypeList(type);
4247

48+
// Update the ID of the Add dropdown
49+
// TODO
50+
4351
// Update the selected ID of each drop down
4452
// TODO
4553
}
@@ -137,18 +145,16 @@ namespace streamsmenu {
137145
float tableWidth = ImGui::GetContentRegionAvail().x;
138146

139147
ImGui::Spacing();
140-
int ssds = 0;
141148
int startCur = ImGui::GetCursorPosX();
142149
{
143150
std::lock_guard<std::recursive_mutex> lck(sinkTypesMtx);
144-
ImGui::Combo(CONCAT("##sdrpp_streams_add_type_", name), &ssds, sinkTypes.txt);
145-
}
146-
147-
ImGui::SameLine();
148-
if (ImGui::Button(CONCAT("Add##sdrpp_streams_add_btn_", name), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
149-
stream->addSink("Audio");
151+
ImGui::Combo(CONCAT("##sdrpp_streams_add_type_", name), &addType, sinkTypes.txt);
152+
ImGui::SameLine();
153+
if (ImGui::Button(CONCAT("Add##sdrpp_streams_add_btn_", name), ImVec2(tableWidth - (ImGui::GetCursorPosX() - startCur), 0))) {
154+
stream->addSink(sinkTypes.value(addType));
155+
}
156+
ImGui::Spacing();
150157
}
151-
ImGui::Spacing();
152158

153159
ImGui::EndTable();
154160

sink_modules/audio_sink/src/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ SDRPP_MOD_INFO{
1616
/* Name: */ "audio_sink",
1717
/* Description: */ "Audio sink module for SDR++",
1818
/* Author: */ "Ryzerth",
19-
/* Version: */ 0, 1, 0,
19+
/* Version: */ 0, 2, 0,
2020
/* Max instances */ 1
2121
};
2222

sink_modules/network_sink/src/main.cpp

+101-95
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
#include <module.h>
44
#include <gui/gui.h>
55
#include <signal_path/signal_path.h>
6-
#include <signal_path/sink.h>
6+
#include <signal_path/stream.h>
77
#include <dsp/buffer/packer.h>
88
#include <dsp/convert/stereo_to_mono.h>
99
#include <dsp/sink/handler_sink.h>
1010
#include <utils/flog.h>
1111
#include <config.h>
1212
#include <gui/style.h>
13+
#include <utils/optionlist.h>
1314
#include <core.h>
1415

1516
#define CONCAT(a, b) ((std::string(a) + b).c_str())
@@ -18,84 +19,97 @@ SDRPP_MOD_INFO{
1819
/* Name: */ "network_sink",
1920
/* Description: */ "Network sink module for SDR++",
2021
/* Author: */ "Ryzerth",
21-
/* Version: */ 0, 1, 0,
22+
/* Version: */ 0, 2, 0,
2223
/* Max instances */ 1
2324
};
2425

2526
ConfigManager config;
2627

27-
enum {
28+
enum SinkMode {
2829
SINK_MODE_TCP,
2930
SINK_MODE_UDP
3031
};
3132

3233
const char* sinkModesTxt = "TCP\0UDP\0";
3334

34-
class NetworkSink : SinkManager::Sink {
35+
class NetworkSink : public Sink {
3536
public:
36-
NetworkSink(SinkManager::Stream* stream, std::string streamName) {
37-
_stream = stream;
38-
_streamName = streamName;
37+
NetworkSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) :
38+
Sink(entry, stream, name, id, stringId)
39+
{
40+
// Define modes
41+
modes.define("TCP", SINK_MODE_TCP);
42+
modes.define("UDP", SINK_MODE_UDP);
3943

40-
// Load config
41-
config.acquire();
42-
if (!config.conf.contains(_streamName)) {
43-
config.conf[_streamName]["hostname"] = "localhost";
44-
config.conf[_streamName]["port"] = 7355;
45-
config.conf[_streamName]["protocol"] = SINK_MODE_UDP; // UDP
46-
config.conf[_streamName]["sampleRate"] = 48000.0;
47-
config.conf[_streamName]["stereo"] = false;
48-
config.conf[_streamName]["listening"] = false;
44+
// Create a list of sample rates
45+
std::vector<int> srList;
46+
for (int sr = 12000; sr <= 200000; sr += 12000) {
47+
srList.push_back(sr);
48+
}
49+
for (int sr = 11025; sr <= 192000; sr += 11025) {
50+
srList.push_back(sr);
51+
}
52+
53+
// Sort sample rate list
54+
std::sort(srList.begin(), srList.end(), [](double a, double b) { return (a < b); });
55+
56+
// Define samplerate options
57+
for (int sr : srList) {
58+
char buf[16];
59+
sprintf(buf, "%d", sr);
60+
samplerates.define(sr, buf, sr);
4961
}
50-
std::string host = config.conf[_streamName]["hostname"];
51-
strcpy(hostname, host.c_str());
52-
port = config.conf[_streamName]["port"];
53-
modeId = config.conf[_streamName]["protocol"];
54-
sampleRate = config.conf[_streamName]["sampleRate"];
55-
stereo = config.conf[_streamName]["stereo"];
56-
bool startNow = config.conf[_streamName]["listening"];
57-
config.release(true);
5862

63+
// Allocate buffer
5964
netBuf = new int16_t[STREAM_BUFFER_SIZE];
6065

61-
packer.init(_stream->sinkOut, 512);
66+
// Init DSP
67+
packer.init(stream, 512);
6268
s2m.init(&packer.out);
6369
monoSink.init(&s2m.out, monoHandler, this);
6470
stereoSink.init(&packer.out, stereoHandler, this);
6571

66-
67-
// Create a list of sample rates
68-
for (int sr = 12000; sr < 200000; sr += 12000) {
69-
sampleRates.push_back(sr);
72+
// Load config
73+
config.acquire();
74+
bool startNow = false;
75+
if (config.conf[stringId].contains("hostname")) {
76+
std::string host = config.conf[stringId]["hostname"];
77+
strcpy(hostname, host.c_str());
7078
}
71-
for (int sr = 11025; sr < 192000; sr += 11025) {
72-
sampleRates.push_back(sr);
79+
if (config.conf[stringId].contains("port")) {
80+
port = config.conf[stringId]["port"];
7381
}
74-
75-
// Sort sample rate list
76-
std::sort(sampleRates.begin(), sampleRates.end(), [](double a, double b) { return (a < b); });
77-
78-
// Generate text list for UI
79-
char buffer[128];
80-
int id = 0;
81-
int _48kId;
82-
bool found = false;
83-
for (auto sr : sampleRates) {
84-
sprintf(buffer, "%d", (int)sr);
85-
sampleRatesTxt += buffer;
86-
sampleRatesTxt += '\0';
87-
if (sr == sampleRate) {
88-
srId = id;
89-
found = true;
82+
if (config.conf[stringId].contains("mode")) {
83+
std::string modeStr = config.conf[stringId]["mode"];
84+
if (modes.keyExists(modeStr)) {
85+
mode = modes.value(modes.keyId(modeStr));
86+
}
87+
else {
88+
mode = SINK_MODE_TCP;
9089
}
91-
if (sr == 48000.0) { _48kId = id; }
92-
id++;
9390
}
94-
if (!found) {
95-
srId = _48kId;
96-
sampleRate = 48000.0;
91+
if (config.conf[stringId].contains("samplerate")) {
92+
int nSr = config.conf[stringId]["samplerate"];
93+
if (samplerates.keyExists(nSr)) {
94+
sampleRate = samplerates.value(samplerates.keyId(nSr));
95+
}
96+
else {
97+
sampleRate = 48000;
98+
}
99+
}
100+
if (config.conf[stringId].contains("stereo")) {
101+
stereo = config.conf[stringId]["stereo"];
102+
}
103+
if (config.conf[stringId].contains("running")) {
104+
startNow = config.conf[stringId]["running"];
97105
}
98-
_stream->setSampleRate(sampleRate);
106+
config.release();
107+
108+
// Set mode ID
109+
modeId = modes.valueId(mode);
110+
111+
// Set samplerate ID
112+
srId = samplerates.valueId(sampleRate);
99113

100114
// Start if needed
101115
if (startNow) { startServer(); }
@@ -122,64 +136,64 @@ class NetworkSink : SinkManager::Sink {
122136
running = false;
123137
}
124138

125-
void menuHandler() {
139+
void showMenu() {
126140
float menuWidth = ImGui::GetContentRegionAvail().x;
127141

128142
bool listening = (listener && listener->isListening()) || (conn && conn->isOpen());
129143

130144
if (listening) { style::beginDisabled(); }
131-
if (ImGui::InputText(CONCAT("##_network_sink_host_", _streamName), hostname, 1023)) {
145+
if (ImGui::InputText(CONCAT("##_network_sink_host_", stringId), hostname, 1023)) {
132146
config.acquire();
133-
config.conf[_streamName]["hostname"] = hostname;
147+
config.conf[stringId]["hostname"] = hostname;
134148
config.release(true);
135149
}
136150
ImGui::SameLine();
137151
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
138-
if (ImGui::InputInt(CONCAT("##_network_sink_port_", _streamName), &port, 0, 0)) {
152+
if (ImGui::InputInt(CONCAT("##_network_sink_port_", stringId), &port, 0, 0)) {
139153
config.acquire();
140-
config.conf[_streamName]["port"] = port;
154+
config.conf[stringId]["port"] = port;
141155
config.release(true);
142156
}
143157

144158
ImGui::LeftLabel("Protocol");
145159
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
146-
if (ImGui::Combo(CONCAT("##_network_sink_mode_", _streamName), &modeId, sinkModesTxt)) {
160+
if (ImGui::Combo(CONCAT("##_network_sink_mode_", stringId), &modeId, sinkModesTxt)) {
147161
config.acquire();
148-
config.conf[_streamName]["protocol"] = modeId;
162+
config.conf[stringId]["mode"] = modeId;
149163
config.release(true);
150164
}
151165

152166
if (listening) { style::endDisabled(); }
153167

154168
ImGui::LeftLabel("Samplerate");
155169
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
156-
if (ImGui::Combo(CONCAT("##_network_sink_sr_", _streamName), &srId, sampleRatesTxt.c_str())) {
157-
sampleRate = sampleRates[srId];
158-
_stream->setSampleRate(sampleRate);
170+
if (ImGui::Combo(CONCAT("##_network_sink_sr_", stringId), &srId, samplerates.txt)) {
171+
sampleRate = samplerates.value(srId);
172+
entry->setSamplerate(sampleRate);
159173
packer.setSampleCount(sampleRate / 60);
160174
config.acquire();
161-
config.conf[_streamName]["sampleRate"] = sampleRate;
175+
config.conf[stringId]["samplerate"] = sampleRate;
162176
config.release(true);
163177
}
164178

165-
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", _streamName), &stereo)) {
179+
if (ImGui::Checkbox(CONCAT("Stereo##_network_sink_stereo_", stringId), &stereo)) {
166180
stop();
167181
start();
168182
config.acquire();
169-
config.conf[_streamName]["stereo"] = stereo;
183+
config.conf[stringId]["stereo"] = stereo;
170184
config.release(true);
171185
}
172186

173-
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
187+
if (listening && ImGui::Button(CONCAT("Stop##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
174188
stopServer();
175189
config.acquire();
176-
config.conf[_streamName]["listening"] = false;
190+
config.conf[stringId]["running"] = false;
177191
config.release(true);
178192
}
179-
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", _streamName), ImVec2(menuWidth, 0))) {
193+
else if (!listening && ImGui::Button(CONCAT("Start##_network_sink_stop_", stringId), ImVec2(menuWidth, 0))) {
180194
startServer();
181195
config.acquire();
182-
config.conf[_streamName]["listening"] = true;
196+
config.conf[stringId]["running"] = true;
183197
config.release(true);
184198
}
185199

@@ -271,47 +285,40 @@ class NetworkSink : SinkManager::Sink {
271285
_this->listener->acceptAsync(clientHandler, _this);
272286
}
273287

274-
SinkManager::Stream* _stream;
288+
// DSP
275289
dsp::buffer::Packer<dsp::stereo_t> packer;
276290
dsp::convert::StereoToMono s2m;
277291
dsp::sink::Handler<float> monoSink;
278292
dsp::sink::Handler<dsp::stereo_t> stereoSink;
279293

280-
std::string _streamName;
281-
282-
int srId = 0;
283-
bool running = false;
294+
OptionList<std::string, SinkMode> modes;
295+
OptionList<int, double> samplerates;
284296

285297
char hostname[1024];
286-
int port = 4242;
287-
288-
int modeId = 1;
289-
290-
std::vector<unsigned int> sampleRates;
291-
std::string sampleRatesTxt;
292-
unsigned int sampleRate = 48000;
298+
int port = 7355;
299+
SinkMode mode = SINK_MODE_TCP;
300+
int modeId;
301+
int sampleRate = 48000;
302+
int srId;
293303
bool stereo = false;
304+
bool running = false;
294305

295306
int16_t* netBuf;
296-
297307
net::Listener listener;
298308
net::Conn conn;
299309
std::mutex connMtx;
300310
};
301311

302-
class NetworkSinkModule : public ModuleManager::Instance {
312+
class NetworkSinkModule : public ModuleManager::Instance, SinkProvider {
303313
public:
304314
NetworkSinkModule(std::string name) {
305-
this->name = name;
306-
provider.create = create_sink;
307-
provider.ctx = this;
308-
309-
sigpath::sinkManager.registerSinkProvider("Network", provider);
315+
// Register self as provider
316+
sigpath::streamManager.registerSinkProvider("Network", this);
310317
}
311318

312319
~NetworkSinkModule() {
313-
// Unregister sink, this will automatically stop and delete all instances of the audio sink
314-
sigpath::sinkManager.unregisterSinkProvider("Network");
320+
// Unregister self
321+
sigpath::streamManager.unregisterSinkProvider(this);
315322
}
316323

317324
void postInit() {}
@@ -328,14 +335,13 @@ class NetworkSinkModule : public ModuleManager::Instance {
328335
return enabled;
329336
}
330337

331-
private:
332-
static SinkManager::Sink* create_sink(SinkManager::Stream* stream, std::string streamName, void* ctx) {
333-
return (SinkManager::Sink*)(new NetworkSink(stream, streamName));
338+
std::unique_ptr<Sink> createSink(SinkEntry* entry, dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id, const std::string& stringId) {
339+
return std::make_unique<NetworkSink>(entry, stream, name, id, stringId);
334340
}
335341

342+
private:
336343
std::string name;
337344
bool enabled = true;
338-
SinkManager::SinkProvider provider;
339345
};
340346

341347
MOD_EXPORT void _INIT_() {

0 commit comments

Comments
 (0)