#include "connection_manager.h" #include "device_connection.h" #include "udevw/include/udevw.hpp" #include #include #include namespace midi_router { static void callback(double time_stamp, std::vector *raw, void *user_data) { Device_Connection* device = static_cast(user_data); if (raw->size() > 3) { std::cerr << "Received message with wrong size (" << raw->size() << ") from " << device->source_id << ", dropping\n"; for (auto const & byte : *raw) std::cerr << static_cast(byte); std::cerr << "\n"; return; } Message message { &device->source_id, *raw }; device->submitter.submit(message); } Connection_Manager::Connection_Manager(Device_Map const & device_map, Submitter & submitter): m_device_map(device_map), m_submitter(submitter), m_connections{}, m_detector(std::bind(&Connection_Manager::detect_devices, this)) { for (auto const & [name, id] : device_map) { m_connections[id] = std::make_unique(id, name, submitter, callback); } refresh_devices(true, false); } Connection_Manager::~Connection_Manager() = default; Sender & Connection_Manager::get_sender(Device_Id const & device) const { return *m_connections.at(device); } void Connection_Manager::detect_devices() { auto udev = udevw::Udev::create(); auto monitor = udevw::Monitor::create_from_netlink(udev, "udev"); monitor.filter_add_match_subsystem("sound"); // devtype = nullptr implied monitor.enable_receiving(); int fd = monitor.get_fd(); for (;;) { fd_set fds; FD_ZERO(&fds); FD_SET(fd, &fds); if (select(fd +1, &fds, nullptr, nullptr, nullptr) > 0 && FD_ISSET(fd, &fds)) { auto device = monitor.receive_device(); auto action = device.get_action(); if (!action) continue; bool add = *action == "add"; bool remove = *action == "remove"; refresh_devices(add, remove); } } } void Connection_Manager::refresh_devices([[maybe_unused]] bool add, [[maybe_unused]] bool remove) { // collect currently connected devices RtMidiIn enumerator {}; std::map port_map {}; for (std::size_t i = 0; i < enumerator.getPortCount(); ++i) { std::string name = enumerator.getPortName(i); port_map[i] = name; } for (auto & [id, device] : m_connections) { bool attached = false; for (auto const & [port, name] : port_map) { attached |= name.contains(device->device_name); if (attached) { device->connect(port); break; } } if (!attached) { device->disconnect(); } } } } // namespace midi_router