From 0aa467ccebc5d404aaa01f71e2196f011964613d Mon Sep 17 00:00:00 2001 From: redPanther Date: Tue, 21 Mar 2017 17:55:46 +0100 Subject: [PATCH] populate zeroconf/avahi/bonjour records via json api (#419) * start of integrating a bonkour service browser * some experiments * blub * bonjour browser via jsonrpc ... * fix indention * - make leddevice as component - extend sysinfo with domain - add more data for bonjour browser (e.g. split domain and hostname) * code cleanup * add translation * use component names instead of ids * fix compile --- .../firmware/arduino/mega_pwm_led_driver.fzz | Bin 13150 -> 0 bytes assets/webconfig/i18n/de.json | 1 + assets/webconfig/i18n/en.json | 1 + assets/webconfig/js/content_remote.js | 20 ++- include/bonjour/bonjourrecord.h | 54 ++++---- include/bonjour/bonjourservicebrowser.h | 65 ++++++++++ include/bonjour/bonjourserviceresolver.h | 69 ++++++++++ include/hyperion/Hyperion.h | 23 +++- include/leddevice/LedDevice.h | 11 +- include/utils/Components.h | 6 +- include/utils/SysInfo.h | 1 + libsrc/bonjour/CMakeLists.txt | 10 +- libsrc/bonjour/bonjourservicebrowser.cpp | 109 ++++++++++++++++ libsrc/bonjour/bonjourserviceresolver.cpp | 122 ++++++++++++++++++ libsrc/hyperion/CMakeLists.txt | 1 + libsrc/hyperion/Hyperion.cpp | 102 ++++++++++++--- libsrc/hyperion/LinearColorSmoothing.cpp | 9 +- libsrc/hyperion/LinearColorSmoothing.h | 5 - libsrc/hyperion/PriorityMuxer.cpp | 8 +- libsrc/jsonserver/JsonClientConnection.cpp | 45 +++++-- .../schema/schema-componentstate.json | 2 +- libsrc/leddevice/LedDevice.cpp | 21 ++- libsrc/utils/SysInfo.cpp | 1 + src/hyperion-remote/hyperion-remote.cpp | 7 +- src/hyperiond/main.cpp | 3 + 25 files changed, 601 insertions(+), 95 deletions(-) delete mode 100644 assets/firmware/arduino/mega_pwm_led_driver.fzz create mode 100644 include/bonjour/bonjourservicebrowser.h create mode 100644 include/bonjour/bonjourserviceresolver.h create mode 100644 libsrc/bonjour/bonjourservicebrowser.cpp create mode 100644 libsrc/bonjour/bonjourserviceresolver.cpp diff --git a/assets/firmware/arduino/mega_pwm_led_driver.fzz b/assets/firmware/arduino/mega_pwm_led_driver.fzz deleted file mode 100644 index c1a97cbe45489076a72a3e4c77a2a768bfa63850..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13150 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 Z@BjQvjD`v#(yJI2`jUkr0`Kd${|EfG'; - if(compId == 10) + if(compId == "EFFECT") owner = $.i18n('remote_effects_label_effects')+' '+owner; - if(compId == 9) - owner = $.i18n('remote_color_label_color')+' '+'
'; - if(compId == 7) + if(compId == "COLOR") + owner = (owner == "Off") ? $.i18n('general_btn_off') : $.i18n('remote_color_label_color')+' '+'
'; + if(compId == "GRABBER") owner = $.i18n('general_comp_GRABBER')+': ('+owner+')'; - if(compId == 8) + if(compId == "V4L") owner = $.i18n('general_comp_V4L')+': ('+owner+')'; - if(compId == 6) + if(compId == "BOBLIGHTSERVER") owner = $.i18n('general_comp_BOBLIGHTSERVER'); - if(compId == 5) + if(compId == "UDPLISTENER") owner = $.i18n('general_comp_UDPLISTENER'); - if(owner == "Off") - owner = $.i18n('general_btn_off'); - if(duration && compId != 7 && compId != 11) + if(duration && compId != "GRABBER" && compId != "PROTOSERVER") owner += '
'+$.i18n('remote_input_duration')+' '+duration.toFixed(0)+$.i18n('edt_append_s')+''; var btn = ''; - if((compId == 10 || compId == 9) && priority != 254) + if((compId == "EFFECT" || compId == "COLOR") && priority < 254) btn += ''; if(btn_type != 'default') diff --git a/include/bonjour/bonjourrecord.h b/include/bonjour/bonjourrecord.h index ae2ebc00..63ed17ab 100755 --- a/include/bonjour/bonjourrecord.h +++ b/include/bonjour/bonjourrecord.h @@ -5,14 +5,14 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. + derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -35,24 +35,34 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class BonjourRecord { public: - BonjourRecord() {} - BonjourRecord(const QString &name, const QString ®Type, const QString &domain) - : serviceName(name), registeredType(regType), replyDomain(domain) - {} - BonjourRecord(const char *name, const char *regType, const char *domain) - { - serviceName = QString::fromUtf8(name); - registeredType = QString::fromUtf8(regType); - replyDomain = QString::fromUtf8(domain); - } - QString serviceName; - QString registeredType; - QString replyDomain; - bool operator==(const BonjourRecord &other) const { - return serviceName == other.serviceName - && registeredType == other.registeredType - && replyDomain == other.replyDomain; - } + BonjourRecord() : port(-1) {} + BonjourRecord(const QString &name, const QString ®Type, const QString &domain) + : serviceName(name) + , registeredType(regType) + , replyDomain(domain) + , port(-1) + {} + + BonjourRecord(const char *name, const char *regType, const char *domain) + : serviceName(QString::fromUtf8(name)) + , registeredType(QString::fromUtf8(regType)) + , replyDomain(QString::fromUtf8(domain)) + , port(-1) + { + } + + QString serviceName; + QString registeredType; + QString replyDomain; + QString hostName; + int port; + + bool operator==(const BonjourRecord &other) const + { + return serviceName == other.serviceName + && registeredType == other.registeredType + && replyDomain == other.replyDomain; + } }; Q_DECLARE_METATYPE(BonjourRecord) diff --git a/include/bonjour/bonjourservicebrowser.h b/include/bonjour/bonjourservicebrowser.h new file mode 100644 index 00000000..590747fd --- /dev/null +++ b/include/bonjour/bonjourservicebrowser.h @@ -0,0 +1,65 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURSERVICEBROWSER_H +#define BONJOURSERVICEBROWSER_H + +#include +#include +#include "bonjour/bonjourrecord.h" + + +class QSocketNotifier; +class BonjourServiceBrowser : public QObject +{ + Q_OBJECT +public: + BonjourServiceBrowser(QObject *parent = 0); + ~BonjourServiceBrowser(); + void browseForServiceType(const QString &serviceType); + inline QList currentRecords() const { return bonjourRecords; } + inline QString serviceType() const { return browsingType; } + +signals: + void currentBonjourRecordsChanged(const QList &list); + void error(DNSServiceErrorType err); + +private slots: + void bonjourSocketReadyRead(); + +private: + static void DNSSD_API bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, quint32, + DNSServiceErrorType errorCode, const char *serviceName, + const char *regType, const char *replyDomain, void *context); + DNSServiceRef dnssref; + QSocketNotifier *bonjourSocket; + QList bonjourRecords; + QString browsingType; +}; + +#endif // BONJOURSERVICEBROWSER_H diff --git a/include/bonjour/bonjourserviceresolver.h b/include/bonjour/bonjourserviceresolver.h new file mode 100644 index 00000000..08ab3811 --- /dev/null +++ b/include/bonjour/bonjourserviceresolver.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef BONJOURSERVICERESOLVER_H +#define BONJOURSERVICERESOLVER_H + +#include + + +#include + +class QSocketNotifier; +class QHostInfo; +class BonjourRecord; + +class BonjourServiceResolver : public QObject +{ + Q_OBJECT +public: + BonjourServiceResolver(QObject *parent); + ~BonjourServiceResolver(); + + bool resolveBonjourRecord(const BonjourRecord &record); + +signals: + void bonjourRecordResolved(const QHostInfo &hostInfo, int port); + void error(DNSServiceErrorType error); + +private slots: + void bonjourSocketReadyRead(); + void cleanupResolve(); + void finishConnect(const QHostInfo &hostInfo); + +private: + static void DNSSD_API bonjourResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags, + quint32 interfaceIndex, DNSServiceErrorType errorCode, + const char *fullName, const char *hosttarget, quint16 port, + quint16 txtLen, const char *txtRecord, void *context); + DNSServiceRef dnssref; + QSocketNotifier *bonjourSocket; + int bonjourPort; +}; + +#endif // BONJOURSERVICERESOLVER_H diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 3202b7af..973fef29 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -2,11 +2,12 @@ // stl includes #include -#include +#include // QT includes #include #include +#include #include #include #include @@ -33,6 +34,8 @@ // KodiVideoChecker includes #include +#include +#include // Forward class declaration class LedDevice; @@ -52,8 +55,8 @@ class Hyperion : public QObject public: /// Type definition of the info structure used by the priority muxer typedef PriorityMuxer::InputInfo InputInfo; - typedef std::map PriorityRegister; - + typedef QMap PriorityRegister; + typedef QMap BonjourRegister; /// /// RGB-Color channel enumeration /// @@ -257,6 +260,9 @@ public slots: /// sets the methode how image is maped to leds void setLedMappingType(int mappingType); + /// + Hyperion::BonjourRegister getHyperionSessions(); + public: static Hyperion *_hyperion; @@ -302,6 +308,10 @@ private slots: /// void update(); + void currentBonjourRecordsChanged(const QList &list); + void bonjourRecordResolved(const QHostInfo &hostInfo, int port); + void bonjourResolve(); + private: /// @@ -344,6 +354,7 @@ private: /// The timer for handling priority channel timeouts QTimer _timer; + QTimer _timerBonjourResolver; /// buffer for leds std::vector _ledBuffer; @@ -373,5 +384,9 @@ private: int _configVersionId; - hyperion::Components _prevCompId; + hyperion::Components _prevCompId; + BonjourServiceBrowser _bonjourBrowser; + BonjourServiceResolver _bonjourResolver; + BonjourRegister _hyperionSessions; + QString _bonjourCurrentServiceToResolve; }; diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h index aae575eb..01af8188 100644 --- a/include/leddevice/LedDevice.h +++ b/include/leddevice/LedDevice.h @@ -19,6 +19,7 @@ #include #include #include +#include class LedDevice; @@ -58,6 +59,12 @@ public: static QJsonObject getLedDeviceSchemas(); static void setLedCount(int ledCount); static int getLedCount() { return _ledCount; } + + void setEnable(bool enable); + bool enabled() { return _enabled; }; + + inline bool componentState() { return enabled(); }; + protected: /// /// Writes the RGB-Color values to the leds. @@ -88,11 +95,13 @@ protected: /// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds QTimer _refresh_timer; unsigned int _refresh_timer_interval; - + protected slots: /// Write the last data to the leds again int rewriteLeds(); private: std::vector _ledValues; + bool _componentRegistered; + bool _enabled; }; diff --git a/include/utils/Components.h b/include/utils/Components.h index 37165a6e..1754c2f2 100644 --- a/include/utils/Components.h +++ b/include/utils/Components.h @@ -19,7 +19,8 @@ enum Components COMP_V4L, COMP_COLOR, COMP_EFFECT, - COMP_PROTOSERVER + COMP_PROTOSERVER, + COMP_LEDDEVICE }; inline const char* componentToString(Components c) @@ -37,6 +38,7 @@ inline const char* componentToString(Components c) case COMP_COLOR: return "Solid color"; case COMP_EFFECT: return "Effect"; case COMP_PROTOSERVER: return "Proto Server"; + case COMP_LEDDEVICE: return "LED device"; default: return ""; } } @@ -56,6 +58,7 @@ inline const char* componentToIdString(Components c) case COMP_COLOR: return "COLOR"; case COMP_EFFECT: return "EFFECT"; case COMP_PROTOSERVER: return "PROTOSERVER"; + case COMP_LEDDEVICE: return "LEDDEVICE"; default: return ""; } } @@ -74,6 +77,7 @@ inline Components stringToComponent(QString component) if (component == "COLOR") return COMP_COLOR; if (component == "EFFECT") return COMP_EFFECT; if (component == "PROTOSERVER") return COMP_PROTOSERVER; + if (component == "LEDDEVICE") return COMP_LEDDEVICE; return COMP_INVALID; } diff --git a/include/utils/SysInfo.h b/include/utils/SysInfo.h index b6b97bb6..4ab17732 100644 --- a/include/utils/SysInfo.h +++ b/include/utils/SysInfo.h @@ -18,6 +18,7 @@ public: QString productVersion; QString prettyName; QString hostName; + QString domainName; }; ~SysInfo(); diff --git a/libsrc/bonjour/CMakeLists.txt b/libsrc/bonjour/CMakeLists.txt index 8d77aa76..e955bccc 100644 --- a/libsrc/bonjour/CMakeLists.txt +++ b/libsrc/bonjour/CMakeLists.txt @@ -6,6 +6,8 @@ set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/bonjour) # Group the headers that go through the MOC compiler set(Bonjour_QT_HEADERS ${CURRENT_HEADER_DIR}/bonjourserviceregister.h + ${CURRENT_HEADER_DIR}/bonjourservicebrowser.h + ${CURRENT_HEADER_DIR}/bonjourserviceresolver.h ) set(Bonjour_HEADERS @@ -13,13 +15,15 @@ set(Bonjour_HEADERS set(Bonjour_SOURCES ${CURRENT_SOURCE_DIR}/bonjourserviceregister.cpp + ${CURRENT_SOURCE_DIR}/bonjourservicebrowser.cpp + ${CURRENT_SOURCE_DIR}/bonjourserviceresolver.cpp ) -set(Bonjour_RESOURCES -) +#set(Bonjour_RESOURCES +#) qt5_wrap_cpp(Bonjour_HEADERS_MOC ${Bonjour_QT_HEADERS}) -qt5_add_resources(Bonjour_RESOURCES_RCC ${Bonjour_RESOURCES} OPTIONS "-no-compress") +#qt5_add_resources(Bonjour_RESOURCES_RCC ${Bonjour_RESOURCES} OPTIONS "-no-compress") add_library(bonjour ${Bonjour_HEADERS} diff --git a/libsrc/bonjour/bonjourservicebrowser.cpp b/libsrc/bonjour/bonjourservicebrowser.cpp new file mode 100644 index 00000000..34024db9 --- /dev/null +++ b/libsrc/bonjour/bonjourservicebrowser.cpp @@ -0,0 +1,109 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "bonjour/bonjourservicebrowser.h" + +#include + +BonjourServiceBrowser::BonjourServiceBrowser(QObject *parent) + : QObject(parent) + , dnssref(0) + , bonjourSocket(0) +{ +} + +BonjourServiceBrowser::~BonjourServiceBrowser() +{ + if (dnssref) + { + DNSServiceRefDeallocate(dnssref); + dnssref = 0; + } +} + +void BonjourServiceBrowser::browseForServiceType(const QString &serviceType) +{ + DNSServiceErrorType err = DNSServiceBrowse(&dnssref, 0, 0, serviceType.toUtf8().constData(), 0, bonjourBrowseReply, this); + if (err != kDNSServiceErr_NoError) + { + emit error(err); + } + else + { + int sockfd = DNSServiceRefSockFD(dnssref); + if (sockfd == -1) + { + emit error(kDNSServiceErr_Invalid); + } + else + { + bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead())); + } + } +} + +void BonjourServiceBrowser::bonjourSocketReadyRead() +{ + DNSServiceErrorType err = DNSServiceProcessResult(dnssref); + if (err != kDNSServiceErr_NoError) + { + emit error(err); + } +} + +void BonjourServiceBrowser::bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, + quint32 , DNSServiceErrorType errorCode, + const char *serviceName, const char *regType, + const char *replyDomain, void *context) +{ + BonjourServiceBrowser *serviceBrowser = static_cast(context); + if (errorCode != kDNSServiceErr_NoError) + { + emit serviceBrowser->error(errorCode); + } + else + { + BonjourRecord bonjourRecord(serviceName, regType, replyDomain); + if (flags & kDNSServiceFlagsAdd) + { + if (!serviceBrowser->bonjourRecords.contains(bonjourRecord)) + { + serviceBrowser->bonjourRecords.append(bonjourRecord); + } + } + else + { + serviceBrowser->bonjourRecords.removeAll(bonjourRecord); + } + if (!(flags & kDNSServiceFlagsMoreComing)) + { + emit serviceBrowser->currentBonjourRecordsChanged(serviceBrowser->bonjourRecords); + } + } +} diff --git a/libsrc/bonjour/bonjourserviceresolver.cpp b/libsrc/bonjour/bonjourserviceresolver.cpp new file mode 100644 index 00000000..217ae00f --- /dev/null +++ b/libsrc/bonjour/bonjourserviceresolver.cpp @@ -0,0 +1,122 @@ +/* +Copyright (c) 2007, Trenton Schulz + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#include "bonjour/bonjourrecord.h" +#include "bonjour/bonjourserviceresolver.h" + +BonjourServiceResolver::BonjourServiceResolver(QObject *parent) + : QObject(parent) + , dnssref(0) + , bonjourSocket(0) + , bonjourPort(-1) +{ +} + +BonjourServiceResolver::~BonjourServiceResolver() +{ + cleanupResolve(); +} + +void BonjourServiceResolver::cleanupResolve() +{ + if (dnssref) + { + DNSServiceRefDeallocate(dnssref); + dnssref = 0; + delete bonjourSocket; + bonjourPort = -1; + } +} + +bool BonjourServiceResolver::resolveBonjourRecord(const BonjourRecord &record) +{ + if (dnssref) + { + //qWarning("resolve in process, aborting"); + return false; + } + DNSServiceErrorType err = DNSServiceResolve(&dnssref, 0, 0, + record.serviceName.toUtf8().constData(), + record.registeredType.toUtf8().constData(), + record.replyDomain.toUtf8().constData(), + (DNSServiceResolveReply)bonjourResolveReply, this); + if (err != kDNSServiceErr_NoError) + { + emit error(err); + } + else + { + int sockfd = DNSServiceRefSockFD(dnssref); + if (sockfd == -1) + { + emit error(kDNSServiceErr_Invalid); + } + else + { + bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead())); + } + } + return true; +} + +void BonjourServiceResolver::bonjourSocketReadyRead() +{ + DNSServiceErrorType err = DNSServiceProcessResult(dnssref); + if (err != kDNSServiceErr_NoError) + emit error(err); +} + +void BonjourServiceResolver::bonjourResolveReply(DNSServiceRef sdRef, DNSServiceFlags , + quint32 , DNSServiceErrorType errorCode, + const char *, const char *hosttarget, quint16 port, + quint16 , const char *, void *context) +{ + BonjourServiceResolver *serviceResolver = static_cast(context); + if (errorCode != kDNSServiceErr_NoError) { + emit serviceResolver->error(errorCode); + return; + } +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + { + port = 0 | ((port & 0x00ff) << 8) | ((port & 0xff00) >> 8); + } +#endif + serviceResolver->bonjourPort = port; + + QHostInfo::lookupHost(QString::fromUtf8(hosttarget), serviceResolver, SLOT(finishConnect(const QHostInfo &))); +} + +void BonjourServiceResolver::finishConnect(const QHostInfo &hostInfo) +{ + emit bonjourRecordResolved(hostInfo, bonjourPort); + QMetaObject::invokeMethod(this, "cleanupResolve", Qt::QueuedConnection); +} diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 771afb40..71d39022 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -57,5 +57,6 @@ target_link_libraries(hyperion blackborder hyperion-utils leddevice + bonjour ${QT_LIBRARIES} ) diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 8835e396..2c136c28 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // QT includes #include @@ -13,6 +14,7 @@ #include #include #include +#include // hyperion include #include @@ -317,8 +319,7 @@ QSize Hyperion::getLedLayoutGridSize(const QJsonValue& ledsConfig) -LinearColorSmoothing * Hyperion::createColorSmoothing(const QJsonObject & smoothingConfig, LedDevice* leddevice) -{ +LinearColorSmoothing * Hyperion::createColorSmoothing(const QJsonObject & smoothingConfig, LedDevice* leddevice){ QString type = smoothingConfig["type"].toString("linear").toLower(); LinearColorSmoothing * device = nullptr; type = "linear"; // TODO currently hardcoded type, delete it if we have more types @@ -390,12 +391,15 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile) , _qjsonConfig(qjsonConfig) , _configFile(configFile) , _timer() + , _timerBonjourResolver() , _log(CORE_LOGGER) , _hwLedCount(_ledString.leds().size()) , _sourceAutoSelectEnabled(true) , _configHash() , _ledGridSize(getLedLayoutGridSize(qjsonConfig["leds"])) , _prevCompId(hyperion::COMP_INVALID) + , _bonjourBrowser(this) + , _bonjourResolver(this) { registerPriority("Off", PriorityMuxer::LOWEST_PRIORITY); @@ -405,6 +409,10 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile) } // set color correction activity state const QJsonObject& color = qjsonConfig["color"].toObject(); + + _bonjourBrowser.browseForServiceType(QLatin1String("_hyperiond-http._tcp")); + connect(&_bonjourBrowser, SIGNAL(currentBonjourRecordsChanged(const QList&)),this, SLOT(currentBonjourRecordsChanged(const QList &))); + connect(&_bonjourResolver, SIGNAL(bonjourRecordResolved(const QHostInfo &, int)), this, SLOT(bonjourRecordResolved(const QHostInfo &, int))); // initialize the image processor factory _ledMAppingType = ImageProcessor::mappingTypeToInt(color["imageToLedMappingType"].toString()); @@ -416,11 +424,17 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile) _device = LedDeviceFactory::construct(qjsonConfig["device"].toObject(),_hwLedCount); _deviceSmooth = createColorSmoothing(qjsonConfig["smoothing"].toObject(), _device); getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState()); + getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState()); // setup the timer _timer.setSingleShot(true); QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update())); + _timerBonjourResolver.setSingleShot(false); + _timerBonjourResolver.setInterval(1000); + QObject::connect(&_timerBonjourResolver, SIGNAL(timeout()), this, SLOT(bonjourResolve())); + _timerBonjourResolver.start(); + // create the effect engine _effectEngine = new EffectEngine(this,qjsonConfig["effects"].toObject()); @@ -470,6 +484,48 @@ unsigned Hyperion::getLedCount() const return _ledString.leds().size(); } +void Hyperion::currentBonjourRecordsChanged(const QList &list) +{ + _hyperionSessions.clear(); + for ( auto rec : list ) + { + _hyperionSessions.insert(rec.serviceName, rec); + } +} + +void Hyperion::bonjourRecordResolved(const QHostInfo &hostInfo, int port) +{ + if ( _hyperionSessions.contains(_bonjourCurrentServiceToResolve)) + { + QString host = hostInfo.hostName(); + QString domain = _hyperionSessions[_bonjourCurrentServiceToResolve].replyDomain; + if (host.endsWith("."+domain)) + { + host.remove(host.length()-domain.length()-1,domain.length()+1); + } + _hyperionSessions[_bonjourCurrentServiceToResolve].hostName = host; + _hyperionSessions[_bonjourCurrentServiceToResolve].port = port; + Debug(_log, "found hyperion session: %s:%d",QSTRING_CSTR(hostInfo.hostName()), port); + } +} + +void Hyperion::bonjourResolve() +{ + for(auto key : _hyperionSessions.keys()) + { + if (_hyperionSessions[key].port < 0) + { + _bonjourCurrentServiceToResolve = key; + _bonjourResolver.resolveBonjourRecord(_hyperionSessions[key]); + break; + } + } +} + +Hyperion::BonjourRegister Hyperion::getHyperionSessions() +{ + return _hyperionSessions; +} bool Hyperion::configModified() { @@ -507,19 +563,19 @@ void Hyperion::registerPriority(const QString &name, const int priority/*, const { Info(_log, "Register new input source named '%s' for priority channel '%d'", QSTRING_CSTR(name), priority ); - for(auto const &entry : _priorityRegister) + for(auto key : _priorityRegister.keys()) { - WarningIf( ( entry.first != name && entry.second == priority), _log, - "Input source '%s' uses same priority channel (%d) as '%s'.", QSTRING_CSTR(name), priority, QSTRING_CSTR(entry.first)); + WarningIf( ( key != name && _priorityRegister.value(key) == priority), _log, + "Input source '%s' uses same priority channel (%d) as '%s'.", QSTRING_CSTR(name), priority, QSTRING_CSTR(key)); } - _priorityRegister.emplace(name,priority); + _priorityRegister.insert(name, priority); } void Hyperion::unRegisterPriority(const QString &name) { Info(_log, "Unregister input source named '%s' from priority register", QSTRING_CSTR(name)); - _priorityRegister.erase(name); + _priorityRegister.remove(name); } void Hyperion::setSourceAutoSelectEnabled(bool enabled) @@ -550,14 +606,20 @@ bool Hyperion::setCurrentSourcePriority(int priority ) void Hyperion::setComponentState(const hyperion::Components component, const bool state) { - if (component == hyperion::COMP_SMOOTHING) + switch (component) { - _deviceSmooth->setEnable(state); - getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState()); - } - else - { - emit componentStateChanged(component, state); + case hyperion::COMP_SMOOTHING: + _deviceSmooth->setEnable(state); + getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, _deviceSmooth->componentState()); + break; + + case hyperion::COMP_LEDDEVICE: + _device->setEnable(state); + getComponentRegister().componentStateChanged(hyperion::COMP_LEDDEVICE, _device->componentState()); + break; + + default: + emit componentStateChanged(component, state); } } @@ -785,10 +847,13 @@ void Hyperion::update() } // Write the data to the device - if (_deviceSmooth->enabled()) - _deviceSmooth->setLedValues(_ledBuffer); - else - _device->setLedValues(_ledBuffer); + if (_device->enabled()) + { + if (_deviceSmooth->enabled()) + _deviceSmooth->setLedValues(_ledBuffer); + else + _device->setLedValues(_ledBuffer); + } // Start the timeout-timer if (priorityInfo.timeoutTime_ms == -1) @@ -800,4 +865,5 @@ void Hyperion::update() int timeout_ms = std::max(0, int(priorityInfo.timeoutTime_ms - QDateTime::currentMSecsSinceEpoch())); _timer.start(timeout_ms); } + } diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp index 2aae81f6..8fae26a6 100644 --- a/libsrc/hyperion/LinearColorSmoothing.cpp +++ b/libsrc/hyperion/LinearColorSmoothing.cpp @@ -17,7 +17,6 @@ LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpd , _outputDelay(updateDelay) , _writeToLedsEnable(true) , _continuousOutput(continuousOutput) - , _enabled(true) { _log = Logger::getInstance("Smoothing"); _timer.setSingleShot(false); @@ -143,7 +142,8 @@ void LinearColorSmoothing::queueColors(const std::vector & ledColors) void LinearColorSmoothing::setEnable(bool enable) { - _enabled = enable; + LedDevice::setEnable(enable); + if (!enable) { _timer.stop(); @@ -151,8 +151,3 @@ void LinearColorSmoothing::setEnable(bool enable) } } - -bool LinearColorSmoothing::enabled() -{ - return _enabled; -} diff --git a/libsrc/hyperion/LinearColorSmoothing.h b/libsrc/hyperion/LinearColorSmoothing.h index d321cb01..d50e2fc7 100644 --- a/libsrc/hyperion/LinearColorSmoothing.h +++ b/libsrc/hyperion/LinearColorSmoothing.h @@ -41,9 +41,6 @@ public: virtual int switchOff(); void setEnable(bool enable); - bool enabled(); - - bool componentState() { return enabled(); }; private slots: /// Timer callback which writes updated led values to the led device @@ -91,6 +88,4 @@ private: /// Flag for dis/enable continuous output to led device regardless there is new data or not bool _continuousOutput; - - bool _enabled; }; diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp index 7aef7ae9..1aaf8b3c 100644 --- a/libsrc/hyperion/PriorityMuxer.cpp +++ b/libsrc/hyperion/PriorityMuxer.cpp @@ -11,10 +11,12 @@ PriorityMuxer::PriorityMuxer(int ledCount) , _activeInputs() , _lowestPriorityInfo() { - _lowestPriorityInfo.priority = LOWEST_PRIORITY; + _lowestPriorityInfo.priority = LOWEST_PRIORITY; _lowestPriorityInfo.timeoutTime_ms = -1; - _lowestPriorityInfo.ledColors = std::vector(ledCount, {0, 0, 0}); - + _lowestPriorityInfo.ledColors = std::vector(ledCount, {0, 0, 0}); + _lowestPriorityInfo.componentId = hyperion::COMP_COLOR; + _lowestPriorityInfo.origin = "System"; + _activeInputs[_currentPriority] = _lowestPriorityInfo; } diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index a7cba33d..3ce54531 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -48,6 +48,8 @@ using namespace hyperion; +int _connectionCounter = 0; + JsonClientConnection::JsonClientConnection(QTcpSocket *socket) : QObject() , _socket(socket) @@ -577,6 +579,7 @@ void JsonClientConnection::handleSysInfoCommand(const QJsonObject&, const QStrin system["productVersion"] = data.productVersion; system["prettyName" ] = data.prettyName; system["hostName" ] = data.hostName; + system["domainName" ] = data.domainName; info["system"] = system; QJsonObject hyperion; @@ -619,22 +622,21 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt } item["owner"] = QString(hyperion::componentToIdString(priorityInfo.componentId)); - item["componentId"] = priorityInfo.componentId; + item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId)); item["origin"] = priorityInfo.origin; item["component"] = QString(hyperion::componentToString(priorityInfo.componentId)); item["active"] = true; item["visible"] = (priority == currentPriority); - foreach(auto const &entry, priorityRegister) + + // remove item from prio register, because we have more valuable information via active priority + QList prios = priorityRegister.keys(priority); + if (! prios.empty()) { - if (entry.second == priority) - { - item["owner"] = entry.first; - priorityRegister.erase(entry.first); - break; - } + item["owner"] = prios[0]; + priorityRegister.remove(prios[0]); } - if(priorityInfo.componentId == 9) + if(priorityInfo.componentId == hyperion::COMP_COLOR) { QJsonObject LEDcolor; @@ -679,14 +681,15 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt // priorities[priorities.size()] = item; priorities.append(item); } - - foreach(auto const &entry, priorityRegister) + + // append left over priorities + for(auto key : priorityRegister.keys()) { QJsonObject item; - item["priority"] = entry.second; + item["priority"] = priorityRegister[key]; item["active"] = false; item["visible"] = false; - item["owner"] = entry.first; + item["owner"] = key; priorities.append(item); } @@ -827,6 +830,22 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt QJsonObject hyperion; hyperion["config_modified" ] = _hyperion->configModified(); hyperion["config_writeable"] = _hyperion->configWriteable(); + + // sessions + QJsonArray sessions; + for (auto session: _hyperion->getHyperionSessions()) + { + if (session.port<0) continue; + QJsonObject item; + item["name"] = session.serviceName; + item["type"] = session.registeredType; + item["domain"] = session.replyDomain; + item["host"] = session.hostName; + item["port"] = session.port; + sessions.append(item); + } + hyperion["sessions"] = sessions; + info["hyperion"] = hyperion; // send the result diff --git a/libsrc/jsonserver/schema/schema-componentstate.json b/libsrc/jsonserver/schema/schema-componentstate.json index 28a8a362..0e8db05f 100644 --- a/libsrc/jsonserver/schema/schema-componentstate.json +++ b/libsrc/jsonserver/schema/schema-componentstate.json @@ -21,7 +21,7 @@ "component": { "type" : "string", - "enum" : ["SMOOTHING", "BLACKBORDER", "KODICHECKER", "FORWARDER", "UDPLISTENER", "BOBLIGHTSERVER", "GRABBER", "V4L"], + "enum" : ["SMOOTHING", "BLACKBORDER", "KODICHECKER", "FORWARDER", "UDPLISTENER", "BOBLIGHTSERVER", "GRABBER", "V4L", "LEDDEVICE"], "required": true }, "state": diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp index 54d825ff..db2228e1 100644 --- a/libsrc/leddevice/LedDevice.cpp +++ b/libsrc/leddevice/LedDevice.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "hyperion/Hyperion.h" LedDeviceRegistry LedDevice::_ledDeviceMap = LedDeviceRegistry(); QString LedDevice::_activeDevice = ""; @@ -19,8 +20,11 @@ LedDevice::LedDevice() , _deviceReady(true) , _refresh_timer() , _refresh_timer_interval(0) + , _componentRegistered(false) + , _enabled(true) { LedDevice::getLedDeviceSchemas(); + qRegisterMetaType("hyperion::Components"); // setup timer _refresh_timer.setSingleShot(false); @@ -34,6 +38,16 @@ int LedDevice::open() return 0; } +void LedDevice::setEnable(bool enable) +{ + if ( _enabled && !enable) + { + switchOff(); + } + _enabled = enable; + +} + int LedDevice::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr) { _ledDeviceMap.emplace(name,funcPtr); @@ -111,12 +125,11 @@ QJsonObject LedDevice::getLedDeviceSchemas() return result; } - int LedDevice::setLedValues(const std::vector& ledValues) { - if (!_deviceReady) + if (!_deviceReady || !_enabled) return -1; - + _ledValues = ledValues; // restart the timer @@ -142,5 +155,5 @@ void LedDevice::setLedCount(int ledCount) int LedDevice::rewriteLeds() { - return write(_ledValues); + return _enabled ? write(_ledValues) : -1; } diff --git a/libsrc/utils/SysInfo.cpp b/libsrc/utils/SysInfo.cpp index 92762ec6..dcdcb3ec 100644 --- a/libsrc/utils/SysInfo.cpp +++ b/libsrc/utils/SysInfo.cpp @@ -29,6 +29,7 @@ SysInfo::SysInfo() _sysinfo.productVersion = v.productVersion; _sysinfo.prettyName = v.prettyName; _sysinfo.hostName = QHostInfo::localHostName(); + _sysinfo.domainName = QHostInfo::localDomainName(); } SysInfo::~SysInfo() diff --git a/src/hyperion-remote/hyperion-remote.cpp b/src/hyperion-remote/hyperion-remote.cpp index 8966d946..a34c1baf 100644 --- a/src/hyperion-remote/hyperion-remote.cpp +++ b/src/hyperion-remote/hyperion-remote.cpp @@ -3,6 +3,7 @@ #include #include #include +#include // Qt includes #include @@ -40,6 +41,8 @@ void showHelp(Option & option){ int main(int argc, char * argv[]) { + setenv("AVAHI_COMPAT_NOWARN", "1", 1); + std::cout << "hyperion-remote:" << std::endl << "\tVersion : " << HYPERION_VERSION << " (" << HYPERION_BUILD_ID << ")" << std::endl @@ -70,8 +73,8 @@ int main(int argc, char * argv[]) BooleanOption & argSysInfo = parser.add('s', "sysinfo" , "show system info"); BooleanOption & argClear = parser.add('x', "clear" , "Clear data for the priority channel provided by the -p option"); BooleanOption & argClearAll = parser.add(0x0, "clearall" , "Clear data for all active priority channels"); - Option & argEnableComponent = parser.add