3
3
#include < module.h>
4
4
#include < gui/gui.h>
5
5
#include < signal_path/signal_path.h>
6
- #include < signal_path/sink .h>
6
+ #include < signal_path/stream .h>
7
7
#include < dsp/buffer/packer.h>
8
8
#include < dsp/convert/stereo_to_mono.h>
9
9
#include < dsp/sink/handler_sink.h>
10
10
#include < utils/flog.h>
11
11
#include < config.h>
12
12
#include < gui/style.h>
13
+ #include < utils/optionlist.h>
13
14
#include < core.h>
14
15
15
16
#define CONCAT (a, b ) ((std::string(a) + b).c_str())
@@ -18,84 +19,97 @@ SDRPP_MOD_INFO{
18
19
/* Name: */ " network_sink" ,
19
20
/* Description: */ " Network sink module for SDR++" ,
20
21
/* Author: */ " Ryzerth" ,
21
- /* Version: */ 0 , 1 , 0 ,
22
+ /* Version: */ 0 , 2 , 0 ,
22
23
/* Max instances */ 1
23
24
};
24
25
25
26
ConfigManager config;
26
27
27
- enum {
28
+ enum SinkMode {
28
29
SINK_MODE_TCP,
29
30
SINK_MODE_UDP
30
31
};
31
32
32
33
const char * sinkModesTxt = " TCP\0 UDP\0 " ;
33
34
34
- class NetworkSink : SinkManager:: Sink {
35
+ class NetworkSink : public Sink {
35
36
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);
39
43
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);
49
61
}
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 );
58
62
63
+ // Allocate buffer
59
64
netBuf = new int16_t [STREAM_BUFFER_SIZE];
60
65
61
- packer.init (_stream->sinkOut , 512 );
66
+ // Init DSP
67
+ packer.init (stream, 512 );
62
68
s2m.init (&packer.out );
63
69
monoSink.init (&s2m.out , monoHandler, this );
64
70
stereoSink.init (&packer.out , stereoHandler, this );
65
71
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 ());
70
78
}
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 " ] ;
73
81
}
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;
90
89
}
91
- if (sr == 48000.0 ) { _48kId = id; }
92
- id++;
93
90
}
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" ];
97
105
}
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);
99
113
100
114
// Start if needed
101
115
if (startNow) { startServer (); }
@@ -122,64 +136,64 @@ class NetworkSink : SinkManager::Sink {
122
136
running = false ;
123
137
}
124
138
125
- void menuHandler () {
139
+ void showMenu () {
126
140
float menuWidth = ImGui::GetContentRegionAvail ().x ;
127
141
128
142
bool listening = (listener && listener->isListening ()) || (conn && conn->isOpen ());
129
143
130
144
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 )) {
132
146
config.acquire ();
133
- config.conf [_streamName ][" hostname" ] = hostname;
147
+ config.conf [stringId ][" hostname" ] = hostname;
134
148
config.release (true );
135
149
}
136
150
ImGui::SameLine ();
137
151
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 )) {
139
153
config.acquire ();
140
- config.conf [_streamName ][" port" ] = port;
154
+ config.conf [stringId ][" port" ] = port;
141
155
config.release (true );
142
156
}
143
157
144
158
ImGui::LeftLabel (" Protocol" );
145
159
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)) {
147
161
config.acquire ();
148
- config.conf [_streamName ][" protocol " ] = modeId;
162
+ config.conf [stringId ][" mode " ] = modeId;
149
163
config.release (true );
150
164
}
151
165
152
166
if (listening) { style::endDisabled (); }
153
167
154
168
ImGui::LeftLabel (" Samplerate" );
155
169
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);
159
173
packer.setSampleCount (sampleRate / 60 );
160
174
config.acquire ();
161
- config.conf [_streamName ][" sampleRate " ] = sampleRate;
175
+ config.conf [stringId ][" samplerate " ] = sampleRate;
162
176
config.release (true );
163
177
}
164
178
165
- if (ImGui::Checkbox (CONCAT (" Stereo##_network_sink_stereo_" , _streamName ), &stereo)) {
179
+ if (ImGui::Checkbox (CONCAT (" Stereo##_network_sink_stereo_" , stringId ), &stereo)) {
166
180
stop ();
167
181
start ();
168
182
config.acquire ();
169
- config.conf [_streamName ][" stereo" ] = stereo;
183
+ config.conf [stringId ][" stereo" ] = stereo;
170
184
config.release (true );
171
185
}
172
186
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 ))) {
174
188
stopServer ();
175
189
config.acquire ();
176
- config.conf [_streamName ][" listening " ] = false ;
190
+ config.conf [stringId ][" running " ] = false ;
177
191
config.release (true );
178
192
}
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 ))) {
180
194
startServer ();
181
195
config.acquire ();
182
- config.conf [_streamName ][" listening " ] = true ;
196
+ config.conf [stringId ][" running " ] = true ;
183
197
config.release (true );
184
198
}
185
199
@@ -271,47 +285,40 @@ class NetworkSink : SinkManager::Sink {
271
285
_this->listener ->acceptAsync (clientHandler, _this);
272
286
}
273
287
274
- SinkManager::Stream* _stream;
288
+ // DSP
275
289
dsp::buffer::Packer<dsp::stereo_t > packer;
276
290
dsp::convert::StereoToMono s2m;
277
291
dsp::sink::Handler<float > monoSink;
278
292
dsp::sink::Handler<dsp::stereo_t > stereoSink;
279
293
280
- std::string _streamName;
281
-
282
- int srId = 0 ;
283
- bool running = false ;
294
+ OptionList<std::string, SinkMode> modes;
295
+ OptionList<int , double > samplerates;
284
296
285
297
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;
293
303
bool stereo = false ;
304
+ bool running = false ;
294
305
295
306
int16_t * netBuf;
296
-
297
307
net::Listener listener;
298
308
net::Conn conn;
299
309
std::mutex connMtx;
300
310
};
301
311
302
- class NetworkSinkModule : public ModuleManager ::Instance {
312
+ class NetworkSinkModule : public ModuleManager ::Instance, SinkProvider {
303
313
public:
304
314
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 );
310
317
}
311
318
312
319
~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 );
315
322
}
316
323
317
324
void postInit () {}
@@ -328,14 +335,13 @@ class NetworkSinkModule : public ModuleManager::Instance {
328
335
return enabled;
329
336
}
330
337
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);
334
340
}
335
341
342
+ private:
336
343
std::string name;
337
344
bool enabled = true ;
338
- SinkManager::SinkProvider provider;
339
345
};
340
346
341
347
MOD_EXPORT void _INIT_ () {
0 commit comments