2021-05-27 10:59:22 -04:00
|
|
|
/*
|
|
|
|
receiver.cpp
|
|
|
|
|
|
|
|
Copyright (c) 2020 Kevin Matz (kevin.matz@gmail.com)
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "receiver.h"
|
2021-08-09 15:01:41 -04:00
|
|
|
#include "config.h"
|
2021-05-27 10:59:22 -04:00
|
|
|
|
|
|
|
namespace SACN {
|
|
|
|
|
|
|
|
/**
|
2021-06-22 21:26:03 -04:00
|
|
|
* @brief Receiver::Receiver
|
|
|
|
* @param cid
|
|
|
|
*
|
|
|
|
* Constructor. Register RLP vector callbacks.
|
|
|
|
*/
|
2021-05-27 10:59:22 -04:00
|
|
|
Receiver::Receiver(UUID::uuid cid)
|
|
|
|
: Appliance(cid)
|
|
|
|
{
|
2021-07-30 09:31:16 -04:00
|
|
|
fctn_ = "libESTA sACN Receiver";
|
2021-07-30 09:26:21 -04:00
|
|
|
|
2021-08-15 11:22:01 -04:00
|
|
|
RlpRegisterVector(VECTOR_ROOT_E131_DATA, std::bind(&Receiver::dataReceiver,
|
|
|
|
this, std::placeholders::_1));
|
|
|
|
RlpRegisterVector(VECTOR_ROOT_E131_EXTENDED, std::bind(&Receiver::extendedReceiver,
|
|
|
|
this, std::placeholders::_1));
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-02 10:09:14 -04:00
|
|
|
/**
|
|
|
|
* @brief Receiver::~Receiver
|
|
|
|
*/
|
|
|
|
Receiver::~Receiver()
|
|
|
|
{
|
|
|
|
for (auto& [_, universe] : universes_)
|
|
|
|
delete universe;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
/**
|
|
|
|
* @brief Receiver::subscribe
|
|
|
|
* @param num
|
|
|
|
*/
|
2021-05-27 10:59:22 -04:00
|
|
|
void Receiver::subscribe(const uint16_t num) {
|
2021-06-22 21:26:03 -04:00
|
|
|
if (universes_.count(num))
|
|
|
|
return;
|
2021-08-02 10:09:14 -04:00
|
|
|
universes_.emplace(num, new MergeProxyUniverse());
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::unsubscribe
|
|
|
|
* @param num
|
|
|
|
*/
|
2021-05-27 10:59:22 -04:00
|
|
|
void Receiver::unsubscribe(const uint16_t num) {
|
2021-08-02 10:09:14 -04:00
|
|
|
// delete merging universe proxy
|
|
|
|
if (universes_.count(num)) {
|
|
|
|
delete universes_.at(num);
|
|
|
|
universes_.erase(num);
|
|
|
|
}
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::universe
|
|
|
|
* @param num
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
Universe * Receiver::universe(const uint16_t num) {
|
|
|
|
if (!universes_.count(num))
|
|
|
|
return 0;
|
|
|
|
return universes_.at(num);
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::discoveryStart
|
|
|
|
*/
|
2021-06-02 09:29:27 -04:00
|
|
|
void Receiver::discoveryStart() {
|
|
|
|
subscribe(SACN::E131_DISCOVERY_UNIVERSE);
|
|
|
|
}
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::discoveryStop
|
|
|
|
*/
|
2021-06-02 09:29:27 -04:00
|
|
|
void Receiver::discoveryStop() {
|
|
|
|
unsubscribe(SACN::E131_DISCOVERY_UNIVERSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2021-06-22 21:26:03 -04:00
|
|
|
* @brief Receiver::onDiscovered
|
|
|
|
* @param cb something that wants to know about available universes.
|
|
|
|
*/
|
2021-06-02 09:29:27 -04:00
|
|
|
void Receiver::onDiscovered(const EXTENDED::DISCOVERY::Watcher cb) {
|
|
|
|
discoveryCallbacks_.push_back(cb);
|
|
|
|
}
|
|
|
|
|
2021-05-27 10:59:22 -04:00
|
|
|
|
|
|
|
/**
|
2021-07-28 10:43:43 -04:00
|
|
|
* @brief Receiver::dataReceiver - dispatcher of RLP DATA PDU
|
2021-06-22 21:26:03 -04:00
|
|
|
* @param root a shared pointer to the PDU
|
|
|
|
*
|
|
|
|
* Receive VECTOR_ROOT_E131_DATA vector'd packets.
|
|
|
|
*/
|
2021-08-15 11:14:09 -04:00
|
|
|
void Receiver::dataReceiver(std::shared_ptr<RLP::Pdu> root)
|
|
|
|
{
|
2021-08-15 13:16:59 -04:00
|
|
|
root->createDataBlock<DATA::Pdu>();
|
|
|
|
auto block = static_cast<PDU::Block<DATA::Pdu>*>(root->data());
|
2021-08-14 09:28:28 -04:00
|
|
|
|
2021-08-15 13:16:59 -04:00
|
|
|
for(auto const &frame : *block->pdu)
|
2021-08-15 11:14:09 -04:00
|
|
|
{
|
|
|
|
// 6.2.1 E1.31 Data Packet: Vector
|
|
|
|
// Sources sending an E1.31 Data Packet shall set the E1.31 Layer's Vector
|
|
|
|
// to VECTOR_E131_DATA_PACKET. This value indicates that the E1.31 framing
|
|
|
|
// layer is wrapping a DMP PDU.
|
|
|
|
switch(frame->vector()) {
|
|
|
|
case VECTOR_E131_DATA_PACKET:
|
|
|
|
dataFrameHandler(frame);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-02 09:29:27 -04:00
|
|
|
/**
|
2021-07-28 10:43:43 -04:00
|
|
|
* @brief Receiver::extendedReceiver - dispatcher of RLP EXTENDED PDU
|
2021-06-22 21:26:03 -04:00
|
|
|
* @param root a shared pointer to the PDU
|
|
|
|
*
|
|
|
|
* Receive VECTOR_ROOT_E131_EXTENDED vector'd packets.
|
|
|
|
*/
|
2021-08-15 11:14:09 -04:00
|
|
|
void Receiver::extendedReceiver(std::shared_ptr<RLP::Pdu> root)
|
|
|
|
{
|
2021-08-15 13:16:59 -04:00
|
|
|
root->createDataBlock<EXTENDED::Pdu>();
|
|
|
|
auto block = static_cast<PDU::Block<EXTENDED::Pdu>*>(root->data());
|
2021-08-14 09:28:28 -04:00
|
|
|
|
2021-08-15 13:16:59 -04:00
|
|
|
for(auto const &frame : *block->pdu)
|
2021-08-15 11:14:09 -04:00
|
|
|
{
|
2021-06-02 09:29:27 -04:00
|
|
|
switch(frame->vector()) {
|
|
|
|
// 6.3 E1.31 Synchronization Packet Framing Layer
|
|
|
|
case VECTOR_E131_EXTENDED_SYNCHRONIZATION:
|
2021-07-28 10:43:43 -04:00
|
|
|
syncFrameHandler(frame);
|
2021-06-02 09:29:27 -04:00
|
|
|
break;
|
2021-08-14 09:28:28 -04:00
|
|
|
// 6.4 E1.31 Universe Discovery Packet Framing Layer
|
2021-06-02 09:29:27 -04:00
|
|
|
case VECTOR_E131_EXTENDED_DISCOVERY:
|
2021-07-28 10:43:43 -04:00
|
|
|
discoveryFrameHandler(frame);
|
2021-06-02 09:29:27 -04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2021-08-14 09:28:28 -04:00
|
|
|
}
|
2021-06-02 09:29:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-22 21:26:03 -04:00
|
|
|
/**
|
2021-07-28 10:43:43 -04:00
|
|
|
* @brief Receiver::dataFrameHandler
|
2021-06-22 21:26:03 -04:00
|
|
|
* @param frame
|
|
|
|
*
|
|
|
|
* Receive `VECTOR_ROOT_E131_DATA -> VECTOR_E131_DATA_PACKET` vector'd packets.
|
|
|
|
*
|
|
|
|
* Merging will be based on frame header. PDU data will be read as a block of
|
|
|
|
* DMP PDUs and passed to the universe.
|
|
|
|
*
|
|
|
|
*/
|
2021-07-28 10:43:43 -04:00
|
|
|
void Receiver::dataFrameHandler(std::shared_ptr<DATA::Pdu> frame) {
|
2021-05-27 10:59:22 -04:00
|
|
|
auto source = std::shared_ptr<UniverseSource>(new UniverseSource(frame));
|
|
|
|
|
2021-07-28 10:43:43 -04:00
|
|
|
if (!universes_.count(source->universe()))
|
2021-05-27 10:59:22 -04:00
|
|
|
return;
|
2021-08-02 10:09:14 -04:00
|
|
|
auto universe = universes_.at(source->universe())->sourceUniverse(*source);
|
2021-05-27 10:59:22 -04:00
|
|
|
|
|
|
|
// 6.2.3 E1.31 Data Packet: Priority
|
|
|
|
// No priority outside the range of 0 to 200 shall be transmitted on
|
|
|
|
// the network.
|
|
|
|
if (source->priority() > 200)
|
2021-06-19 10:18:09 -04:00
|
|
|
frame->stream()->setstate(std::ios_base::failbit);
|
2021-05-27 10:59:22 -04:00
|
|
|
|
|
|
|
// 6.2.6 E1.31 Data Packet: Options
|
|
|
|
// Preview_Data: Bit 7 (most significant bit)
|
2021-08-06 12:36:04 -04:00
|
|
|
// This bit, when set to 1, indicates that the data in this packet is
|
|
|
|
// intended for use in visualization or media server preview applications and
|
|
|
|
// shall not be used to generate live output.
|
2021-05-27 10:59:22 -04:00
|
|
|
if (source->isPreview())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// 6.2.6 E1.31 Data Packet: Options
|
|
|
|
// Stream_Terminated: Bit 6
|
|
|
|
// allow E1.31 sources to terminate transmission of a stream or of
|
|
|
|
// universe synchronization without waiting for a timeout to occur.
|
|
|
|
// Any property values in an E1.31 Data Packet containing this bit
|
|
|
|
// shall be ignored.
|
|
|
|
if (source->isTerminated()) {
|
2021-08-02 10:09:14 -04:00
|
|
|
universes_[source->universe()]->deleteSourceUniverse(*source);
|
2021-05-27 10:59:22 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 6.2.4.1 Synchronization Address Usage in an E1.31 Data Packet
|
|
|
|
// a value of 0 in the Synchronization Address indicates that the universe
|
|
|
|
// data is not synchronized.
|
2021-08-06 12:36:04 -04:00
|
|
|
if (source->syncAddress() != 0)
|
|
|
|
subscribe(source->syncAddress());
|
2021-05-27 10:59:22 -04:00
|
|
|
|
|
|
|
// PDU data will be a block of DMP
|
2021-08-14 09:28:28 -04:00
|
|
|
auto block = static_cast<PDU::Block<DMP::Pdu>*>(frame->data());
|
2021-08-15 11:14:09 -04:00
|
|
|
for (auto const &dmp : *block->pdu)
|
|
|
|
{
|
|
|
|
// 7.2 DMP Layer: Vector
|
|
|
|
// The DMP Layer's Vector shall be set to VECTOR_DMP_SET_PROPERTY, which
|
|
|
|
// indicates a DMP Set Property message by sources. Receivers shall discard
|
|
|
|
// the packet if the received value is not VECTOR_DMP_SET_PROPERTY.
|
|
|
|
switch(dmp->vector()) {
|
|
|
|
case DMP::SET_PROPERTY:
|
|
|
|
universe->set(dmp, source);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-05-27 10:59:22 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-28 10:43:43 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::syncFrameHandler
|
|
|
|
* @param frame
|
|
|
|
*/
|
2021-08-06 12:36:04 -04:00
|
|
|
void Receiver::syncFrameHandler(std::shared_ptr<EXTENDED::Pdu> frame)
|
2021-07-28 10:43:43 -04:00
|
|
|
{
|
2021-08-06 12:36:04 -04:00
|
|
|
#if defined(RTTI_ENABLED)
|
|
|
|
auto header = dynamic_cast<EXTENDED::frame_sync_header*>(frame->header());
|
|
|
|
#else
|
2021-08-14 09:28:28 -04:00
|
|
|
auto header = static_cast<EXTENDED::sync_header*>(frame->header());
|
2021-08-06 12:36:04 -04:00
|
|
|
#endif
|
|
|
|
universes_.at(header->sync_address)->synchronize();
|
2021-07-28 10:43:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::discoveryFrameHandler
|
|
|
|
* @param frame
|
|
|
|
*/
|
|
|
|
void Receiver::discoveryFrameHandler(std::shared_ptr<EXTENDED::Pdu> frame) {
|
2021-08-14 09:28:28 -04:00
|
|
|
// PDU data will be a block of Discovery List PDU
|
|
|
|
auto block = static_cast<PDU::Block<EXTENDED::DISCOVERY::Pdu>*>(frame->data());
|
|
|
|
for(auto const &pdu : *block->pdu)
|
|
|
|
{
|
|
|
|
// 8 Universe Discovery Layer
|
|
|
|
// Universe Discovery data only appears in E1.31 Universe Discovery
|
|
|
|
// Packets and shall not be included in E1.31 Data Packets or E1.31
|
|
|
|
// Synchronization Packets.
|
2021-07-28 10:43:43 -04:00
|
|
|
switch(pdu->vector()) {
|
|
|
|
case VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST:
|
|
|
|
discoveryListHanlder(pdu);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2021-08-14 09:28:28 -04:00
|
|
|
}
|
2021-07-28 10:43:43 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Receiver::discoveryListHanlder
|
|
|
|
* @param pdu
|
|
|
|
*/
|
|
|
|
void Receiver::discoveryListHanlder(std::shared_ptr<EXTENDED::DISCOVERY::Pdu> pdu) {
|
2021-08-14 09:28:28 -04:00
|
|
|
auto data = static_cast<EXTENDED::DISCOVERY::discovery_list_data*>(pdu->data());
|
|
|
|
for (auto& f : data->found)
|
|
|
|
for (const auto &cb : discoveryCallbacks_)
|
|
|
|
cb(std::make_shared<EXTENDED::DISCOVERY::discoveredUniverse>(f));
|
2021-07-28 10:43:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-27 10:59:22 -04:00
|
|
|
}; // SACN
|