diff --git a/protocols/sacn/source.cpp b/protocols/sacn/source.cpp index 9b437e7..82e1b1d 100644 --- a/protocols/sacn/source.cpp +++ b/protocols/sacn/source.cpp @@ -88,6 +88,85 @@ void Source::end(const uint16_t num) } +/** + * @brief @cite sACN 12 Universe Discovery + * + * > E1.31 Universe Discovery enables other components on a network to know + * > which universes are being used to transmit data or synchronization + * > information. ... this specification requires any source intending to + * > comply with E1.31 to implement Universe Discovery... + */ +void Source::discoveryAnnounce() +{ + /// > \cite sACN 12.1 Universe Discovery and Termination + /// > + /// > Any source that is no longer sending any universe data may stop + /// > sending E1.31 Universe Discovery Packets until such time that it + /// > resumes transmission of E1.31 Data and/or Synchronization information. + if (universes_.empty()) + return; + + // destination IP + ipAddress ip; + + // framing layer header + auto frmheader = new EXTENDED::discovery_header; + frmheader->source_name = name(); + + // universe discovery layer + EXTENDED::DISCOVERY::discovery_list_header header; + + // known universes + std::vector list; + for (const auto & [num, univ] : universes_) + { + if (univ->destination.type != ACN::SDT::SDT_ADDR_NULL) + continue; + list.emplace_back(EXTENDED::DISCOVERY::discoveredUniverse()); + list.back().universe = num; + } + + /// > \cite sACN 8.3 Page + /// > + /// > A single source may be transmitting on so many universes that the + /// > total number of universes it must include in its List of Universes + /// > will span multiple packets. Each one of these packets acts as a + /// > “page” of those universes. + /// + /// > \cite sACN 8.4 Last Page + /// > + /// > The Universe Discovery Layer's Last Page field is an 8-bit field + /// > indicating the number of the final page being to be transmitted. ... + /// > Page numbers are indexed starting at 0. + header.last_page = list.size() / 512; + for (size_t i = 0; i <= header.last_page; i++) + { + /// > The Universe Discovery Layer's Page field is an 8-bit field + /// > indicating the page number of this E1.31 Universe Discovery Packet. + /// > Page numbers are indexed, starting at 0. + header.page = i; + + // universe discover layer data + EXTENDED::DISCOVERY::discovery_list_data data; + for (size_t n = i * 512; n < (i * 512) + 512; n++) + { + if (n > list.size()) + break; + data.found.push_back(list.at(n)); + } + + // framing layer data + auto dlistpdu = new EXTENDED::DISCOVERY::Pdu; + dlistpdu->setVector(VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST); + dlistpdu->setHeader(&header); + dlistpdu->setData(&data); + + // framing layer + sendExtendedFrame(VECTOR_E131_EXTENDED_DISCOVERY, frmheader, dlistpdu, ip); + } +} + + /** * @brief Source::sendExtendedFrame * @param vector diff --git a/protocols/sacn/source.h b/protocols/sacn/source.h index f3bef02..aab5c3b 100644 --- a/protocols/sacn/source.h +++ b/protocols/sacn/source.h @@ -51,6 +51,7 @@ public: protected: virtual void end(const uint16_t); + virtual void discoveryAnnounce(); void sendExtendedFrame(const uint16_t vector, ACN::PDU::pdu_header *header,