2016-06-20 08:38:12 +02:00
|
|
|
// project includes
|
|
|
|
#include <udplistener/UDPListener.h>
|
|
|
|
|
2018-12-28 18:12:45 +01:00
|
|
|
// bonjour includes
|
2018-12-27 23:11:32 +01:00
|
|
|
#include <bonjour/bonjourserviceregister.h>
|
|
|
|
|
2018-12-28 18:12:45 +01:00
|
|
|
// hyperion includes
|
2019-02-17 15:26:11 +01:00
|
|
|
#include <hyperion/Hyperion.h>
|
2019-07-14 22:43:22 +02:00
|
|
|
#include <hyperion/HyperionIManager.h>
|
2016-06-20 08:38:12 +02:00
|
|
|
#include "HyperionConfig.h"
|
|
|
|
|
2019-07-12 16:54:26 +02:00
|
|
|
// utils includes
|
|
|
|
#include <utils/NetOrigin.h>
|
|
|
|
|
2018-12-27 23:11:32 +01:00
|
|
|
// qt includes
|
|
|
|
#include <QUdpSocket>
|
2018-12-28 18:12:45 +01:00
|
|
|
#include <QJsonObject>
|
2018-12-27 23:11:32 +01:00
|
|
|
|
2016-08-11 07:13:55 +02:00
|
|
|
using namespace hyperion;
|
|
|
|
|
2019-07-12 16:54:26 +02:00
|
|
|
UDPListener::UDPListener(const QJsonDocument& config)
|
|
|
|
: QObject()
|
|
|
|
, _server(new QUdpSocket(this))
|
|
|
|
, _priority(0)
|
|
|
|
, _timeout(0)
|
|
|
|
, _log(Logger::getInstance("UDPLISTENER"))
|
|
|
|
, _isActive(false)
|
|
|
|
, _listenPort(0)
|
|
|
|
, _netOrigin(NetOrigin::getInstance())
|
2016-06-20 08:38:12 +02:00
|
|
|
{
|
2018-12-27 23:11:32 +01:00
|
|
|
// init
|
|
|
|
handleSettingsUpdate(settings::UDPLISTENER, config);
|
2016-06-27 09:27:11 +02:00
|
|
|
}
|
2016-06-25 15:15:23 +02:00
|
|
|
|
2016-06-27 09:27:11 +02:00
|
|
|
UDPListener::~UDPListener()
|
|
|
|
{
|
|
|
|
// clear the current channel
|
|
|
|
stop();
|
|
|
|
delete _server;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPListener::start()
|
|
|
|
{
|
|
|
|
if ( active() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QHostAddress mcastGroup;
|
2019-07-14 22:43:22 +02:00
|
|
|
if (_listenAddress.isInSubnet(QHostAddress::parseSubnet("224.0.0.0/4")))
|
|
|
|
{
|
2016-06-27 09:27:11 +02:00
|
|
|
mcastGroup = _listenAddress;
|
2016-06-26 20:08:03 +02:00
|
|
|
}
|
2016-06-25 15:15:23 +02:00
|
|
|
|
2016-06-27 09:27:11 +02:00
|
|
|
if (!_server->bind(_listenAddress, _listenPort, _bondage))
|
2016-06-20 08:38:12 +02:00
|
|
|
{
|
2018-12-27 23:11:32 +01:00
|
|
|
Error(_log, "Could not bind to %s:%d", _listenAddress.toString().toStdString().c_str(), _listenPort);
|
2016-06-27 09:27:11 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Info(_log, "Started, listening on %s:%d", _listenAddress.toString().toStdString().c_str(), _listenPort);
|
2019-07-14 22:43:22 +02:00
|
|
|
if (!mcastGroup.isNull())
|
|
|
|
{
|
2016-06-27 09:27:11 +02:00
|
|
|
bool joinGroupOK = _server->joinMulticastGroup(_listenAddress);
|
|
|
|
InfoIf ( joinGroupOK, _log, "Multicast enabled");
|
|
|
|
WarningIf( ! joinGroupOK, _log, "Multicast failed");
|
2016-06-25 15:15:23 +02:00
|
|
|
}
|
2016-06-27 09:27:11 +02:00
|
|
|
_isActive = true;
|
2018-12-27 23:11:32 +01:00
|
|
|
|
2018-12-28 18:12:45 +01:00
|
|
|
if(_serviceRegister == nullptr)
|
|
|
|
{
|
|
|
|
_serviceRegister = new BonjourServiceRegister(this);
|
|
|
|
_serviceRegister->registerService("_hyperiond-udp._udp", _listenPort);
|
|
|
|
}
|
|
|
|
else if( _serviceRegister->getPort() != _listenPort)
|
2018-12-27 23:11:32 +01:00
|
|
|
{
|
2018-12-28 18:12:45 +01:00
|
|
|
delete _serviceRegister;
|
|
|
|
_serviceRegister = new BonjourServiceRegister(this);
|
|
|
|
_serviceRegister->registerService("_hyperiond-udp._udp", _listenPort);
|
2018-12-27 23:11:32 +01:00
|
|
|
}
|
2016-06-20 08:38:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 09:27:11 +02:00
|
|
|
void UDPListener::stop()
|
2016-06-20 08:38:12 +02:00
|
|
|
{
|
2016-06-27 09:27:11 +02:00
|
|
|
if ( ! active() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
_server->close();
|
|
|
|
_isActive = false;
|
2018-12-27 23:11:32 +01:00
|
|
|
Info(_log, "Stopped");
|
2016-06-20 08:38:12 +02:00
|
|
|
}
|
|
|
|
|
2019-07-14 22:43:22 +02:00
|
|
|
void UDPListener::updatedComponentState(const hyperion::Components component, bool enable)
|
2016-08-11 07:13:55 +02:00
|
|
|
{
|
2016-09-07 20:10:37 +02:00
|
|
|
if (component == COMP_UDPLISTENER)
|
2016-08-11 07:13:55 +02:00
|
|
|
{
|
2016-09-07 20:10:37 +02:00
|
|
|
if (_isActive != enable)
|
|
|
|
{
|
|
|
|
if (enable) start();
|
|
|
|
else stop();
|
|
|
|
}
|
2016-08-11 07:13:55 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-27 09:27:11 +02:00
|
|
|
|
2016-06-20 08:38:12 +02:00
|
|
|
uint16_t UDPListener::getPort() const
|
|
|
|
{
|
|
|
|
return _server->localPort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPListener::readPendingDatagrams()
|
|
|
|
{
|
2019-07-14 22:43:22 +02:00
|
|
|
while (_server->hasPendingDatagrams())
|
|
|
|
{
|
2016-06-20 08:38:12 +02:00
|
|
|
QByteArray datagram;
|
|
|
|
datagram.resize(_server->pendingDatagramSize());
|
|
|
|
QHostAddress sender;
|
|
|
|
quint16 senderPort;
|
|
|
|
|
2016-08-11 07:13:55 +02:00
|
|
|
_server->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
|
2019-07-12 16:54:26 +02:00
|
|
|
|
|
|
|
if(_netOrigin->accessAllowed(sender, _listenAddress))
|
|
|
|
processTheDatagram(&datagram, &sender);
|
2016-06-20 08:38:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 15:23:53 +01:00
|
|
|
void UDPListener::processTheDatagram(const QByteArray * datagram, const QHostAddress * sender)
|
2016-06-20 08:38:12 +02:00
|
|
|
{
|
2016-07-11 13:15:08 +02:00
|
|
|
int packetLedCount = datagram->size()/3;
|
2018-12-28 18:12:45 +01:00
|
|
|
//DebugIf( (packetLedCount != hyperionLedCount), _log, "packetLedCount (%d) != hyperionLedCount (%d)", packetLedCount, hyperionLedCount);
|
2016-06-20 08:38:12 +02:00
|
|
|
|
2018-12-28 18:12:45 +01:00
|
|
|
std::vector<ColorRgb> _ledColors(packetLedCount, ColorRgb::BLACK);
|
2016-07-11 13:15:08 +02:00
|
|
|
|
2019-07-14 22:43:22 +02:00
|
|
|
for (int ledIndex=0; ledIndex < packetLedCount; ledIndex++)
|
|
|
|
{
|
2016-06-20 08:38:12 +02:00
|
|
|
ColorRgb & rgb = _ledColors[ledIndex];
|
2017-03-01 15:23:53 +01:00
|
|
|
rgb.red = datagram->at(ledIndex*3+0);
|
2016-06-20 08:38:12 +02:00
|
|
|
rgb.green = datagram->at(ledIndex*3+1);
|
2017-03-01 15:23:53 +01:00
|
|
|
rgb.blue = datagram->at(ledIndex*3+2);
|
2016-06-20 08:38:12 +02:00
|
|
|
}
|
2018-12-27 23:11:32 +01:00
|
|
|
// TODO provide a setInput with origin arg to overwrite senders smarter
|
2018-12-28 18:12:45 +01:00
|
|
|
emit registerGlobalInput(_priority, hyperion::COMP_UDPLISTENER, QString("UDPListener@%1").arg(sender->toString()));
|
|
|
|
emit setGlobalInput(_priority, _ledColors, _timeout);
|
2016-06-20 08:38:12 +02:00
|
|
|
}
|
2017-03-01 15:23:53 +01:00
|
|
|
|
2018-12-27 23:11:32 +01:00
|
|
|
void UDPListener::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
|
|
|
|
{
|
|
|
|
if(type == settings::UDPLISTENER)
|
|
|
|
{
|
|
|
|
QJsonObject obj = config.object();
|
|
|
|
// if we change the prio we need to make sure the old one is cleared before we apply the new one!
|
|
|
|
stop();
|
|
|
|
|
|
|
|
QString addr = obj["address"].toString("");
|
|
|
|
_priority = obj["priority"].toInt();
|
|
|
|
_listenPort = obj["port"].toInt();
|
|
|
|
_listenAddress = addr.isEmpty()? QHostAddress::AnyIPv4 : QHostAddress(addr);
|
|
|
|
_bondage = (obj["shared"].toBool(false)) ? QAbstractSocket::ShareAddress : QAbstractSocket::DefaultForPlatform;
|
|
|
|
_timeout = obj["timeout"].toInt(10000);
|
|
|
|
if(obj["enable"].toBool())
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
}
|