#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Required to determine the cmake options #include "hyperiond.h" // FlatBufferServer #include // bonjour browser #include // ssdp #include // settings #include // Init Python #include // EffectFileHandler #include HyperionDaemon* HyperionDaemon::daemon = nullptr; HyperionDaemon::HyperionDaemon(QString configFile, const QString rootPath, QObject *parent, const bool& logLvlOverwrite) : QObject(parent) , _log(Logger::getInstance("DAEMON")) , _bonjourBrowserWrapper(new BonjourBrowserWrapper()) , _pyInit(new PythonInit()) , _webserver(nullptr) , _jsonServer(nullptr) , _udpListener(nullptr) , _v4l2Grabbers() , _dispmanx(nullptr) , _x11Grabber(nullptr) , _amlGrabber(nullptr) , _fbGrabber(nullptr) , _osxGrabber(nullptr) , _qtGrabber(nullptr) , _hyperion(nullptr) , _stats(nullptr) , _ssdp(nullptr) , _currVideoMode(VIDEO_2D) { HyperionDaemon::daemon = this; // Register metas for thread queued connection qRegisterMetaType>("Image"); qRegisterMetaType("hyperion::Components"); qRegisterMetaType("settings::type"); qRegisterMetaType("VideoMode"); qRegisterMetaType>("QMap"); // init settings _settingsManager = new SettingsManager(0,configFile); // set inital log lvl if the loglvl wasn't overwritten by arg if(!logLvlOverwrite) handleSettingsUpdate(settings::LOGGER, _settingsManager->getSetting(settings::LOGGER)); // init EffectFileHandler EffectFileHandler* efh = new EffectFileHandler(rootPath, _settingsManager->getSetting(settings::EFFECTS), this); connect(this, &HyperionDaemon::settingsChanged, efh, &EffectFileHandler::handleSettingsUpdate); // spawn all Hyperion instances before network services _hyperion = Hyperion::initInstance(this, 0, configFile, rootPath); Info(_log, "Hyperion initialized"); //connect(_hyperion,SIGNAL(closing()),this,SLOT(freeObjects())); for app restart refactor required // listen for setting changes connect(_hyperion, &Hyperion::settingsChanged, this, &HyperionDaemon::settingsChanged); // listen for setting changes of framegrabber and v4l2 connect(this, &HyperionDaemon::settingsChanged, this, &HyperionDaemon::handleSettingsUpdate); // forward videoModes from Hyperion to Daemon evaluation connect(_hyperion, &Hyperion::videoMode, this, &HyperionDaemon::setVideoMode); // forward videoMode changes from Daemon to Hyperion connect(this, &HyperionDaemon::videoMode, _hyperion, &Hyperion::newVideoMode); // ---- grabber ----- #if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_AMLOGIC) Warning(_log, "No platform capture can be instantiated, because all grabbers have been left out from the build"); #endif // init system capture (framegrabber) handleSettingsUpdate(settings::SYSTEMCAPTURE, getSetting(settings::SYSTEMCAPTURE)); // init v4l2 capture handleSettingsUpdate(settings::V4L2, getSetting(settings::V4L2)); // ---- network services ----- startNetworkServices(); } HyperionDaemon::~HyperionDaemon() { freeObjects(); delete _hyperion; delete _settingsManager; delete _pyInit; } void HyperionDaemon::setVideoMode(const VideoMode& mode) { if(_currVideoMode != mode) { _currVideoMode = mode; emit videoMode(mode); } } const QJsonDocument HyperionDaemon::getSetting(const settings::type &type) { return _settingsManager->getSetting(type); } void HyperionDaemon::freeObjects() { _hyperion->clearall(true); // destroy network first as a client might want to access hyperion delete _jsonServer; _flatBufferServer->thread()->quit(); _flatBufferServer->thread()->wait(1000); //ssdp before webserver _ssdp->thread()->quit(); _ssdp->thread()->wait(1000); _webserver->thread()->quit(); _webserver->thread()->wait(1000); delete _udpListener; delete _bonjourBrowserWrapper; delete _amlGrabber; delete _dispmanx; delete _fbGrabber; delete _osxGrabber; delete _qtGrabber; for(V4L2Wrapper* grabber : _v4l2Grabbers) { delete grabber; } delete _stats; _v4l2Grabbers.clear(); _bonjourBrowserWrapper = nullptr; _amlGrabber = nullptr; _dispmanx = nullptr; _fbGrabber = nullptr; _osxGrabber = nullptr; _qtGrabber = nullptr; _webserver = nullptr; _jsonServer = nullptr; _udpListener = nullptr; _stats = nullptr; } void HyperionDaemon::startNetworkServices() { // Create Stats _stats = new Stats(_settingsManager->getSettings()); // Create Json server _jsonServer = new JsonServer(getSetting(settings::JSONSERVER)); connect(this, &HyperionDaemon::settingsChanged, _jsonServer, &JsonServer::handleSettingsUpdate); // Create FlatBuffer server in thread _flatBufferServer = new FlatBufferServer(getSetting(settings::FLATBUFSERVER)); QThread* fbThread = new QThread(this); _flatBufferServer->moveToThread(fbThread); connect( fbThread, &QThread::started, _flatBufferServer, &FlatBufferServer::initServer ); connect( fbThread, &QThread::finished, _flatBufferServer, &QObject::deleteLater ); connect( fbThread, &QThread::finished, fbThread, &QObject::deleteLater ); connect(this, &HyperionDaemon::settingsChanged, _flatBufferServer, &FlatBufferServer::handleSettingsUpdate); fbThread->start(); // Create UDP listener _udpListener = new UDPListener(getSetting(settings::UDPLISTENER)); connect(this, &HyperionDaemon::settingsChanged, _udpListener, &UDPListener::handleSettingsUpdate); // Create Webserver in thread _webserver = new WebServer(getSetting(settings::WEBSERVER)); QThread* wsThread = new QThread(this); _webserver->moveToThread(wsThread); connect( wsThread, &QThread::started, _webserver, &WebServer::initServer ); connect( wsThread, &QThread::finished, _webserver, &QObject::deleteLater ); connect( wsThread, &QThread::finished, wsThread, &QObject::deleteLater ); connect(this, &HyperionDaemon::settingsChanged, _webserver, &WebServer::handleSettingsUpdate); wsThread->start(); // create ssdp server in thread _ssdp = new SSDPHandler(_webserver, getSetting(settings::FLATBUFSERVER).object()["port"].toInt()); QThread* ssdpThread = new QThread(this); _ssdp->moveToThread(ssdpThread); connect( ssdpThread, &QThread::started, _ssdp, &SSDPHandler::initServer ); connect( ssdpThread, &QThread::finished, _ssdp, &QObject::deleteLater ); connect( ssdpThread, &QThread::finished, ssdpThread, &QObject::deleteLater ); connect( _webserver, &WebServer::stateChange, _ssdp, &SSDPHandler::handleWebServerStateChange); connect(this, &HyperionDaemon::settingsChanged, _ssdp, &SSDPHandler::handleSettingsUpdate); ssdpThread->start(); } void HyperionDaemon::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config) { if(type == settings::LOGGER) { const QJsonObject & logConfig = config.object(); std::string level = logConfig["level"].toString("warn").toStdString(); // silent warn verbose debug if (level == "silent") Logger::setLogLevel(Logger::OFF); else if (level == "warn") Logger::setLogLevel(Logger::WARNING); else if (level == "verbose") Logger::setLogLevel(Logger::INFO); else if (level == "debug") Logger::setLogLevel(Logger::DEBUG); } if(type == settings::SYSTEMCAPTURE) { const QJsonObject & grabberConfig = config.object(); _grabber_width = grabberConfig["width"].toInt(96); _grabber_height = grabberConfig["height"].toInt(96); _grabber_frequency = grabberConfig["frequency_Hz"].toInt(10); _grabber_cropLeft = grabberConfig["cropLeft"].toInt(0); _grabber_cropRight = grabberConfig["cropRight"].toInt(0); _grabber_cropTop = grabberConfig["cropTop"].toInt(0); _grabber_cropBottom = grabberConfig["cropBottom"].toInt(0); #ifdef ENABLE_OSX QString type = "osx"; #else QString type = grabberConfig["type"].toString("auto"); #endif // auto eval of type if ( type == "auto" ) { // dispmanx -> on raspi if (QFile::exists("/dev/vchiq")) { type = "dispmanx"; } // amlogic -> /dev/amvideo exists else if ( QFile::exists("/dev/amvideo") && ( QFile::exists("/dev/amvideocap0") || QFile::exists("/dev/ge2d") ) ) { type = "amlogic"; } // x11 -> if DISPLAY is set else if (getenv("DISPLAY") != NULL ) { type = "x11"; } // qt -> if nothing other applies else { type = "qt"; } } if(_prevType != type) { Info( _log, "set screen capture device to '%s'", QSTRING_CSTR(type)); // stop all capture interfaces #ifdef ENABLE_FB if(_fbGrabber != nullptr) _fbGrabber->stop(); #endif #ifdef ENABLE_DISPMANX if(_dispmanx != nullptr) _dispmanx->stop(); #endif #ifdef ENABLE_AMLOGIC if(_amlGrabber != nullptr) _amlGrabber->stop(); #endif #ifdef ENABLE_OSX if(_osxGrabber != nullptr) _osxGrabber->stop(); #endif #ifdef ENABLE_X11 if(_x11Grabber != nullptr) _x11Grabber->stop(); #endif #ifdef ENABLE_QT if(_qtGrabber != nullptr) _qtGrabber->stop(); #endif // create/start capture interface if(type == "framebuffer") { if(_fbGrabber == nullptr) createGrabberFramebuffer(grabberConfig); #ifdef ENABLE_FB _fbGrabber->start(); #endif } else if(type == "dispmanx") { if(_dispmanx == nullptr) createGrabberDispmanx(); #ifdef ENABLE_DISPMANX _dispmanx->start(); #endif } else if(type == "amlogic") { if(_amlGrabber == nullptr) createGrabberAmlogic(); #ifdef ENABLE_AMLOGIC _amlGrabber->start(); #endif } else if(type == "osx") { if(_osxGrabber == nullptr) createGrabberOsx(grabberConfig); #ifdef ENABLE_OSX _osxGrabber->start(); #endif } else if(type == "x11") { if(_x11Grabber == nullptr) createGrabberX11(grabberConfig); #ifdef ENABLE_X11 _x11Grabber->start(); #endif } else if(type == "qt") { if(_qtGrabber == nullptr) createGrabberQt(grabberConfig); #ifdef ENABLE_QT _qtGrabber->start(); #endif } else { Error(_log,"Unknown platform capture type: %s", QSTRING_CSTR(type)); return; } _prevType = type; } } else if(type == settings::V4L2) { // stop if(_v4l2Grabbers.size()>0) return; unsigned v4lEnableCount = 0; const QJsonArray & v4lArray = config.array(); for ( signed idx=0; idxsetSignalThreshold( grabberConfig["redSignalThreshold"].toDouble(0.0)/100.0, grabberConfig["greenSignalThreshold"].toDouble(0.0)/100.0, grabberConfig["blueSignalThreshold"].toDouble(0.0)/100.0); grabber->setCropping( grabberConfig["cropLeft"].toInt(0), grabberConfig["cropRight"].toInt(0), grabberConfig["cropTop"].toInt(0), grabberConfig["cropBottom"].toInt(0)); grabber->setSignalDetectionEnable(grabberConfig["signalDetection"].toBool(true)); grabber->setSignalDetectionOffset( grabberConfig["sDHOffsetMin"].toDouble(0.25), grabberConfig["sDVOffsetMin"].toDouble(0.25), grabberConfig["sDHOffsetMax"].toDouble(0.75), grabberConfig["sDVOffsetMax"].toDouble(0.75)); Debug(_log, "V4L2 grabber created"); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, grabber, &V4L2Wrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, grabber, &V4L2Wrapper::handleSettingsUpdate); _v4l2Grabbers.push_back(grabber); #endif } ErrorIf( (v4lEnableCount>0 && _v4l2Grabbers.size()==0), _log, "The v4l2 grabber can not be instantiated, because it has been left out from the build"); } } void HyperionDaemon::createGrabberDispmanx() { #ifdef ENABLE_DISPMANX _dispmanx = new DispmanxWrapper(_grabber_width, _grabber_height, _grabber_frequency); _dispmanx->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _dispmanx, &DispmanxWrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _dispmanx, &DispmanxWrapper::handleSettingsUpdate); Info(_log, "DISPMANX frame grabber created"); #else Error( _log, "The dispmanx framegrabber can not be instantiated, because it has been left out from the build"); #endif } void HyperionDaemon::createGrabberAmlogic() { #ifdef ENABLE_AMLOGIC _amlGrabber = new AmlogicWrapper(_grabber_width, _grabber_height, _grabber_frequency); _amlGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _amlGrabber, &AmlogicWrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _amlGrabber, &AmlogicWrapper::handleSettingsUpdate); Info(_log, "AMLOGIC grabber created"); #else Error( _log, "The AMLOGIC grabber can not be instantiated, because it has been left out from the build"); #endif } void HyperionDaemon::createGrabberX11(const QJsonObject & grabberConfig) { #ifdef ENABLE_X11 _x11Grabber = new X11Wrapper( _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, grabberConfig["pixelDecimation"].toInt(8), _grabber_frequency ); _x11Grabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _x11Grabber, &X11Wrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _x11Grabber, &X11Wrapper::handleSettingsUpdate); Info(_log, "X11 grabber created"); #else Error(_log, "The X11 grabber can not be instantiated, because it has been left out from the build"); #endif } void HyperionDaemon::createGrabberQt(const QJsonObject & grabberConfig) { #ifdef ENABLE_QT _qtGrabber = new QtWrapper( _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, grabberConfig["pixelDecimation"].toInt(8), grabberConfig["display"].toInt(0), _grabber_frequency ); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _qtGrabber, &QtWrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _qtGrabber, &QtWrapper::handleSettingsUpdate); Info(_log, "Qt grabber created"); #else Error(_log, "The Qt grabber can not be instantiated, because it has been left out from the build"); #endif } void HyperionDaemon::createGrabberFramebuffer(const QJsonObject & grabberConfig) { #ifdef ENABLE_FB // Construct and start the framebuffer grabber if the configuration is present _fbGrabber = new FramebufferWrapper( grabberConfig["device"].toString("/dev/fb0"), _grabber_width, _grabber_height, _grabber_frequency); _fbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _fbGrabber, &FramebufferWrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _fbGrabber, &FramebufferWrapper::handleSettingsUpdate); Info(_log, "Framebuffer grabber created"); #else Error(_log, "The framebuffer grabber can not be instantiated, because it has been left out from the build"); #endif } void HyperionDaemon::createGrabberOsx(const QJsonObject & grabberConfig) { #ifdef ENABLE_OSX // Construct and start the osx grabber if the configuration is present _osxGrabber = new OsxWrapper( grabberConfig["display"].toInt(0), _grabber_width, _grabber_height, _grabber_frequency); // connect to HyperionDaemon signal connect(this, &HyperionDaemon::videoMode, _osxGrabber, &OsxWrapper::setVideoMode); connect(this, &HyperionDaemon::settingsChanged, _osxGrabber, &OsxWrapper::handleSettingsUpdate); Info(_log, "OSX grabber created"); #else Error(_log, "The osx grabber can not be instantiated, because it has been left out from the build"); #endif }