#include "qsacnnode.h" #include #include #include #include /** * @brief QSacnNode::QSacnNode * @param parent * @param cid */ QSacnNode::QSacnNode(QObject *parent, QUuid cid) : Component(UUID::uuid(cid.toString().toStdString())) , QUdpSocket(parent) { fctn_ = "OpenLCP QSacnNode"; bind(QHostAddress::AnyIPv4, sACN::ACN_SDT_MULTICAST_PORT); connect(this, &QUdpSocket::readyRead, this, &QSacnNode::udpReceive); sACN::Receiver::onDiscovered([this](){ emit discoveryUpdates(); }); } /** * @brief QSacnNode::~QSacnNode */ QSacnNode::~QSacnNode() { auto rx_list = rx_universes.keys(); for (const auto & num : rx_list) QSacnNode::unsubscribe(num); auto tx_list = tx_universes.keys(); for (const auto & num : tx_list) QSacnNode::terminate(num); } /** * @brief QSacnNode::subscribe * @param num */ void QSacnNode::subscribe(const uint16_t num) { if (Receiver::universe(num)) // already subscribed return; if (num != sACN::E131_DISCOVERY_UNIVERSE) { qDebug() << "Subscribing to universe" << QString::number(num); Receiver::subscribe(num); rx_universes.emplace(num, new QSacnUniverse(this, Receiver::universe(num))); emit subscribing(rx_universes.value(num)); } for (QNetworkInterface &iface : QNetworkInterface::allInterfaces()) joinMulticastGroup(IPv4MulticastAddress(num), iface); for (QNetworkInterface &iface : QNetworkInterface::allInterfaces()) joinMulticastGroup(IPv6MulticastAddress(num), iface); } /** * @brief QSacnNode::unsubscribe * @param num */ void QSacnNode::unsubscribe(const uint16_t num) { for (QNetworkInterface &iface : QNetworkInterface::allInterfaces()) leaveMulticastGroup(IPv4MulticastAddress(num), iface); for (QNetworkInterface &iface : QNetworkInterface::allInterfaces()) leaveMulticastGroup(IPv6MulticastAddress(num), iface); if (Receiver::universe(num)) { qDebug() << "Unsubscribing from universe " << QString::number(num); emit unsubscribing(rx_universes.value(num)); rx_universes.take(num)->deleteLater(); Receiver::unsubscribe(num); } } /** * @brief QSacnNode::create * @param num */ void QSacnNode::create(const uint16_t num) { if (Source::universe(num)) // already created return; Source::create(num); tx_universes.emplace(num, new QSacnUniverse(this, Source::universe(num))); emit creating(tx_universes.value(num)); } /** * @brief QSacnNode::terminate * @param num */ void QSacnNode::terminate(const uint16_t num) { if (Source::universe(num)) { qDebug() << "Terminating universe " << QString::number(num); Source::terminate(num); emit terminating(tx_universes.value(num)); tx_universes.take(num)->deleteLater(); } } /** * @brief QSacnNode::UdpPayloadReceiver */ void QSacnNode::udpReceive() { while (hasPendingDatagrams()) { QNetworkDatagram datagram = receiveDatagram(); // Expecting IANA registered Session Data Transport traffic if (datagram.destinationPort() != sACN::ACN_SDT_MULTICAST_PORT) return; // wrap a PDU io stream around the QNetworkDatagram data buffer auto stream = std::make_shared( reinterpret_cast(datagram.data().data()), datagram.data().length()); UdpPayloadReceiver(stream); } } /** * @brief QSacnNode::rlpSend * @param stream * @param ip */ void QSacnNode::rlpSend(const ACN::PDU::Stream stream, const ACN::SDT::UDP::ipAddress& ip) { QHostAddress addr; switch (ip.type) { case ACN::SDT::SDT_ADDR_IPV4: addr = QHostAddress(ip.address.ipv4.value); break; case ACN::SDT::SDT_ADDR_IPV6: addr = QHostAddress(ip.address.ipv6.bytes); break; default: return; } writeDatagram(reinterpret_cast(stream->base()), stream->size(), addr, ip.port); } /** * @brief QSacnNode::universe * @param u * @return */ QSacnUniverse* QSacnNode::universe(const uint16_t u) { return rx_universes.value(u); } /** * @brief QSacnNode::source * @param u * @return */ QSacnUniverse *QSacnNode::source(const uint16_t u) { return tx_universes.value(u); }