OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
osc_receive.hpp
1#pragma once
2#include <ossia/detail/fmt.hpp>
4#include <ossia/network/base/device.hpp>
5#include <ossia/network/base/listening.hpp>
6#include <ossia/network/base/message_origin_identifier.hpp>
7#include <ossia/network/base/parameter.hpp>
8#include <ossia/network/common/network_logger.hpp>
9#include <ossia/network/osc/detail/osc.hpp>
10
11#include <oscpack/osc/OscPrintReceivedElements.h>
12#include <oscpack/osc/OscReceivedElements.h>
13
14#if defined(OSSIA_HAS_FMT)
15namespace fmt
16{
17template <>
18struct formatter<oscpack::ReceivedMessage>
19{
20 template <typename ParseContext>
21 constexpr auto parse(ParseContext& ctx)
22 {
23 return ctx.begin();
24 }
25
26 template <typename FormatContext>
27 auto format(const oscpack::ReceivedMessage& m, FormatContext& ctx) const
28 {
29 auto out = ctx.out();
30 out = fmt::format_to(out, "{}", m.AddressPattern());
31 if(m.ArgumentCount() > 0)
32 {
33 out = fmt::format_to(out, ": ");
34 auto buf = fmt::basic_memory_buffer<char>();
35 for(auto it = m.ArgumentsBegin(); it != m.ArgumentsEnd(); ++it)
36 {
37 using namespace detail;
38 buf.clear();
39
40 formatbuf<std::basic_streambuf<char>> format_buf{buf};
41 std::basic_ostream<char> output{&format_buf};
42 output << *it;
43
44 out = fmt::format_to(out, "{} ", std::string_view{buf.data(), buf.size()});
45 }
46 }
47 return ctx.out();
48 }
49};
50}
51#endif
52
53namespace ossia::net
54{
55
56struct osc_message_applier
57{
58 message_origin_identifier id;
59 const oscpack::ReceivedMessage& m;
60 void on_listened_value(
62 network_logger& logger)
63 {
64 if(auto v = net::get_filtered_value(the_addr, m); v.valid())
65 {
66 dev.apply_incoming_message(id, the_addr, std::move(v));
67 }
68
69 if(logger.inbound_listened_logger)
70 logger.inbound_listened_logger->info("[input] {}", m);
71 }
72
73 void on_value(ossia::net::parameter_base& the_addr, ossia::net::device_base& dev)
74 {
75 if(auto v = net::get_filtered_value(the_addr, m); v.valid())
76 {
77 dev.apply_incoming_message(id, the_addr, std::move(v));
78 }
79 }
80
81 void on_value_quiet(ossia::net::parameter_base& the_addr, ossia::net::device_base& dev)
82 {
83 if(auto v = net::get_filtered_value(the_addr, m); v.valid())
84 {
85 dev.apply_incoming_message_quiet(id, the_addr, std::move(v));
86 }
87 }
88
89 void on_unhandled(ossia::net::device_base& dev)
90 {
91 dev.on_unhandled_message(
92 m.AddressPattern(),
93 net::osc_utilities::create_any(
94 m.ArgumentsBegin(), m.ArgumentsEnd(), m.ArgumentCount()));
95 }
96
97 void log(network_logger& logger)
98 {
99 if(logger.inbound_logger)
100 logger.inbound_logger->info("[input] {}", m);
101 }
102};
103
104template <bool SilentUpdate, typename F>
105void on_input_message(
106 std::string_view addr_txt, F&& f, const ossia::net::listened_parameters& listening,
107 ossia::net::device_base& dev, network_logger& logger)
108{
109 auto addr = listening.find(addr_txt);
110
111 if(addr && *addr)
112 {
113 f.on_listened_value(**addr, dev, logger);
114 }
115 else
116 {
117 // We still want to save the value even if it is not listened to.
118 if(auto n = find_node(dev.get_root_node(), addr_txt))
119 {
120 if(auto base_addr = n->get_parameter())
121 {
122 if constexpr(!SilentUpdate)
123 f.on_value(*base_addr, dev);
124 else
125 f.on_value_quiet(*base_addr, dev);
126 }
127 }
128 else
129 {
130 // Try to handle pattern matching
131 auto nodes = find_nodes(dev.get_root_node(), addr_txt);
132 for(auto n : nodes)
133 {
134 if(auto addr = n->get_parameter())
135 {
136 if(!SilentUpdate || listening.find(n->osc_address()))
137 f.on_value(*addr, dev);
138 else
139 f.on_value_quiet(*addr, dev);
140 }
141 }
142
143 if(nodes.empty())
144 f.on_unhandled(dev);
145 }
146 }
147
148 f.log(logger);
149}
150
151}
Root of a device tree.
Definition ossia/network/base/device.hpp:58
The parameter_base class.
Definition ossia/network/base/parameter.hpp:48
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118