Skip to content

Commit

Permalink
[net] Implement internal io_context in case external one is not provided
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Oct 26, 2024
1 parent a8fc100 commit 804877b
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 26 deletions.
4 changes: 4 additions & 0 deletions cmake/libremidi.net.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ if(NOT TARGET Boost::boost)
return()
endif()

if(NOT LIBREMIDI_HAS_STD_STOP_TOKEN)
return()
endif()

message(STATUS "libremidi: Network support using Boost.ASIO")
set(LIBREMIDI_HAS_BOOST_ASIO 1)
set(LIBREMIDI_HAS_NETWORK 1)
Expand Down
37 changes: 36 additions & 1 deletion examples/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,41 @@ int main(int argc, const char** argv)
if (auto err = midiout.send_ump(ump); err != stdx::error{})
err.throw_exception();

ctx.run();
ctx.run_one();
ctx.run_one();
}

// MIDI 1 no context
{
libremidi::net::dgram_input_configuration in_apiconf{
.client_name = "libremidi",
.protocol = libremidi::net::protocol::OSC_MIDI,
.accept = "0.0.0.0",
.port = 5677};

libremidi::midi_in midiin{
{.on_message = [](const libremidi::message& m) { std::cerr << m << std::endl; }},
in_apiconf};
midiin.open_virtual_port("/midi");

std::this_thread::sleep_for(std::chrono::milliseconds(10));

libremidi::net::dgram_output_configuration out_apiconf{
.client_name = "libremidi",
.protocol = libremidi::net::protocol::OSC_MIDI,
.host = "127.0.0.1",
.port = 5677,
.broadcast = false,
.io_context = &ctx};

libremidi::midi_out midiout{{}, out_apiconf};

if (auto err = midiout.open_virtual_port("/midi"); err != stdx::error{})
err.throw_exception();

if (auto err = midiout.send_message(144, 127, 64); err != stdx::error{})
err.throw_exception();

std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
15 changes: 7 additions & 8 deletions include/libremidi/backends/net/helpers.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include <libremidi/config.hpp>

#include <boost/asio.hpp>
#include <boost/asio/ip/udp.hpp>

#include <memory>
namespace stdx
Expand Down Expand Up @@ -59,24 +59,23 @@ struct optionally_owned

~optionally_owned()
{
if (ownership == owned)
std::destroy_at(storage.object);
if (is_owned())
std::destroy_at(reinterpret_cast<T*>(storage.object));
}

T& get() noexcept
{
return *((ownership == owned) ? reinterpret_cast<T*>(&storage.object) : storage.ref);
}
T& get() noexcept { return *(is_owned() ? reinterpret_cast<T*>(&storage.object) : storage.ref); }
const T& get() const noexcept
{
return *((ownership == owned) ? reinterpret_cast<T*>(&storage.object) : storage.ref);
return *(is_owned() ? reinterpret_cast<T*>(&storage.object) : storage.ref);
}

optionally_owned(const optionally_owned&) = delete;
optionally_owned(optionally_owned&&) noexcept = delete;
optionally_owned& operator=(const optionally_owned&) = delete;
optionally_owned& operator=(optionally_owned&&) noexcept = delete;

bool is_owned() const noexcept { return ownership == owned; }

private:
union
{
Expand Down
41 changes: 30 additions & 11 deletions include/libremidi/backends/net/midi_in.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace libremidi
{

template <typename Impl, typename F>
struct osc_parser
{
Expand Down Expand Up @@ -150,8 +149,8 @@ class midi_in final

explicit midi_in(input_configuration&& conf, dgram_input_configuration&& apiconf)
: configuration{std::move(conf), std::move(apiconf)}
, ctx{configuration.io_context}
, m_socket{ctx.get()}
, m_ctx{configuration.io_context}
, m_socket{m_ctx.get()}
{
m_socket.open(boost::asio::ip::udp::v4());
m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
Expand All @@ -171,7 +170,7 @@ class midi_in final
client_open_ = stdx::error{};
}

~midi_in() override { }
~midi_in() override { close_port(); }

libremidi::API get_current_api() const noexcept override { return libremidi::API::NETWORK; }

Expand All @@ -186,6 +185,14 @@ class midi_in final

receive();

if (m_ctx.is_owned())
{
m_thread = std::jthread{[this, &ctx = m_ctx.get()] {
auto wg = boost::asio::make_work_guard(m_ctx);
ctx.run();
}};
}

return stdx::error{};
}

Expand Down Expand Up @@ -247,10 +254,11 @@ class midi_in final

midi1::input_state_machine m_processing{this->configuration};

libremidi::optionally_owned<boost::asio::io_context> ctx;
libremidi::optionally_owned<boost::asio::io_context> m_ctx;
boost::asio::ip::udp::endpoint m_endpoint;
boost::asio::ip::udp::socket m_socket;
bool m_owned_context{};

std::jthread m_thread;

std::string m_portname;
alignas(16) unsigned char m_data[65535];
Expand Down Expand Up @@ -314,8 +322,8 @@ class midi_in final

explicit midi_in(ump_input_configuration&& conf, dgram_input_configuration&& apiconf)
: configuration{std::move(conf), std::move(apiconf)}
, ctx{configuration.io_context}
, m_socket{ctx.get()}
, m_ctx{configuration.io_context}
, m_socket{m_ctx.get()}
{
m_socket.open(boost::asio::ip::udp::v4());
m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
Expand All @@ -335,7 +343,7 @@ class midi_in final
client_open_ = stdx::error{};
}

~midi_in() override { }
~midi_in() override { close_port(); }

libremidi::API get_current_api() const noexcept override { return libremidi::API::NETWORK_UMP; }

Expand All @@ -350,6 +358,13 @@ class midi_in final

receive();

if (m_ctx.is_owned())
{
m_thread = std::jthread{[this, &ctx = m_ctx.get()] {
auto wg = boost::asio::make_work_guard(m_ctx);
ctx.run();
}};
}
return stdx::error{};
}

Expand All @@ -371,6 +386,9 @@ class midi_in final
stdx::error close_port() override
{
// FIXME async close
if (m_ctx.is_owned())
m_ctx.get().stop();

if (m_socket.is_open())
m_socket.close();
return {};
Expand Down Expand Up @@ -410,10 +428,11 @@ class midi_in final

midi2::input_state_machine m_processing{this->configuration};

libremidi::optionally_owned<boost::asio::io_context> ctx;
libremidi::optionally_owned<boost::asio::io_context> m_ctx;
boost::asio::ip::udp::endpoint m_endpoint;
boost::asio::ip::udp::socket m_socket;
bool m_owned_context{};

std::jthread m_thread;

std::string m_portname;
alignas(16) unsigned char m_data[65535];
Expand Down
12 changes: 6 additions & 6 deletions include/libremidi/backends/net/midi_out.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ class midi_out final

midi_out(output_configuration&& conf, dgram_output_configuration&& apiconf)
: configuration{std::move(conf), std::move(apiconf)}
, ctx{configuration.io_context ? configuration.io_context : new boost::asio::io_context}
, m_socket{*ctx}
, ctx{configuration.io_context}
, m_socket{ctx.get()}
{
m_socket.open(boost::asio::ip::udp::v4());
m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
Expand Down Expand Up @@ -137,7 +137,7 @@ class midi_out final
return from_errc(ret);
}

boost::asio::io_context* ctx{};
libremidi::optionally_owned<boost::asio::io_context> ctx;
boost::asio::ip::udp::endpoint m_endpoint;
boost::asio::ip::udp::socket m_socket;

Expand Down Expand Up @@ -219,8 +219,8 @@ class midi_out final

midi_out(output_configuration&& conf, dgram_output_configuration&& apiconf)
: configuration{std::move(conf), std::move(apiconf)}
, ctx{configuration.io_context ? configuration.io_context : new boost::asio::io_context}
, m_socket{*ctx}
, ctx{configuration.io_context}
, m_socket{ctx.get()}
{
m_socket.open(boost::asio::ip::udp::v4());
m_socket.set_option(boost::asio::ip::udp::socket::reuse_address(true));
Expand Down Expand Up @@ -278,7 +278,7 @@ class midi_out final
return from_errc(ret);
}

boost::asio::io_context* ctx{};
libremidi::optionally_owned<boost::asio::io_context> ctx;
boost::asio::ip::udp::endpoint m_endpoint;
boost::asio::ip::udp::socket m_socket;

Expand Down

0 comments on commit 804877b

Please sign in to comment.