Skip to content

Commit

Permalink
osc: implement support for always sending bundles in OSC protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Dec 18, 2024
1 parent 6981d87 commit 2c0d85f
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 22 deletions.
77 changes: 77 additions & 0 deletions src/ossia/network/osc/detail/bundle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,83 @@ catch(...)
return {};
}

template <typename NetworkPolicy>
std::optional<bundle> make_bundle(
NetworkPolicy add_element_to_bundle, const ossia::net::full_parameter_data& param)
try
{
bundle ret{
ossia::buffer_pool::instance().acquire(max_osc_message_size), param.critical};
{
oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
str << oscpack::BeginBundleImmediate();
auto val = param.value();
add_element_to_bundle(str, val, param);
str << oscpack::EndBundle();
ret.data.resize(str.Size());

// TODO useless condition for now.
// But if we know that we are going through ws we can increase the size
// beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
}
return ret;
}
catch(const oscpack::OutOfBufferMemoryException&)
{
ossia::logger().error(
"make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
return {};
}
catch(const std::runtime_error& e)
{
ossia::logger().error("make_bundle_client: {}", e.what());
return {};
}
catch(...)
{
ossia::logger().error("make_bundle_client: unknown error");
return {};
}

template <typename NetworkPolicy>
std::optional<bundle> make_bundle(
NetworkPolicy add_element_to_bundle, const ossia::net::parameter_base& param,
ossia::value& v)
try
{
bundle ret{
ossia::buffer_pool::instance().acquire(max_osc_message_size),
param.get_critical()};
{
oscpack::OutboundPacketStream str(ret.data.data(), max_osc_message_size);
str << oscpack::BeginBundleImmediate();
add_element_to_bundle(str, v, param);
str << oscpack::EndBundle();
ret.data.resize(str.Size());

// TODO useless condition for now.
// But if we know that we are going through ws we can increase the size
// beyond 65k. ret.critical |= str.Size() > max_osc_message_size;
}
return ret;
}
catch(const oscpack::OutOfBufferMemoryException&)
{
ossia::logger().error(
"make_bundle_client: message too large (limit is {} bytes)", max_osc_message_size);
return {};
}
catch(const std::runtime_error& e)
{
ossia::logger().error("make_bundle_client: {}", e.what());
return {};
}
catch(...)
{
ossia::logger().error("make_bundle_client: unknown error");
return {};
}

template <typename NetworkPolicy>
std::optional<bundle> make_bundle(
NetworkPolicy add_element_to_bundle,
Expand Down
8 changes: 8 additions & 0 deletions src/ossia/network/osc/detail/osc_common_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@

namespace ossia::net
{

template <typename T>
struct osc_always_bundled_policy : T
{
using bundled = std::true_type;
};
template <typename T>
using osc_never_bundled_policy = T;
// Handling for types compatible with all OSC version

// This class is an implementation detail. It is used to send things that work
Expand Down
53 changes: 53 additions & 0 deletions src/ossia/network/osc/detail/osc_protocol_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace ossia::net
template <typename OscVersion>
struct osc_protocol_common
{
using osc_configuration = OscVersion;
template <typename T, typename Value_T>
static bool push(T& self, const ossia::net::parameter_base& addr, Value_T&& v)
{
Expand Down Expand Up @@ -123,6 +124,32 @@ struct osc_protocol_client : osc_protocol_common<OscVersion>
return osc_protocol_common<OscVersion>::push_raw(self, addr);
}

template <typename T, typename Writer>
static bool push_bundle(
T& self, Writer writer, const ossia::net::parameter_base& addr, ossia::value v)
{
if(auto bundle = make_bundle(bundle_client_policy<OscVersion>{}, addr, v))
{
writer(bundle->data.data(), bundle->data.size());
ossia::buffer_pool::instance().release(std::move(bundle->data));
return true;
}
return false;
}

template <typename T, typename Writer>
static bool
push_bundle(T& self, Writer writer, const ossia::net::full_parameter_data& addr)
{
if(auto bundle = make_bundle(bundle_client_policy<OscVersion>{}, addr))
{
writer(bundle->data.data(), bundle->data.size());
ossia::buffer_pool::instance().release(std::move(bundle->data));
return true;
}
return false;
}

template <typename T, typename Writer, typename Addresses>
static bool push_bundle(T& self, Writer writer, const Addresses& addresses)
{
Expand Down Expand Up @@ -168,6 +195,32 @@ struct osc_protocol_server : osc_protocol_common<OscVersion>
return osc_protocol_common<OscVersion>::push_raw(self, addr);
}

template <typename T, typename Writer>
static bool
push_bundle(T& self, Writer writer, const ossia::net::full_parameter_data& addr)
{
if(auto bundle = make_bundle(bundle_server_policy<OscVersion>{}, addr))
{
writer(bundle->data.data(), bundle->data.size());
ossia::buffer_pool::instance().release(std::move(bundle->data));
return true;
}
return false;
}

template <typename T, typename Writer>
static bool push_bundle(
T& self, Writer writer, const ossia::net::parameter_base& addr, ossia::value v)
{
if(auto bundle = make_bundle(bundle_server_policy<OscVersion>{}, addr, v))
{
writer(bundle->data.data(), bundle->data.size());
ossia::buffer_pool::instance().release(std::move(bundle->data));
return true;
}
return false;
}

template <typename T, typename Writer, typename Addresses>
static bool push_bundle(T& self, Writer writer, const Addresses& addresses)
{
Expand Down
43 changes: 33 additions & 10 deletions src/ossia/protocols/osc/osc_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,20 +250,43 @@ make_osc_protocol(network_context_ptr ctx, osc_protocol_configuration config)
{
using conf = osc_protocol_configuration;

switch(config.version)
switch(config.bundle_strategy)
{
case conf::OSC1_0:
return make_osc_protocol_impl<osc_1_0_policy>(std::move(ctx), std::move(config));
case conf::OSC1_1:
return make_osc_protocol_impl<osc_1_1_policy>(std::move(ctx), std::move(config));
case conf::EXTENDED:
return make_osc_protocol_impl<osc_extended_policy>(
std::move(ctx), std::move(config));
default:
case conf::NEVER_BUNDLE:
switch(config.version)
{
case conf::OSC1_0:
return make_osc_protocol_impl<osc_1_0_policy>(
std::move(ctx), std::move(config));
case conf::OSC1_1:
return make_osc_protocol_impl<osc_1_1_policy>(
std::move(ctx), std::move(config));
case conf::EXTENDED:
return make_osc_protocol_impl<osc_extended_policy>(
std::move(ctx), std::move(config));
default:
break;
}
break;
case conf::ALWAYS_BUNDLE: {
switch(config.version)
{
case conf::OSC1_0:
return make_osc_protocol_impl<osc_always_bundled_policy<osc_1_0_policy>>(
std::move(ctx), std::move(config));
case conf::OSC1_1:
return make_osc_protocol_impl<osc_always_bundled_policy<osc_1_1_policy>>(
std::move(ctx), std::move(config));
case conf::EXTENDED:
return make_osc_protocol_impl<osc_always_bundled_policy<osc_extended_policy>>(
std::move(ctx), std::move(config));
default:
break;
}
break;
}
}

return {};
}

}
6 changes: 6 additions & 0 deletions src/ossia/protocols/osc/osc_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ struct osc_protocol_configuration
SLIP
} framing{SLIP};

enum
{
NEVER_BUNDLE,
ALWAYS_BUNDLE
} bundle_strategy{NEVER_BUNDLE};

osc_transport_configuration transport;
};

Expand Down
57 changes: 45 additions & 12 deletions src/ossia/protocols/osc/osc_generic_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
namespace ossia::net
{
template <typename OscMode, typename SendSocket, typename RecvSocket>
class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
class osc_generic_bidir_protocol final : public can_learn<ossia::net::protocol_base>
{
public:
// using socket_type = Socket;
using osc_configuration = typename OscMode::osc_configuration;
static constexpr bool bundled = requires { typename osc_configuration::bundled{}; };
using writer_type = socket_writer<SendSocket>;

osc_generic_bidir_protocol(
Expand Down Expand Up @@ -156,6 +157,7 @@ class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
{
if constexpr(!std::is_same_v<SendSocket, ossia::net::null_socket>)
{
// FIXME bundling ?
return OscMode::echo_incoming_message(*this, id, addr, val);
}
else
Expand All @@ -168,7 +170,10 @@ class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
{
if constexpr(!std::is_same_v<SendSocket, ossia::net::null_socket>)
{
return OscMode::push(*this, addr, v);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, v);
else
return OscMode::push(*this, addr, v);
}
else
{
Expand All @@ -180,7 +185,10 @@ class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
{
if constexpr(!std::is_same_v<SendSocket, ossia::net::null_socket>)
{
return OscMode::push(*this, addr, std::move(v));
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, std::move(v));
else
return OscMode::push(*this, addr, std::move(v));
}
else
{
Expand All @@ -192,7 +200,10 @@ class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
{
if constexpr(!std::is_same_v<SendSocket, ossia::net::null_socket>)
{
return OscMode::push_raw(*this, addr);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr);
else
return OscMode::push_raw(*this, addr);
}
else
{
Expand Down Expand Up @@ -273,9 +284,11 @@ class osc_generic_bidir_protocol : public can_learn<ossia::net::protocol_base>
};

template <typename OscMode, typename Socket>
class osc_generic_server_protocol : public can_learn<ossia::net::protocol_base>
class osc_generic_server_protocol final : public can_learn<ossia::net::protocol_base>
{
public:
using osc_configuration = typename OscMode::osc_configuration;
static constexpr bool bundled = requires { typename osc_configuration::bundled{}; };
using socket_type = Socket;
using writer_type = socket_writer<socket_type>;

Expand Down Expand Up @@ -323,17 +336,26 @@ class osc_generic_server_protocol : public can_learn<ossia::net::protocol_base>

bool push(const ossia::net::parameter_base& addr, const ossia::value& v) override
{
return OscMode::push(*this, addr, v);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, v);
else
return OscMode::push(*this, addr, v);
}

bool push(const ossia::net::parameter_base& addr, ossia::value&& v) override
{
return OscMode::push(*this, addr, std::move(v));
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, std::move(v));
else
return OscMode::push(*this, addr, std::move(v));
}

bool push_raw(const ossia::net::full_parameter_data& addr) override
{
return OscMode::push_raw(*this, addr);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr);
else
return OscMode::push_raw(*this, addr);
}

bool push_bundle(const std::vector<const parameter_base*>& addresses) override
Expand Down Expand Up @@ -380,6 +402,8 @@ template <typename OscMode, typename Socket>
class osc_generic_client_protocol : public can_learn<ossia::net::protocol_base>
{
public:
using osc_configuration = typename OscMode::osc_configuration;
static constexpr bool bundled = requires { typename osc_configuration::bundled{}; };
using socket_type = Socket;
using writer_type = socket_writer<socket_type>;

Expand Down Expand Up @@ -431,17 +455,26 @@ class osc_generic_client_protocol : public can_learn<ossia::net::protocol_base>

bool push(const ossia::net::parameter_base& addr, const ossia::value& v) override
{
return OscMode::push(*this, addr, v);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, v);
else
return OscMode::push(*this, addr, v);
}

bool push(const ossia::net::parameter_base& addr, ossia::value&& v) override
{
return OscMode::push(*this, addr, std::move(v));
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr, std::move(v));
else
return OscMode::push(*this, addr, std::move(v));
}

bool push_raw(const ossia::net::full_parameter_data& addr) override
{
return OscMode::push_raw(*this, addr);
if constexpr(bundled)
return OscMode::push_bundle(*this, writer(), addr);
else
return OscMode::push_raw(*this, addr);
}

bool push_bundle(const std::vector<const parameter_base*>& addresses) override
Expand Down

0 comments on commit 2c0d85f

Please sign in to comment.