OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
dense_protocol.hpp
1#pragma once
2
3#include <ossia/detail/timer.hpp>
4#include <ossia/network/base/bundle.hpp>
5#include <ossia/network/base/parameter.hpp>
6#include <ossia/network/base/protocol.hpp>
7#include <ossia/network/context.hpp>
8#include <ossia/network/osc/detail/osc_packet_processor.hpp>
9#include <ossia/network/osc/detail/osc_receive.hpp>
10#include <ossia/network/sockets/configuration.hpp>
11#include <ossia/network/sockets/null_socket.hpp>
12#include <ossia/network/sockets/writers.hpp>
13#include <ossia/protocols/dense/dense_protocol_configuration.hpp>
14
15#include <oscpack/osc/OscReceivedElements.h>
16
17#include <span>
18
19namespace ossia::net
20{
21struct dense_writer
22{
23 unsigned char* it{};
24 unsigned char* end{};
25 int available() const noexcept { return end - it; }
26
27 bool operator()() { return false; }
28 bool operator()(ossia::impulse) { return true; }
29 bool operator()(uint16_t v) noexcept
30 {
31 if(available() >= 2)
32 {
33 memcpy(it, &v, sizeof(v));
34 it += 2;
35 return true;
36 }
37 return false;
38 }
39 bool operator()(int32_t v) noexcept
40 {
41 if(available() >= 4)
42 {
43 memcpy(it, &v, sizeof(v));
44 it += 4;
45 return true;
46 }
47 return false;
48 }
49 bool operator()(bool vv) noexcept
50 {
51 int32_t v = vv ? 1 : 0;
52 if(available() >= 4)
53 {
54 memcpy(it, &v, sizeof(v));
55 it += 4;
56 return true;
57 }
58 return false;
59 }
60 bool operator()(float v) noexcept
61 {
62 if(available() >= 4)
63 {
64 memcpy(it, &v, sizeof(v));
65 it += 4;
66 return true;
67 }
68 return false;
69 }
70 bool operator()(std::string_view v) noexcept
71 {
72 if(available() >= (4 + v.size()))
73 {
74 (*this)((int)std::ssize(v));
75 memcpy(it, v.data(), v.size());
76 it += v.size();
77 return true;
78 }
79 return false;
80 }
81 template <std::size_t N>
82 bool operator()(std::array<float, N> v) noexcept
83 {
84 if(available() >= 4 * N)
85 {
86 for(int i = 0; i < N; i++)
87 (*this)(v[N]);
88 return true;
89 }
90 return false;
91 }
92 bool operator()(const std::vector<ossia::value>& v) noexcept
93 {
94 if(available() >= 4 * v.size() + 4) // FIXME
95 {
96 (*this)((uint16_t)0);
97 (*this)((uint16_t)v.size());
98 bool ok = true;
99 for(int i = 0; i < v.size(); i++)
100 {
101 ok &= v[i].apply(*this);
102 if(!ok)
103 return false;
104 }
105 return true;
106 }
107 return false;
108 }
109 bool operator()(const ossia::value_map_type& v) noexcept
110 {
111 if(available() >= 4 * v.size() + 4) // FIXME
112 {
113 (*this)((uint16_t)0);
114 (*this)((uint16_t)v.size());
115 bool ok = true;
116 for(auto& [k, val] : v)
117 {
118 ok &= val.apply(*this);
119 if(!ok)
120 return false;
121 }
122 return true;
123 }
124 return false;
125 }
126};
127
128template <typename SendSocket, typename RecvSocket>
129class dense_generic_bidir_protocol : public ossia::net::protocol_base
130{
131public:
132 // using socket_type = Socket;
133 using writer_type = socket_writer<SendSocket>;
134
135 dense_generic_bidir_protocol(
136 network_context_ptr ctx, const dense_configuration& conf,
137 const send_fd_configuration& send_conf, const receive_fd_configuration& recv_conf)
138 : ossia::net::protocol_base{flags{SupportsMultiplex}}
139 , m_ctx{std::move(ctx)}
140 , m_id{*this}
141 , from_client{recv_conf, m_ctx->context}
142 , to_client{send_conf, m_ctx->context}
143 {
144 from_client.open();
145 to_client.connect();
146
147 init_timer(conf.interval);
148 }
149
150 dense_generic_bidir_protocol(
151 network_context_ptr ctx, const dense_configuration& conf,
152 const outbound_socket_configuration& send_conf,
153 const inbound_socket_configuration& recv_conf)
154 : ossia::net::protocol_base{flags{SupportsMultiplex}}
155 , m_ctx{std::move(ctx)}
156 , m_id{*this}
157 , from_client{recv_conf, m_ctx->context}
158 , to_client{send_conf, m_ctx->context}
159 {
160 from_client.open();
161 to_client.connect();
162 this->receive();
163 init_timer(conf.interval);
164 }
165
166 dense_generic_bidir_protocol(
167 network_context_ptr ctx, const dense_configuration& conf,
168 const outbound_socket_configuration& send_conf)
169 : ossia::net::protocol_base{flags{SupportsMultiplex}}
170 , m_ctx{std::move(ctx)}
171 , m_id{*this}
172 , to_client{send_conf, m_ctx->context}
173 , m_timer{m_ctx->context}
174 {
175 to_client.connect();
176 init_timer(conf.interval);
177 }
178
179 dense_generic_bidir_protocol(
180 network_context_ptr ctx, const dense_configuration& conf,
181 const inbound_socket_configuration& recv_conf)
182 : ossia::net::protocol_base{flags{SupportsMultiplex}}
183 , m_ctx{std::move(ctx)}
184 , m_id{*this}
185 , from_client{recv_conf, m_ctx->context}
186 {
187 from_client.open();
188 this->receive();
189 init_timer(conf.interval);
190 }
191
192 dense_generic_bidir_protocol(
193 network_context_ptr ctx, const dense_configuration& conf,
194 const send_fd_configuration& send_conf)
195 : ossia::net::protocol_base{flags{SupportsMultiplex}}
196 , m_ctx{std::move(ctx)}
197 , m_id{*this}
198 , to_client{send_conf, m_ctx->context}
199 {
200 to_client.connect();
201 init_timer(conf.interval);
202 }
203
204 dense_generic_bidir_protocol(
205 network_context_ptr ctx, const dense_configuration& conf,
206 const receive_fd_configuration& recv_conf)
207 : ossia::net::protocol_base{flags{SupportsMultiplex}}
208 , m_ctx{std::move(ctx)}
209 , m_id{*this}
210 , from_client{recv_conf, m_ctx->context}
211 {
212 from_client.open();
213 this->receive();
214 init_timer(conf.interval);
215 }
216
217 dense_generic_bidir_protocol(const dense_generic_bidir_protocol&) = delete;
218 dense_generic_bidir_protocol(dense_generic_bidir_protocol&&) = delete;
219 dense_generic_bidir_protocol& operator=(const dense_generic_bidir_protocol&) = delete;
220 dense_generic_bidir_protocol& operator=(dense_generic_bidir_protocol&&) = delete;
221
222 ~dense_generic_bidir_protocol() override = default;
223
224 void init_timer(std::chrono::microseconds us) { m_timer.set_delay(us); }
225
226 void receive()
227 {
228 from_client.receive([this](const char* data, std::size_t sz) {
229 if(!m_device)
230 return;
231 auto on_message = [this](auto&& msg) {
232 ossia::net::on_input_message<false>(
233 msg.AddressPattern(), ossia::net::osc_message_applier{m_id, msg}, false,
234 *m_device, m_logger);
235 };
236 osc_packet_processor<decltype(on_message)>{on_message}(data, sz);
237 });
238 }
239
240 bool update(ossia::net::node_base& node_base) override { return false; }
241
242 bool pull(ossia::net::parameter_base& parameter_base) override { return false; }
243
244 bool observe(ossia::net::parameter_base& parameter_base, bool enable) override
245 {
246 return false;
247 }
248
249 bool echo_incoming_message(
250 const message_origin_identifier& id, const parameter_base& addr,
251 const value& val) override
252 {
253 // FIXME
254 return false;
255 }
256
257 bool push(const ossia::net::parameter_base& addr, const ossia::value& v) override
258 {
259 // Store locally
260 return false;
261 }
262
263 bool push(const ossia::net::parameter_base& addr, ossia::value&& v) override
264 {
265 // Store locally
266 return false;
267 }
268
269 bool push_raw(const ossia::net::full_parameter_data& addr) override
270 {
271 // Store locally
272 return false;
273 }
274
275 bool push_bundle(const std::vector<const parameter_base*>& addresses) override
276 {
277 // Store locally
278 return false;
279 }
280
281 bool push_bundle(tcb::span<ossia::bundle_element> addresses) override
282 {
283 // Store locally
284 return false;
285 }
286
287 bool push_bundle_bounded(tcb::span<ossia::bundle_element> addresses) override
288 {
289 // Store locally
290 return false;
291 }
292
293 bool
294 push_raw_bundle(const std::vector<ossia::net::full_parameter_data>& addresses) override
295 {
296 // Store locally
297 return false;
298 }
299
300 void set_device(ossia::net::device_base& dev) override
301 {
302 m_device = &dev;
303 m_timer.start([this] { this->update_function(); });
304 }
305
306 auto writer() noexcept { return writer_type{to_client}; }
307
308 void update_function()
309 {
310 recompute_nodes();
311
312 static std::atomic_int seq = 0;
313 try
314 {
315 dense_packet pkt;
316 pkt.header.protocol_code = 0xCAFECAFE;
317
318 int n = write_packet(pkt.data);
319
320 to_client.write(reinterpret_cast<const char*>(&pkt), sizeof(pkt.header) + n);
321 }
322 catch(std::exception& e)
323 {
324 ossia::logger().error("write failure: {}", e.what());
325 }
326 catch(...)
327 {
328 ossia::logger().error("write failure");
329 }
330 }
331
332 void recompute_nodes()
333 {
334 m_params.clear();
335 m_params.reserve(200);
336
337 if(!this->m_device)
338 return;
339 auto& dev = this->m_device->get_root_node();
340 ossia::net::iterate_all_children(
341 &dev, [this](ossia::net::parameter_base& p) { m_params.insert(&p); });
342
343 // FIXME hash: name + type
344 for(auto& p : m_params)
345 {
346 }
347 }
348
349 int write_packet(std::span<unsigned char> data)
350 {
351 dense_writer wr{data.data(), data.data() + data.size()};
352 for(auto& param : m_params)
353 {
354 param->value().apply(wr);
355 }
356 return wr.it - data.data();
357 }
358
359 using ossia::net::protocol_base::m_logger;
360 ossia::net::network_context_ptr m_ctx;
361 message_origin_identifier m_id;
362
363 ossia::net::device_base* m_device{};
364
365 RecvSocket from_client;
366 SendSocket to_client;
367
368 ossia::timer m_timer;
369
370 ossia::flat_set<ossia::net::parameter_base*, parameter_alphabetical_sort> m_params;
371};
372}
Root of a device tree.
Definition ossia/network/base/device.hpp:58
The node_base class.
Definition node.hpp:48
The parameter_base class.
Definition ossia/network/base/parameter.hpp:48
The protocol_base class.
Definition protocol.hpp:40
The value class.
Definition value.hpp:173
Definition git_info.h:7
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118
Full information about a parameter.
Definition parameter_data.hpp:61