OSSIA
Open Scenario System for Interactive Application
osc_protocol_common.hpp
1 #pragma once
2 #include <ossia/network/base/parameter.hpp>
3 #include <ossia/network/osc/detail/bundle.hpp>
4 #include <ossia/network/osc/detail/message_generator.hpp>
5 #include <ossia/network/osc/detail/osc_1_0_policy.hpp>
6 #include <ossia/network/osc/detail/osc_packet_processor.hpp>
7 #include <ossia/network/osc/detail/osc_receive.hpp>
8 #include <ossia/network/osc/detail/osc_value_write_visitor.hpp>
9 #include <ossia/network/value/format_value.hpp>
10 
11 namespace ossia::net
12 {
13 
14 template <typename OscVersion>
15 struct osc_protocol_common
16 {
17  template <typename T, typename Value_T>
18  static bool push(T& self, const ossia::net::parameter_base& addr, Value_T&& v)
19  {
20  auto val = bound_value(addr, std::forward<Value_T>(v));
21  if(val.valid())
22  {
23  using send_visitor = osc_value_send_visitor<
24  ossia::net::parameter_base, OscVersion, typename T::writer_type>;
25 
26  send_visitor vis{addr, addr.get_node().osc_address(), self.writer()};
27  val.apply(vis);
28 
29  if(const auto& logger = self.m_logger.outbound_logger)
30  {
31  logger->info("[push] {} {}", addr.get_node().osc_address(), val);
32  }
33  return true;
34  }
35  return false;
36  }
37 
38  template <typename T>
39  static bool push_raw(T& self, const ossia::net::full_parameter_data& addr)
40  {
41  auto val = bound_value(addr, addr.value());
42  if(val.valid())
43  {
44  using send_visitor = osc_value_send_visitor<
45  ossia::net::full_parameter_data, OscVersion, typename T::writer_type>;
46  val.apply(send_visitor{addr, addr.address, self.writer()});
47 
48  if(const auto& logger = self.m_logger.outbound_logger)
49  {
50  logger->info("[push_raw] {} {}", addr.address, val);
51  }
52  return true;
53  }
54  return false;
55  }
56 
57  template <typename T>
58  static bool echo_incoming_message(
59  T& self, const message_origin_identifier& id, const parameter_base& addr,
60  const value& val)
61  {
62  if(&id.protocol == &self)
63  return true;
64 
65  using send_visitor = osc_value_send_visitor<
66  ossia::net::parameter_base, OscVersion, typename T::writer_type>;
67  val.apply(send_visitor{addr, addr.get_node().osc_address(), self.writer()});
68 
69  if(const auto& logger = self.m_logger.outbound_logger)
70  {
71  logger->info("[echo] {} {}", addr.get_node().osc_address(), val);
72  }
73  return true;
74  }
75 
76  template <typename T>
77  static bool observe(T& self, ossia::net::parameter_base& address, bool enable)
78  {
79  if(enable)
80  self.m_listening.insert(
81  std::make_pair(address.get_node().osc_address(), &address));
82  else
83  self.m_listening.erase(address.get_node().osc_address());
84 
85  return true;
86  }
87 
88  template <typename T>
89  static void on_received_message(T& self, const oscpack::ReceivedMessage& m)
90  {
91  [[unlikely]] if(self.learning())
92  {
93  auto already_learned = ossia::net::osc_learn(&self.m_device->get_root_node(), m);
94  if(!already_learned)
95  return;
96  }
97 
98  ossia::net::on_input_message<false>(
99  m.AddressPattern(), ossia::net::osc_message_applier{self.m_id, m},
100  self.m_listening, *self.m_device, self.m_logger);
101  }
102 };
103 
104 // Client can't push to GET addresses
105 template <typename OscVersion>
106 struct osc_protocol_client : osc_protocol_common<OscVersion>
107 {
108  template <typename T, typename Val_T>
109  static bool push(T& self, const ossia::net::parameter_base& addr, Val_T&& v)
110  {
111  if(addr.get_access() == ossia::access_mode::GET)
112  return false;
113 
114  return osc_protocol_common<OscVersion>::push(self, addr, std::forward<Val_T>(v));
115  }
116 
117  template <typename T>
118  static bool push_raw(T& self, const ossia::net::full_parameter_data& addr)
119  {
120  if(addr.get_access() == ossia::access_mode::GET)
121  return false;
122 
123  return osc_protocol_common<OscVersion>::push_raw(self, addr);
124  }
125 
126  template <typename T, typename Writer, typename Addresses>
127  static bool push_bundle(T& self, Writer writer, const Addresses& addresses)
128  {
129  if(auto bundle = make_bundle(bundle_client_policy<OscVersion>{}, addresses))
130  {
131  writer(bundle->data.data(), bundle->data.size());
132  ossia::buffer_pool::instance().release(std::move(bundle->data));
133  return true;
134  }
135  return false;
136  }
137 
138  template <typename T, typename Writer, typename Addresses>
139  static bool push_bundle_bounded(T& self, Writer writer, const Addresses& addresses)
140  {
141  return make_bundle_bounded(
142  bundle_bounded_client_policy<OscVersion>{}, addresses,
143  [writer](const ossia::net::bundle& bundle) {
144  writer(bundle.data.data(), bundle.data.size());
145  });
146  }
147 };
148 
149 // Servers can push to GET addresses
150 template <typename OscVersion>
151 struct osc_protocol_server : osc_protocol_common<OscVersion>
152 {
153  template <typename T, typename Val_T>
154  static bool push(T& self, const ossia::net::parameter_base& addr, Val_T&& v)
155  {
156  if(addr.get_access() == ossia::access_mode::SET)
157  return false;
158 
159  return osc_protocol_common<OscVersion>::push(self, addr, std::forward<Val_T>(v));
160  }
161 
162  template <typename T>
163  static bool push_raw(T& self, const ossia::net::full_parameter_data& addr)
164  {
165  if(addr.get_access() == ossia::access_mode::SET)
166  return false;
167 
168  return osc_protocol_common<OscVersion>::push_raw(self, addr);
169  }
170 
171  template <typename T, typename Writer, typename Addresses>
172  static bool push_bundle(T& self, Writer writer, const Addresses& addresses)
173  {
174  if(auto bundle = make_bundle(bundle_server_policy<OscVersion>{}, addresses))
175  {
176  writer(bundle->data.data(), bundle->data.size());
177  ossia::buffer_pool::instance().release(std::move(bundle->data));
178  return true;
179  }
180  return false;
181  }
182 
183  template <typename T, typename Writer>
184  static bool
185  push_bundle(T& self, Writer writer, tcb::span<ossia::bundle_element> addresses)
186  {
187  if(auto bundle = make_bundle(bundle_server_policy<OscVersion>{}, addresses))
188  {
189  writer(bundle->data.data(), bundle->data.size());
190  ossia::buffer_pool::instance().release(std::move(bundle->data));
191  return true;
192  }
193  return false;
194  }
195 
196  template <typename T, typename Writer>
197  static bool
198  push_bundle_bounded(T& self, Writer writer, tcb::span<ossia::bundle_element> addresses)
199  {
200  return make_bundle_bounded(
201  bundle_bounded_server_policy<OscVersion>{}, addresses,
202  [writer](const ossia::net::bundle& bundle) {
203  writer(bundle.data.data(), bundle.data.size());
204  });
205  }
206 };
207 
208 }
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:104
@ GET
The value can be retrieved and changed.
@ SET
The value can be retrieved.
Full information about a parameter.
Definition: parameter_data.hpp:61