Refactor event handling incl.CEC

This commit is contained in:
LordGrey 2023-11-06 21:40:12 +01:00
parent b1c8534cb7
commit 0d9a8b8a3a
39 changed files with 1306 additions and 1158 deletions

View File

@ -192,8 +192,8 @@
"conf_network_tok_intro": "Here you can create and delete tokens for API authentication. Created tokens will only be displayed once.", "conf_network_tok_intro": "Here you can create and delete tokens for API authentication. Created tokens will only be displayed once.",
"conf_network_tok_lastuse": "Last use", "conf_network_tok_lastuse": "Last use",
"conf_network_tok_title": "Token Management", "conf_network_tok_title": "Token Management",
"conf_system_events_heading_title": "System Events", "conf_os_events_heading_title": "Operating System Events",
"conf_system_events_intro": "Settings related to diffent Operating System events Hyperion can handle", "conf_os_events_intro": "Settings related to diffent Operating System events Hyperion can handle",
"conf_webconfig_label_intro": "Webconfiguration settings. Edit wisely.", "conf_webconfig_label_intro": "Webconfiguration settings. Edit wisely.",
"dashboard_active_instance": "Selected instance", "dashboard_active_instance": "Selected instance",
"dashboard_alert_message_confedit": "Your Hyperion configuration has been modified. To apply it, restart Hyperion.", "dashboard_alert_message_confedit": "Your Hyperion configuration has been modified. To apply it, restart Hyperion.",
@ -457,6 +457,12 @@
"edt_conf_net_localApiAuth_title": "Local API Authentication", "edt_conf_net_localApiAuth_title": "Local API Authentication",
"edt_conf_net_restirctedInternetAccessAPI_expl": "You can restrict the access to the API through the internet to certain IP's.", "edt_conf_net_restirctedInternetAccessAPI_expl": "You can restrict the access to the API through the internet to certain IP's.",
"edt_conf_net_restirctedInternetAccessAPI_title": "Restrict to IP's", "edt_conf_net_restirctedInternetAccessAPI_title": "Restrict to IP's",
"edt_conf_os_events_lockEnable_title": "Listen to lock events",
"edt_conf_os_events_lockEnable_expl": "Listen to screen lock/unlock events",
"edt_conf_os_events_suspendEnable_title": "Listen to suspend events",
"edt_conf_os_events_suspendEnable_expl": "Listen to operating system suspend/resume events",
"edt_conf_os_events_suspendOnLockEnable_title": "Suspend when locked",
"edt_conf_os_events_suspendOnLockEnable_expl": "Suspend when the screen is locked, otherwise go into idle mode",
"edt_conf_pbs_heading_title": "Protocol Buffers Server", "edt_conf_pbs_heading_title": "Protocol Buffers Server",
"edt_conf_pbs_timeout_expl": "If no data are received for the given period, the component will be (soft) disabled.", "edt_conf_pbs_timeout_expl": "If no data are received for the given period, the component will be (soft) disabled.",
"edt_conf_pbs_timeout_title": "Timeout", "edt_conf_pbs_timeout_title": "Timeout",
@ -477,12 +483,6 @@
"edt_conf_smooth_updateDelay_title": "Output delay", "edt_conf_smooth_updateDelay_title": "Output delay",
"edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.", "edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.",
"edt_conf_smooth_updateFrequency_title": "Update frequency", "edt_conf_smooth_updateFrequency_title": "Update frequency",
"edt_conf_system_events_lockEnable_title": "Listen to lock events",
"edt_conf_system_events_lockEnable_expl": "Listen to screen lock/unlock events",
"edt_conf_system_events_suspendEnable_title": "Listen to suspend events",
"edt_conf_system_events_suspendEnable_expl": "Listen to system suspend/resume events",
"edt_conf_system_events_suspendOnLockEnable_title": "Suspend when locked",
"edt_conf_system_events_suspendOnLockEnable_expl": "Suspend when the screen is locked, otherwise go into idle mode",
"edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)", "edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)",
"edt_conf_v4l2_blueSignalThreshold_title": "Blue signal threshold", "edt_conf_v4l2_blueSignalThreshold_title": "Blue signal threshold",
"edt_conf_v4l2_cecDetection_expl": "If enabled, USB capture will be temporarily disabled when CEC standby event received from HDMI bus.", "edt_conf_v4l2_cecDetection_expl": "If enabled, USB capture will be temporarily disabled when CEC standby event received from HDMI bus.",

View File

@ -1,35 +1,75 @@
$(document).ready(function () { $(document).ready(function () {
performTranslation(); performTranslation();
var conf_editor_systemEvents = null; var CEC_ENABLED = (jQuery.inArray("cec", window.serverInfo.services) !== -1);
var conf_editor_osEvents = null;
var conf_editor_cecEvents = null;
if (window.showOptHelp) { if (window.showOptHelp) {
//System Events //Operating System Events
$('#conf_cont').append(createRow('conf_cont_system_events')); $('#conf_cont').append(createRow('conf_cont_os_events'));
$('#conf_cont_system_events').append(createOptPanel('fa-laptop', $.i18n("conf_system_events_heading_title"), 'editor_container_system_events', 'btn_submit_system_events', 'panel-system')); $('#conf_cont_os_events').append(createOptPanel('fa-laptop', $.i18n("conf_os_events_heading_title"), 'editor_container_os_events', 'btn_submit_os_events', 'panel-system'));
$('#conf_cont_system_events').append(createHelpTable(window.schema.systemEvents.properties, $.i18n("conf_system_events_heading_title"))); $('#conf_cont_os_events').append(createHelpTable(window.schema.osEvents.properties, $.i18n("conf_os_events_heading_title")));
//CEC Events
if (CEC_ENABLED) {
$('#conf_cont').append(createRow('conf_cont_event_cec'));
$('#conf_cont_event_cec').append(createOptPanel('fa-tv', $.i18n("conf_cec_events_heading_title"), 'editor_container_cec_events', 'btn_submit_cec_events', 'panel-system'));
$('#conf_cont_event_cec').append(createHelpTable(window.schema.cecEvents.properties, $.i18n("conf_cec_events_heading_title"), "cecEventsHelpPanelId"));
}
} }
else { else {
$('#conf_cont').addClass('row'); $('#conf_cont').addClass('row');
$('#conf_cont').append(createOptPanel('fa-laptop', $.i18n("conf_system_events_heading_title"), 'editor_container_system_events', 'btn_submit_system_events')); $('#conf_cont').append(createOptPanel('fa-laptop', $.i18n("conf_os_events_heading_title"), 'editor_container_os_events', 'btn_submit_os_events'));
if (CEC_ENABLED) {
$('#conf_cont').append(createOptPanel('fa-tv', $.i18n("conf_cec_events_heading_title"), 'editor_container_cec_events', 'btn_submit_cec_events'));
}
} }
//System Events //Operating System Events
conf_editor_systemEvents = createJsonEditor('editor_container_system_events', { conf_editor_osEvents = createJsonEditor('editor_container_os_events', {
systemEvents: window.schema.systemEvents osEvents: window.schema.osEvents
}, true, true); }, true, true);
conf_editor_systemEvents.on('change', function () { conf_editor_osEvents.on('change', function () {
conf_editor_systemEvents.validate().length || window.readOnlyMode ? $('#btn_submit_system_events').prop('disabled', true) : $('#btn_submit_system_events').prop('disabled', false); conf_editor_osEvents.validate().length || window.readOnlyMode ? $('#btn_submit_os_events').prop('disabled', true) : $('#btn_submit_os_events').prop('disabled', false);
}); });
$('#btn_submit_system_events').off().on('click', function () { $('#btn_submit_os_events').off().on('click', function () {
requestWriteConfig(conf_editor_systemEvents.getValue()); requestWriteConfig(conf_editor_osEvents.getValue());
}); });
//CEC Events
if (CEC_ENABLED) {
conf_editor_cecEvents = createJsonEditor('editor_container_cec_events', {
cecEvents: window.schema.cecEvents
}, true, true);
conf_editor_cecEvents.on('change', function () {
var cecEventsEnable = conf_editor_cecEvents.getEditor("root.cecEvents.enable").getValue();
if (cecEventsEnable) {
showInputOptionsForKey(conf_editor_cecEvents, "cecEvents", "enable", true);
$('#cecEventsHelpPanelId').show();
} else {
showInputOptionsForKey(conf_editor_cecEvents, "cecEvents", "enable", false);
$('#cecEventsHelpPanelId').hide();
}
conf_editor_cecEvents.validate().length || window.readOnlyMode ? $('#btn_submit_cec_events').prop('disabled', true) : $('#btn_submit_cec_events').prop('disabled', false);
});
$('#btn_submit_cec_events').off().on('click', function () {
requestWriteConfig(conf_editor_cecEvents.getValue());
});
}
//create introduction //create introduction
if (window.showOptHelp) { if (window.showOptHelp) {
createHint("intro", $.i18n('conf_system_events_intro'), "editor_container_system_events"); createHint("intro", $.i18n('conf_os_events_intro'), "editor_container_os_events");
if (CEC_ENABLED) {
createHint("intro", $.i18n('conf_cec_events_intro'), "editor_container_cec_events");
}
} }
removeOverlay(); removeOverlay();

View File

@ -231,26 +231,34 @@ macro(DeployLinux TARGET)
if (EXISTS ${QT_PLUGINS_DIR}/${PLUGIN}) if (EXISTS ${QT_PLUGINS_DIR}/${PLUGIN})
file(GLOB files "${QT_PLUGINS_DIR}/${PLUGIN}/*.so") file(GLOB files "${QT_PLUGINS_DIR}/${PLUGIN}/*.so")
foreach(file ${files}) foreach(file ${files})
get_prerequisites(${file} PLUGINS 0 1 "" "") if ("${file}" STREQUAL "libqsqlmimer.so")
foreach(DEPENDENCY ${PLUGINS}) continue()
get_filename_component(resolved ${DEPENDENCY} NAME_WE) else()
list(FIND SYSTEM_LIBS_SKIP ${resolved} _index) get_prerequisites(${file} PLUGINS 0 1 "" "")
if (${_index} GREATER -1) foreach(DEPENDENCY ${PLUGINS})
continue() # Skip system libraries get_filename_component(resolved ${DEPENDENCY} NAME_WE)
else() list(FIND SYSTEM_LIBS_SKIP ${resolved} _index)
gp_resolve_item("${file}" "${DEPENDENCY}" "" "" resolved_file) if (${_index} GREATER -1)
get_filename_component(resolved_file ${resolved_file} ABSOLUTE) continue() # Skip system libraries
gp_append_unique(PREREQUISITE_LIBS ${resolved_file}) else()
get_filename_component(file_canonical ${resolved_file} REALPATH) gp_resolve_item("${file}" "${DEPENDENCY}" "" "" resolved_file)
gp_append_unique(PREREQUISITE_LIBS ${file_canonical}) get_filename_component(resolved_file ${resolved_file} ABSOLUTE)
endif() gp_append_unique(PREREQUISITE_LIBS ${resolved_file})
endforeach() get_filename_component(file_canonical ${resolved_file} REALPATH)
gp_append_unique(PREREQUISITE_LIBS ${file_canonical})
install( endif()
FILES ${file} endforeach()
DESTINATION "share/hyperion/lib/${PLUGIN}" endif()
COMPONENT "Hyperion" if ("${file}" STREQUAL "libqsqlmimer.so")
) continue()
else()
install(
FILES ${file}
DESTINATION "share/hyperion/lib/${PLUGIN}"
COMPONENT "Hyperion"
)
endif()
endforeach() endforeach()
endif() endif()
endforeach() endforeach()

View File

@ -250,8 +250,12 @@
} }
], ],
"systemEvents": { "osEvents": {
"suspendEnable": true, "suspendEnable": true,
"lockEnable": true "lockEnable": true
} },
"cecEvents": {
"enable": false
}
} }

BIN
help/db/hyperion.db Normal file

Binary file not shown.

View File

@ -2,6 +2,7 @@
// parent class // parent class
#include <api/API.h> #include <api/API.h>
#include <events/Event.h>
// hyperion includes // hyperion includes
#include <utils/Components.h> #include <utils/Components.h>
@ -105,24 +106,9 @@ signals:
void forwardJsonMessage(QJsonObject); void forwardJsonMessage(QJsonObject);
/// ///
/// Signal emits whenever a suspend/resume request for all instances should be forwarded /// Signal emits whenever a hyperion event request for all instances should be forwarded
/// ///
void suspendAll(bool isSuspend); void signalEvent(Event event);
///
/// Signal emits whenever a toggle suspend/resume request for all instances should be forwarded
///
void toggleSuspendAll();
///
/// Signal emits whenever a idle mode request for all instances should be forwarded
///
void idleAll(bool isIdle);
///
/// Signal emits whenever a toggle idle/working mode request for all instances should be forwarded
///
void toggleIdleAll();
private: private:
// true if further callbacks are forbidden (http) // true if further callbacks are forbidden (http)

View File

@ -1,8 +0,0 @@
#pragma once
enum class CECEvent
{
On,
Off
};

View File

@ -7,7 +7,10 @@
#include <libcec/cec.h> #include <libcec/cec.h>
#include <cec/CECEvent.h> #include <utils/settings.h>
//#include <cec/CECEvent.h>
#include <events/Event.h>
using CECCallbacks = CEC::ICECCallbacks; using CECCallbacks = CEC::ICECCallbacks;
using CECAdapter = CEC::ICECAdapter; using CECAdapter = CEC::ICECAdapter;
@ -39,8 +42,12 @@ public slots:
bool start(); bool start();
void stop(); void stop();
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
signals: signals:
void cecEvent(CECEvent event); //void cecEvent(CECEvent event);
void signalEvent(Event event);
private: private:
/* CEC Callbacks */ /* CEC Callbacks */
@ -65,5 +72,7 @@ private:
CECCallbacks _cecCallbacks {}; CECCallbacks _cecCallbacks {};
CECConfig _cecConfig {}; CECConfig _cecConfig {};
bool _isEnabled;
Logger * _logger {}; Logger * _logger {};
}; };

View File

@ -113,7 +113,7 @@ public:
// capture // capture
<< "framegrabber" << "grabberV4L2" << "grabberAudio" << "framegrabber" << "grabberV4L2" << "grabberAudio"
//Events //Events
<< "systemEvents" << "osEvents" << "cecEvents"
// other // other
<< "logger" << "general"; << "logger" << "general";

32
include/events/Event.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef EVENT_H
#define EVENT_H
enum class Event
{
Suspend,
Resume,
ToggleSuspend,
Idle,
ResumeIdle,
ToggleIdle,
Reload,
Restart
};
inline const char* eventToString(Event event)
{
switch (event)
{
case Event::Suspend: return "Suspend";
case Event::Resume: return "Resume";
case Event::ToggleSuspend: return "ToggleSuspend detector";
case Event::Idle: return "Idle";
case Event::ResumeIdle: return "ResumeIdle";
case Event::ToggleIdle: return "ToggleIdle";
case Event::Reload: return "Reload";
case Event::Restart: return "Restart";
default: return "Unknown";
}
}
#endif // EVENT_H

View File

@ -0,0 +1,54 @@
#ifndef EVENTHANDLER_H
#define EVENTHANDLER_H
#include <utils/settings.h>
#include <events/Event.h>
#include <QObject>
class Logger;
class EventHandler : public QObject {
Q_OBJECT
public:
EventHandler();
~EventHandler() override;
static EventHandler* getInstance();
public slots:
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
void suspend(bool sleep);
void suspend();
void resume();
void toggleSuspend();
void idle(bool isIdle);
void idle();
void resumeIdle();
void toggleIdle();
void handleEvent(Event event);
signals:
void signalEvent(Event event);
protected:
Logger * _log {};
private:
bool _isSuspended;
bool _isIdle;
};
#endif // EVENTHANDLER_H

View File

@ -0,0 +1,116 @@
#ifndef OsEventHandler_H
#define OsEventHandler_H
#include <QObject>
#include <QJsonDocument>
#include <events/Event.h>
#if defined(_WIN32)
#include <QAbstractNativeEventFilter>
#include <QAbstractEventDispatcher>
#include <QWidget>
#include <windows.h>
#endif
#include <utils/settings.h>
class Logger;
class OsEventHandlerBase : public QObject {
Q_OBJECT
public:
OsEventHandlerBase();
~OsEventHandlerBase() override;
public slots:
void suspend(bool sleep);
void lock(bool isLocked);
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
signals:
void signalEvent(Event event);
protected:
virtual bool registerOsEventHandler() { return true; }
virtual void unregisterOsEventHandler() {}
virtual bool registerLockHandler() { return true; }
virtual void unregisterLockHandler() {}
bool _isSuspendEnabled;
bool _isLockEnabled;
bool _isSuspendOnLock;
bool _isSuspendRegistered;
bool _isLockRegistered;
Logger * _log {};
private:
};
#if defined(_WIN32)
class OsEventHandlerWindows : public OsEventHandlerBase, public QAbstractNativeEventFilter {
public:
OsEventHandlerWindows();
~OsEventHandlerWindows() override;
protected:
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result) override;
#else
bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
#endif
^
private:
bool registerOsEventHandler() override;
void unregisterOsEventHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
QWidget _widget;
HPOWERNOTIFY _notifyHandle;
};
using OsEventHandler = OsEventHandlerWindows;
#elif defined(__linux__)
class OsEventHandlerLinux : public OsEventHandlerBase {
Q_OBJECT
static void static_signaleHandler(int signum)
{
OsEventHandlerLinux::getInstance()->handleSignal(signum);
}
public:
OsEventHandlerLinux();
void handleSignal (int signum);
private:
static OsEventHandlerLinux* getInstance();
#if defined(HYPERION_HAS_DBUS)
bool registerOsEventHandler() override;
void unregisterOsEventHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
#endif
};
using OsEventHandler = OsEventHandlerLinux;
#else
using OsEventHandler = OsEventHandlerBase;
#endif
#endif // OsEventHandler_H

View File

@ -24,9 +24,7 @@
// Determine the cmake options // Determine the cmake options
#include <HyperionConfig.h> #include <HyperionConfig.h>
#if defined(ENABLE_CEC) #include <events/Event.h>
#include <cec/CECEvent.h>
#endif
/// ///
/// Capture class for V4L2 devices /// Capture class for V4L2 devices
@ -77,13 +75,10 @@ public:
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold = 50); void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold = 50);
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax); void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable); void setSignalDetectionEnable(bool enable);
void setCecDetectionEnable(bool enable);
bool reload(bool force = false); bool reload(bool force = false);
QRectF getSignalDetectionOffset() const { return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); } //used from hyperion-v4l2 QRectF getSignalDetectionOffset() const { return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); } //used from hyperion-v4l2
/// ///
/// @brief Discover available V4L2 USB devices (for configuration). /// @brief Discover available V4L2 USB devices (for configuration).
/// @param[in] params Parameters used to overwrite discovery default behaviour /// @param[in] params Parameters used to overwrite discovery default behaviour
@ -97,9 +92,7 @@ public slots:
void stop(); void stop();
void newThreadFrame(Image<ColorRgb> image); void newThreadFrame(Image<ColorRgb> image);
#if defined(ENABLE_CEC) void handleEvent(Event event);
void handleCecEvent(CECEvent event);
#endif
signals: signals:
void newFrame(const Image<ColorRgb> & image); void newFrame(const Image<ColorRgb> & image);
@ -167,7 +160,7 @@ private:
// signal detection // signal detection
int _noSignalCounterThreshold; int _noSignalCounterThreshold;
ColorRgb _noSignalThresholdColor; ColorRgb _noSignalThresholdColor;
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected; bool _standbyActivated, _signalDetectionEnabled, _noSignalDetected;
int _noSignalCounter; int _noSignalCounter;
int _brightness, _contrast, _saturation, _hue; int _brightness, _contrast, _saturation, _hue;
double _x_frac_min; double _x_frac_min;

View File

@ -9,9 +9,7 @@
#include <grabber/V4L2Grabber.h> #include <grabber/V4L2Grabber.h>
#endif #endif
#if defined(ENABLE_CEC) #include <events/Event.h>
#include <cec/CECEvent.h>
#endif
class VideoWrapper : public GrabberWrapper class VideoWrapper : public GrabberWrapper
{ {
@ -25,9 +23,7 @@ public slots:
bool start() override; bool start() override;
void stop() override; void stop() override;
#if defined(ENABLE_CEC) void handleEvent(Event event);
void handleCecEvent(CECEvent event);
#endif
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override; void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;

View File

@ -5,6 +5,7 @@
#include <utils/VideoMode.h> #include <utils/VideoMode.h>
#include <utils/settings.h> #include <utils/settings.h>
#include <utils/Components.h> #include <utils/Components.h>
#include <events/Event.h>
// qt // qt
#include <QMap> #include <QMap>
@ -74,26 +75,10 @@ public slots:
bool stopInstance(quint8 inst); bool stopInstance(quint8 inst);
/// ///
/// @brief Suspend (disable) all Hyperion instances /// @brief Handle an Hyperion Event
/// @param event Event to be processed
/// ///
void suspend(); void handleEvent(Event event);
///
/// @brief Resume (resume) all Hyperion instances
///
void resume();
///
/// @brief Toggle the state of all Hyperion instances for a suspend sceanrio (user is not interacting with the system)
/// @param isSuspend, If true all instances toggle to suspend, else to resume
///
void toggleSuspend(bool isSuspend);
///
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio
/// @param isIdle, If true all instances toggle to idle, else to resume
///
void toggleIdle(bool isIdle);
/// ///
/// @brief Toggle the state of all Hyperion instances /// @brief Toggle the state of all Hyperion instances
@ -147,10 +132,6 @@ signals:
/// ///
void startInstanceResponse(QObject *caller, const int &tan); void startInstanceResponse(QObject *caller, const int &tan);
void triggerSuspend(bool isSuspend);
void triggerToggleSuspend();
void triggerIdle(bool isIdle);
void triggerToggleIdle();
signals: signals:
/////////////////////////////////////// ///////////////////////////////////////
@ -192,6 +173,18 @@ private slots:
/// ///
void handleFinished(); void handleFinished();
///
/// @brief Toggle the state of all Hyperion instances for a suspend sceanrio (user is not interacting with the system)
/// @param isSuspend, If true all instances toggle to suspend, else to resume
///
void toggleSuspend(bool isSuspend);
///
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio
/// @param isIdle, If true all instances toggle to idle, else to resume
///
void toggleIdle(bool isIdle);
private: private:
friend class HyperionDaemon; friend class HyperionDaemon;
/// ///

View File

@ -30,7 +30,8 @@ namespace settings {
NETWORK, NETWORK,
FLATBUFSERVER, FLATBUFSERVER,
PROTOSERVER, PROTOSERVER,
SYSTEMEVENTS, OSEVENTS,
CECEVENTS,
INVALID INVALID
}; };
@ -65,7 +66,8 @@ namespace settings {
case NETWORK: return "network"; case NETWORK: return "network";
case FLATBUFSERVER: return "flatbufServer"; case FLATBUFSERVER: return "flatbufServer";
case PROTOSERVER: return "protoServer"; case PROTOSERVER: return "protoServer";
case SYSTEMEVENTS: return "systemEvents"; case OSEVENTS: return "osEvents";
case CECEVENTS: return "cecEvents";
default: return "invalid"; default: return "invalid";
} }
} }
@ -99,7 +101,8 @@ namespace settings {
else if (type == "network") return NETWORK; else if (type == "network") return NETWORK;
else if (type == "flatbufServer") return FLATBUFSERVER; else if (type == "flatbufServer") return FLATBUFSERVER;
else if (type == "protoServer") return PROTOSERVER; else if (type == "protoServer") return PROTOSERVER;
else if (type == "systemEvents") return SYSTEMEVENTS; else if (type == "osEvents") return OSEVENTS;
else if (type == "cecEvents") return CECEVENTS;
else return INVALID; else return INVALID;
} }
} }

View File

@ -32,6 +32,12 @@ add_subdirectory(db)
add_subdirectory(api) add_subdirectory(api)
add_subdirectory(ssdp) add_subdirectory(ssdp)
if(ENABLE_CEC)
add_subdirectory(cec)
endif()
add_subdirectory(events)
if(ENABLE_MDNS) if(ENABLE_MDNS)
add_subdirectory(mdns) add_subdirectory(mdns)
endif() endif()
@ -41,10 +47,6 @@ if(ENABLE_EFFECTENGINE)
add_subdirectory(python) add_subdirectory(python)
endif() endif()
if(ENABLE_CEC)
add_subdirectory(cec)
endif()
if(ENABLE_EXPERIMENTAL) if(ENABLE_EXPERIMENTAL)
add_subdirectory(experimental) add_subdirectory(experimental)
endif() endif()

View File

@ -22,6 +22,7 @@
#include <grabber/QtGrabber.h> #include <grabber/QtGrabber.h>
#include <utils/WeakConnect.h> #include <utils/WeakConnect.h>
#include <events/Event.h>
#if defined(ENABLE_MF) #if defined(ENABLE_MF)
#include <grabber/MFGrabber.h> #include <grabber/MFGrabber.h>
@ -82,6 +83,7 @@
// api includes // api includes
#include <api/JsonCB.h> #include <api/JsonCB.h>
#include <events/EventHandler.h>
// auth manager // auth manager
#include <hyperion/AuthManager.h> #include <hyperion/AuthManager.h>
@ -110,6 +112,8 @@ JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject
_ledStreamTimer = new QTimer(this); _ledStreamTimer = new QTimer(this);
Q_INIT_RESOURCE(JSONRPC_schemas); Q_INIT_RESOURCE(JSONRPC_schemas);
qRegisterMetaType<Event>("Event");
} }
void JsonAPI::initialize() void JsonAPI::initialize()
@ -135,16 +139,13 @@ void JsonAPI::initialize()
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage); connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
} }
//notify instance manager on suspend/resume/idle requests //notify eventhadler on suspend/resume/idle requests
connect(this, &JsonAPI::suspendAll, _instanceManager, &HyperionIManager::triggerSuspend); connect(this, &JsonAPI::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
connect(this, &JsonAPI::toggleSuspendAll, _instanceManager, &HyperionIManager::triggerToggleSuspend);
connect(this, &JsonAPI::idleAll, _instanceManager, &HyperionIManager::triggerIdle);
connect(this, &JsonAPI::toggleIdleAll, _instanceManager, &HyperionIManager::triggerToggleIdle);
connect(_ledStreamTimer, &QTimer::timeout, this, &JsonAPI::streamLedColorsUpdate, Qt::UniqueConnection); connect(_ledStreamTimer, &QTimer::timeout, this, &JsonAPI::streamLedColorsUpdate, Qt::UniqueConnection);
} }
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced) bool JsonAPI::handleInstanceSwitch(quint8 inst, bool /*forced*/)
{ {
if (API::setHyperionInstance(inst)) if (API::setHyperionInstance(inst))
{ {
@ -1014,8 +1015,7 @@ void JsonAPI::handleConfigCommand(const QJsonObject &message, const QString &com
if (_adminAuthorized) if (_adminAuthorized)
{ {
Debug(_log, "Restarting due to RPC command"); Debug(_log, "Restarting due to RPC command");
emit signalEvent(Event::Reload);
Process::restartHyperion(10);
sendSuccessReply(command + "-" + subcommand, tan); sendSuccessReply(command + "-" + subcommand, tan);
} }
@ -1852,32 +1852,37 @@ void JsonAPI::handleSystemCommand(const QJsonObject &message, const QString &com
if (subc == "suspend") if (subc == "suspend")
{ {
emit suspendAll(true); emit signalEvent(Event::Suspend);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else if (subc == "resume") else if (subc == "resume")
{ {
emit suspendAll(false); emit signalEvent(Event::Resume);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else if (subc == "restart") else if (subc == "restart")
{ {
Process::restartHyperion(11); emit signalEvent(Event::Restart);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else if (subc == "toggleSuspend") else if (subc == "toggleSuspend")
{ {
emit toggleSuspendAll(); emit signalEvent(Event::ToggleSuspend);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else if (subc == "idle") else if (subc == "idle")
{ {
emit idleAll(true); emit signalEvent(Event::Idle);
sendSuccessReply(command + "-" + subc, tan);
}
else if (subc == "resumeIdle")
{
emit signalEvent(Event::ResumeIdle);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else if (subc == "toggleIdle") else if (subc == "toggleIdle")
{ {
emit toggleIdleAll(); emit signalEvent(Event::ToggleIdle);
sendSuccessReply(command + "-" + subc, tan); sendSuccessReply(command + "-" + subc, tan);
} }
else else

View File

@ -4,6 +4,7 @@
#include <algorithm> #include <algorithm>
#include <libcec/cecloader.h> #include <libcec/cecloader.h>
#include <events/EventHandler.h>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
@ -12,13 +13,14 @@
#include <QFile> #include <QFile>
/* Enable to turn on detailed CEC logs */ /* Enable to turn on detailed CEC logs */
#define NO_VERBOSE_CEC #define VERBOSE_CEC
CECHandler::CECHandler() CECHandler::CECHandler()
: _isEnabled(false)
{ {
qRegisterMetaType<CECEvent>("CECEvent"); qRegisterMetaType<Event>("Event");
_logger = Logger::getInstance("CEC"); _logger = Logger::getInstance("CEC");
_cecCallbacks = getCallbacks(); _cecCallbacks = getCallbacks();
_cecConfig = getConfig(); _cecConfig = getConfig();
@ -31,25 +33,41 @@ CECHandler::~CECHandler()
stop(); stop();
} }
void CECHandler::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::CECEVENTS)
{
const QJsonObject& obj = config.object();
_isEnabled = obj["Enable"].toBool(false);
Debug(_logger, "_isEnabled: [%d]", _isEnabled);
}
}
bool CECHandler::start() bool CECHandler::start()
{ {
if (_cecAdapter) if (_cecAdapter)
return true;
std::string library = std::string("" CEC_LIBRARY);
_cecAdapter = LibCecInitialise(&_cecConfig, QFile::exists(QString::fromStdString(library)) ? library.c_str() : nullptr);
if(!_cecAdapter)
{ {
Error(_logger, "Failed to loading libcec.so"); return true;
}
// std::string library = std::string("" CEC_LIBRARY);
// _cecAdapter = LibCecInitialise(&_cecConfig, QFile::exists(QString::fromStdString(library)) ? library.c_str() :CEC_DEVICE_TYPE_PLAYBACK_DEVICE nullptr);
_cecAdapter = LibCecInitialise(&_cecConfig);
if(_cecAdapter == nullptr)
{
Error(_logger, "Failed loading libCEC library. CEC is not supported.");
return false; return false;
} }
Info(_logger, "CEC handler started"); Info(_logger, "CEC handler started");
auto adapters = getAdapters(); const auto adapters = getAdapters();
if (adapters.isEmpty()) if (adapters.isEmpty())
{ {
Error(_logger, "Failed to find CEC adapter"); Error(_logger, "Failed to find any CEC adapter.");
UnloadLibCec(_cecAdapter); UnloadLibCec(_cecAdapter);
_cecAdapter = nullptr; _cecAdapter = nullptr;
@ -64,14 +82,19 @@ bool CECHandler::start()
if (!opened && openAdapter(adapter)) if (!opened && openAdapter(adapter))
{ {
Info(_logger, "CEC Handler initialized with adapter : %s", adapter.strComName); QObject::connect(this, &CECHandler::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
Info(_logger, "CEC adapter '%s', type: %s initialized." , adapter.strComName, _cecAdapter->ToString(adapter.adapterType));
opened = true; opened = true;
break;
} }
} }
scan();
if (!opened) if (!opened)
{ {
Error(_logger, "Could not initialize any CEC adapter.");
UnloadLibCec(_cecAdapter); UnloadLibCec(_cecAdapter);
_cecAdapter = nullptr; _cecAdapter = nullptr;
} }
@ -81,10 +104,12 @@ bool CECHandler::start()
void CECHandler::stop() void CECHandler::stop()
{ {
if (_cecAdapter) if (_cecAdapter != nullptr)
{ {
Info(_logger, "Stopping CEC handler"); Info(_logger, "Stopping CEC handler");
QObject::disconnect(this, &CECHandler::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
_cecAdapter->Close(); _cecAdapter->Close();
UnloadLibCec(_cecAdapter); UnloadLibCec(_cecAdapter);
_cecAdapter = nullptr; _cecAdapter = nullptr;
@ -97,9 +122,9 @@ CECConfig CECHandler::getConfig() const
const std::string name("HyperionCEC"); const std::string name("HyperionCEC");
name.copy(configuration.strDeviceName, std::min(name.size(), sizeof(configuration.strDeviceName))); name.copy(configuration.strDeviceName, std::min(name.size(), sizeof(configuration.strDeviceName)));
configuration.deviceTypes.Add(CEC::CEC_DEVICE_TYPE_RECORDING_DEVICE); configuration.deviceTypes.Add(CEC::CEC_DEVICE_TYPE_RECORDING_DEVICE);
configuration.clientVersion = CEC::LIBCEC_VERSION_CURRENT; configuration.clientVersion = CEC::LIBCEC_VERSION_CURRENT;
configuration.bActivateSource = 0;
return configuration; return configuration;
} }
@ -125,7 +150,8 @@ QVector<CECAdapterDescriptor> CECHandler::getAdapters() const
return {}; return {};
QVector<CECAdapterDescriptor> descriptors(16); QVector<CECAdapterDescriptor> descriptors(16);
int8_t size = _cecAdapter->DetectAdapters(descriptors.data(), descriptors.size(), nullptr, true /*quickscan*/); //int8_t size = _cecAdapter->DetectAdapters(descriptors.data(), static_cast<uint8_t>(descriptors.size()), nullptr, true /*quickscan*/);
int8_t size = _cecAdapter->DetectAdapters(descriptors.data(), static_cast<uint8_t>(descriptors.size()), nullptr, false /*NO quickscan*/);
descriptors.resize(size); descriptors.resize(size);
return descriptors; return descriptors;
@ -138,10 +164,7 @@ bool CECHandler::openAdapter(const CECAdapterDescriptor & descriptor)
if(!_cecAdapter->Open(descriptor.strComName)) if(!_cecAdapter->Open(descriptor.strComName))
{ {
Error(_logger, "%s", QSTRING_CSTR(QString("Failed to open the CEC adaper on port %1") Error(_logger, "CEC adapter '%s', type: %s failed to open.", descriptor.strComName, _cecAdapter->ToString(descriptor.adapterType));
.arg(descriptor.strComName))
);
return false; return false;
} }
return true; return true;
@ -149,9 +172,16 @@ bool CECHandler::openAdapter(const CECAdapterDescriptor & descriptor)
void CECHandler::printAdapter(const CECAdapterDescriptor & descriptor) const void CECHandler::printAdapter(const CECAdapterDescriptor & descriptor) const
{ {
Info(_logger, "%s", QSTRING_CSTR(QString("CEC Adapter:"))); Info(_logger, "CEC Adapter:");
Info(_logger, "%s", QSTRING_CSTR(QString("\tName : %1").arg(descriptor.strComName))); Info(_logger, "\tName : %s", descriptor.strComName);
Info(_logger, "%s", QSTRING_CSTR(QString("\tPath : %1").arg(descriptor.strComPath))); Info(_logger, "\tPath : %s", descriptor.strComPath);
Info(_logger, "\tVendor id: %04x", descriptor.iVendorId);
Info(_logger, "\tProduct id: %04x", descriptor.iProductId);
Info(_logger, "\tFirmware id: %d", descriptor.iFirmwareVersion);
if (descriptor.adapterType != CEC::ADAPTERTYPE_UNKNOWN)
{
Info(_logger, "\tType : %s", _cecAdapter->ToString(descriptor.adapterType));
}
} }
QString CECHandler::scan() const QString CECHandler::scan() const
@ -163,14 +193,14 @@ QString CECHandler::scan() const
QJsonArray devices; QJsonArray devices;
CECLogicalAddresses addresses = _cecAdapter->GetActiveDevices(); CECLogicalAddresses addresses = _cecAdapter->GetActiveDevices();
for (int address = CEC::CECDEVICE_TV; address <= CEC::CECDEVICE_BROADCAST; ++address) for (uint8_t address = CEC::CECDEVICE_TV; address <= CEC::CECDEVICE_BROADCAST; ++address)
{ {
if (addresses[address]) if (addresses[address] != 0)
{ {
CECLogicalAddress logicalAddress = (CECLogicalAddress)address; CECLogicalAddress logicalAddress = static_cast<CECLogicalAddress>(address);
QJsonObject device; QJsonObject device;
CECVendorId vendor = (CECVendorId)_cecAdapter->GetDeviceVendorId(logicalAddress); CECVendorId vendor = static_cast<CECVendorId>(_cecAdapter->GetDeviceVendorId(logicalAddress));
CECPowerStatus power = _cecAdapter->GetDevicePowerStatus(logicalAddress); CECPowerStatus power = _cecAdapter->GetDevicePowerStatus(logicalAddress);
device["name" ] = _cecAdapter->GetDeviceOSDName(logicalAddress).c_str(); device["name" ] = _cecAdapter->GetDeviceOSDName(logicalAddress).c_str();
@ -181,14 +211,17 @@ QString CECHandler::scan() const
devices << device; devices << device;
Info(_logger, "%s", QSTRING_CSTR(QString("\tCECDevice: %1 / %2 / %3 / %4") Info(_logger, "%s", QSTRING_CSTR(QString("\tCECDevice: %1 / %2 / %3 / %4")
.arg(device["name"].toString(), .arg(device["name"].toString(),
device["vendor"].toString(), device["vendor"].toString(),
device["address"].toString(), device["address"].toString(),
device["power"].toString())) device["power"].toString())
)
); );
} }
} }
std::cout << "Devices: " << QJsonDocument(devices).toJson().toStdString() << std::endl;
return QJsonDocument(devices).toJson(QJsonDocument::Compact); return QJsonDocument(devices).toJson(QJsonDocument::Compact);
} }
@ -202,25 +235,17 @@ void CECHandler::onCecLogMessage(void * context, const CECLogMessage * message)
switch (message->level) switch (message->level)
{ {
case CEC::CEC_LOG_ERROR: case CEC::CEC_LOG_ERROR:
Error(handler->_logger, QString("%1") Error(handler->_logger, "%s", message->message);
.arg(message->message)
.toLocal8Bit());
break; break;
case CEC::CEC_LOG_WARNING: case CEC::CEC_LOG_WARNING:
Warning(handler->_logger, QString("%1") Warning(handler->_logger, "%s", message->message);
.arg(message->message)
.toLocal8Bit());
break; break;
case CEC::CEC_LOG_TRAFFIC: case CEC::CEC_LOG_TRAFFIC:
case CEC::CEC_LOG_NOTICE: case CEC::CEC_LOG_NOTICE:
Info(handler->_logger, QString("%1") Info(handler->_logger, "%s", message->message);
.arg(message->message)
.toLocal8Bit());
break; break;
case CEC::CEC_LOG_DEBUG: case CEC::CEC_LOG_DEBUG:
Debug(handler->_logger, QString("%1") Debug(handler->_logger, "%s", message->message);
.arg(message->message)
.toLocal8Bit());
break; break;
default: default:
break; break;
@ -230,29 +255,44 @@ void CECHandler::onCecLogMessage(void * context, const CECLogMessage * message)
void CECHandler::onCecKeyPress(void * context, const CECKeyPress * key) void CECHandler::onCecKeyPress(void * context, const CECKeyPress * key)
{ {
#ifdef VERBOSE_CEC
CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context)); CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
if (!handler) if (!handler)
return; return;
CECAdapter * adapter = handler->_cecAdapter; CECAdapter * adapter = handler->_cecAdapter;
Debug(handler->_logger, QString("CECHandler::onCecKeyPress: %1") #ifdef VERBOSE_CEC
.arg(adapter->ToString(key->keycode)) Debug(handler->_logger, "CECHandler::onCecKeyPress: %s", adapter->ToString(key->keycode));
.toLocal8Bit());
#endif #endif
switch (key->keycode) {
case CEC::CEC_USER_CONTROL_CODE_F1_BLUE:
emit handler->signalEvent(Event::ToggleIdle);
break;
case CEC::CEC_USER_CONTROL_CODE_F2_RED:
emit handler->signalEvent(Event::Suspend);
break;
case CEC::CEC_USER_CONTROL_CODE_F3_GREEN:
emit handler->signalEvent(Event::Resume);
break;
case CEC::CEC_USER_CONTROL_CODE_F4_YELLOW:
emit handler->signalEvent(Event::ToggleSuspend);
break;
default:
break;
}
} }
void CECHandler::onCecAlert(void * context, const CECAlert alert, const CECParameter data) void CECHandler::onCecAlert(void * context, const CECAlert alert, const CECParameter /* data */)
{ {
#ifdef VERBOSE_CEC #ifdef VERBOSE_CEC
CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context)); CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
if (!handler) if (!handler)
return; return;
Error(handler->_logger, QString("CECHandler::onCecAlert: %1") Error(handler->_logger, QSTRING_CSTR(QString("CECHandler::onCecAlert: %1")
.arg(alert) .arg(alert)));
.toLocal8Bit());
#endif #endif
} }
@ -263,9 +303,7 @@ void CECHandler::onCecConfigurationChanged(void * context, const CECConfig * con
if (!handler) if (!handler)
return; return;
Debug(handler->_logger, QString("CECHandler::onCecConfigurationChanged: %1") Debug(handler->_logger, "CECHandler::onCecConfigurationChanged: %s", configuration->strDeviceName);
.arg(configuration->strDeviceName)
.toLocal8Bit());
#endif #endif
} }
@ -278,9 +316,7 @@ int CECHandler::onCecMenuStateChanged(void * context, const CECMenuState state)
CECAdapter * adapter = handler->_cecAdapter; CECAdapter * adapter = handler->_cecAdapter;
Debug(handler->_logger, QString("CECHandler::onCecMenuStateChanged: %1") Debug(handler->_logger, "CECHandler::onCecMenuStateChanged: %s", adapter->ToString(state));
.arg(adapter->ToString(state))
.toLocal8Bit());
#endif #endif
return 0; return 0;
} }
@ -294,28 +330,28 @@ void CECHandler::onCecCommandReceived(void * context, const CECCommand * command
CECAdapter * adapter = handler->_cecAdapter; CECAdapter * adapter = handler->_cecAdapter;
#ifdef VERBOSE_CEC #ifdef VERBOSE_CEC
Debug(handler->_logger, QString("CECHandler::onCecCommandReceived: %1 (%2 > %3)") Debug(handler->_logger, "CECHandler::onCecCommandReceived: %s %s > %s)",
.arg(adapter->ToString(command->opcode)) adapter->ToString(command->opcode),
.arg(adapter->ToString(command->initiator)) adapter->ToString(command->initiator),
.arg(adapter->ToString(command->destination)) adapter->ToString(command->destination)
.toLocal8Bit()); );
#endif #endif
/* We do NOT check sender */ /* We do NOT check sender */
// if (address == CEC::CECDEVICE_TV) //if (address == CEC::CECDEVICE_TV)
{ {
if (command->opcode == CEC::CEC_OPCODE_SET_STREAM_PATH) switch (command->opcode) {
{ case CEC::CEC_OPCODE_STANDBY:
Info(handler->_logger, "%s", QSTRING_CSTR(QString("CEC source activated: %1") Info(handler->_logger, "CEC source deactivated: %s", adapter->ToString(command->initiator));
.arg(adapter->ToString(command->initiator))) emit handler->signalEvent(Event::Suspend);
); break;
emit handler->cecEvent(CECEvent::On);
} case CEC::CEC_OPCODE_SET_STREAM_PATH:
if (command->opcode == CEC::CEC_OPCODE_STANDBY) Info(handler->_logger, "'CEC source activated: %s", adapter->ToString(command->initiator));
{ emit handler->signalEvent(Event::Resume);
Info(handler->_logger, "%s", QSTRING_CSTR(QString("CEC source deactivated: %1") break;
.arg(adapter->ToString(command->initiator)))
); default:
emit handler->cecEvent(CECEvent::Off); break;
} }
} }
} }
@ -328,14 +364,15 @@ void CECHandler::onCecSourceActivated(void * context, const CECLogicalAddress ad
#ifdef VERBOSE_CEC #ifdef VERBOSE_CEC
CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context)); CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
if (!handler) if (!handler)
{
return; return;
}
CECAdapter * adapter = handler->_cecAdapter; CECAdapter * adapter = handler->_cecAdapter;
Debug(handler->_logger, QSTRING_CSTR(QString("CEC source %1 : %2")
Debug(handler->_logger, QString("CEC source %1 : %2") .arg(activated ? "activated" : "deactivated",
.arg(activated ? "activated" : "deactivated") adapter->ToString(address))
.arg(adapter->ToString(address)) ));
.toLocal8Bit());
#endif #endif
} }

View File

@ -7,6 +7,9 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/cec)
FILE (GLOB CEC_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp") FILE (GLOB CEC_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp")
add_library(cechandler ${CEC_SOURCES}) add_library(cechandler ${CEC_SOURCES})
message(STATUS "CEC_LIBRARIES = ${CEC_LIBRARIES}")
list(GET CEC_LIBRARIES 0 CEC_LIBRARIES) list(GET CEC_LIBRARIES 0 CEC_LIBRARIES)
add_definitions(-DCEC_LIBRARY="${CEC_LIBRARIES}") add_definitions(-DCEC_LIBRARY="${CEC_LIBRARIES}")

View File

@ -0,0 +1,25 @@
# Define the current source/header locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/events)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/events)
add_library(events
${CURRENT_HEADER_DIR}/Event.h
${CURRENT_HEADER_DIR}/EventHandler.h
${CURRENT_SOURCE_DIR}/EventHandler.cpp
${CURRENT_HEADER_DIR}/OsEventHandler.h
${CURRENT_SOURCE_DIR}/OsEventHandler.cpp
)
if (UNIX)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET )
if (Qt${QT_VERSION_MAJOR}DBus_FOUND)
target_link_libraries(events Qt${QT_VERSION_MAJOR}::DBus)
if (NOT APPLE)
target_compile_definitions(events PUBLIC HYPERION_HAS_DBUS)
endif()
endif()
endif(UNIX)
target_include_directories(events PUBLIC
${CURRENT_HEADER_DIR}
)

View File

@ -0,0 +1,186 @@
#include <events/EventHandler.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <events/Event.h>
#include <utils/Logger.h>
#include <utils/Process.h>
#include <hyperion/HyperionIManager.h>
EventHandler::EventHandler()
: _isSuspended(false)
, _isIdle(false)
{
qRegisterMetaType<Event>("Event");
_log = Logger::getInstance("EVENTS");
QObject::connect(this, &EventHandler::signalEvent, HyperionIManager::getInstance(), &HyperionIManager::handleEvent);
}
EventHandler::~EventHandler()
{
QObject::disconnect(this, &EventHandler::signalEvent, HyperionIManager::getInstance(), &HyperionIManager::handleEvent);
}
EventHandler* EventHandler::getInstance()
{
static EventHandler instance;
return &instance;
}
void EventHandler::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::OSEVENTS)
{
const QJsonObject& obj = config.object();
}
}
void EventHandler::suspend()
{
suspend(true);
}
void EventHandler::suspend(bool sleep)
{
if (sleep)
{
if (!_isSuspended)
{
_isSuspended = true;
Info(_log, "Suspend event received - Hyperion is going to sleep");
emit signalEvent(Event::Suspend);
}
else
{
Debug(_log, "Suspend event ignored - already suspended");
}
}
else
{
if (_isSuspended || _isIdle)
{
Info(_log, "Resume event received - Hyperion is going into working mode");
emit signalEvent(Event::Resume);
_isSuspended = false;
_isIdle = false;
}
else
{
Debug(_log, "Resume event ignored - not in suspend nor idle mode");
}
}
}
void EventHandler::resume()
{
suspend(false);
}
void EventHandler::toggleSuspend()
{
Debug(_log, "Toggle suspend event received");
if (!_isSuspended)
{
suspend(true);
}
else
{
suspend(false);
}
}
void EventHandler::idle()
{
idle(true);
}
void EventHandler::idle(bool isIdle)
{
if (!_isSuspended)
{
if (isIdle)
{
if (!_isIdle)
{
_isIdle = true;
Info(_log, "Idle event received");
emit signalEvent(Event::Idle);
}
}
else
{
if (_isIdle)
{
Info(_log, "Resume from idle event recevied");
emit signalEvent(Event::ResumeIdle);
_isIdle = false;
}
}
}
else
{
Debug(_log, "Idle event ignored - Hyperion is suspended");
}
}
void EventHandler::resumeIdle()
{
idle(false);
}
void EventHandler::toggleIdle()
{
Debug(_log, "Toggle idle event received");
if (!_isIdle)
{
idle(true);
}
else
{
idle(false);
}
}
void EventHandler::handleEvent(Event event)
{
Debug(_log,"%s Event [%d] received", eventToString(event), event);
switch (event) {
case Event::Suspend:
suspend();
break;
case Event::Resume:
resume();
break;
case Event::ToggleSuspend:
suspend();
break;
case Event::Idle:
idle(true);
break;
case Event::ResumeIdle:
idle(false);
break;
case Event::ToggleIdle:
toggleIdle();
break;
case Event::Reload:
Process::restartHyperion(10);
break;
case Event::Restart:
Process::restartHyperion(11);
break;
default:
Error(_log,"Unkonwn Event '%d' received", event);
break;
}
}

View File

@ -0,0 +1,448 @@
#include "OsEventHandler.h"
#include <QtGlobal>
#include <QJsonDocument>
#include <QJsonObject>
#include <events/EventHandler.h>
#include <utils/Logger.h>
#include <iostream>
#if defined(_WIN32)
#include <QCoreApplication>
#include <QWidget>
#include <windows.h>
#include <wtsapi32.h>
#pragma comment( lib, "wtsapi32.lib" )
#endif
OsEventHandlerBase::OsEventHandlerBase()
: _isSuspendEnabled(false)
, _isLockEnabled(false)
, _isSuspendOnLock(false)
, _isSuspendRegistered(false)
, _isLockRegistered(false)
{
qRegisterMetaType<Event>("Event");
_log = Logger::getInstance("EVENTS");
QObject::connect(this, &OsEventHandlerBase::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
}
OsEventHandlerBase::~OsEventHandlerBase()
{
QObject::disconnect(this, &OsEventHandlerBase::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
unregisterLockHandler();
unregisterOsEventHandler();
}
void OsEventHandlerBase::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::OSEVENTS)
{
const QJsonObject& obj = config.object();
//Suspend on lock or go into idle mode
bool prevIsSuspendOnLock = _isSuspendOnLock;
_isSuspendOnLock = obj["suspendOnLockEnable"].toBool(false);
//Handle OS event related configurations
_isSuspendEnabled = obj["suspendEnable"].toBool(true);
if (_isSuspendEnabled)
{
// Listen to suspend/resume/idle events received by the OS
registerOsEventHandler();
}
else
{
unregisterOsEventHandler();
}
_isLockEnabled = obj["lockEnable"].toBool(true);
if (_isLockEnabled || _isSuspendOnLock != prevIsSuspendOnLock)
{
// Listen to lock/screensaver events received by the OS
registerLockHandler();
}
else
{
unregisterLockHandler();
}
}
}
void OsEventHandlerBase::suspend(bool sleep)
{
if (sleep)
{
emit signalEvent(Event::Suspend);
}
else
{
emit signalEvent(Event::Resume);
}
}
void OsEventHandlerBase::lock(bool isLocked)
{
if (isLocked)
{
if (_isSuspendOnLock)
{
emit signalEvent(Event::Suspend);
}
else
{
emit signalEvent(Event::Idle);
}
}
else
{
if (_isSuspendOnLock)
{
emit signalEvent(Event::Resume);
}
else
{
emit signalEvent(Event::ResumeIdle);
}
}
}
#if defined(_WIN32)
OsEventHandlerWindows::OsEventHandlerWindows()
: _notifyHandle(NULL)
{
}
OsEventHandlerWindows::~OsEventHandlerWindows()
{
unregisterLockHandler();
unregisterOsEventHandler();
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool OsEventHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, qintptr* /*result*/)
#else
bool OsEventHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, long int* /*result*/)
#endif
{
MSG* msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_WTSSESSION_CHANGE:
switch (msg->wParam)
{
case WTS_SESSION_LOCK:
emit lock(true);
return true;
break;
case WTS_SESSION_UNLOCK:
emit lock(false);
return true;
break;
}
break;
case WM_POWERBROADCAST:
switch (msg->wParam)
{
case PBT_APMRESUMESUSPEND:
emit suspend(false);
return true;
break;
case PBT_APMSUSPEND:
emit suspend(true);
return true;
break;
}
break;
}
return false;
}
bool OsEventHandlerWindows::registerOsEventHandler()
{
bool isRegistered{ _isSuspendRegistered };
if (!_isSuspendRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
_notifyHandle = RegisterSuspendResumeNotification(handle, DEVICE_NOTIFY_WINDOW_HANDLE);
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->installNativeEventFilter(this);
}
else
{
Error(_log, "Could not register for suspend/resume events!");
}
if (isRegistered)
{
_isSuspendRegistered = true;
}
}
return isRegistered;
}
void OsEventHandlerWindows::unregisterOsEventHandler()
{
if (_isSuspendRegistered)
{
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->removeNativeEventFilter(this);
UnregisterSuspendResumeNotification(_notifyHandle);
}
_notifyHandle = NULL;
_isSuspendRegistered = false;
}
}
bool OsEventHandlerWindows::registerLockHandler()
{
bool isRegistered{ _isLockRegistered };
if (!_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
if (WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION))
{
isRegistered = true;
}
else
{
Error(_log, "Could not register for lock/unlock events!");
}
}
if (isRegistered)
{
_isLockRegistered = true;
}
return isRegistered;
}
void OsEventHandlerWindows::unregisterLockHandler()
{
if (_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
WTSUnRegisterSessionNotification(handle);
_isLockRegistered = false;
}
}
#elif defined(__linux__)
#include <csignal>
OsEventHandlerLinux* OsEventHandlerLinux::getInstance()
{
static OsEventHandlerLinux instance;
return &instance;
}
OsEventHandlerLinux::OsEventHandlerLinux()
{
signal(SIGUSR1, static_signaleHandler);
signal(SIGUSR2, static_signaleHandler);
}
void OsEventHandlerLinux::handleSignal (int signum)
{
if (signum == SIGUSR1)
{
suspend(true);
}
else if (signum == SIGUSR2)
{
suspend(false);
}
}
#if defined(HYPERION_HAS_DBUS)
#include <QDBusConnection>
struct dBusSignals
{
QString service;
QString path;
QString interface;
QString name;
};
typedef QMultiMap<QString, dBusSignals> DbusSignalsMap;
// Constants
namespace {
const DbusSignalsMap dbusSignals = {
//system signals
{"Suspend", {"org.freedesktop.login1","/org/freedesktop/login1","org.freedesktop.login1.Manager","PrepareForSleep"}},
//Session signals
{"ScreenSaver", {"org.freedesktop.ScreenSaver","/org/freedesktop/ScreenSaver","org.freedesktop.ScreenSaver","ActiveChanged"}},
{"ScreenSaver", {"org.gnome.ScreenSaver","/org/gnome/ScreenSaver","org.gnome.ScreenSaver","ActiveChanged"}},
};
} //End of constants
bool OsEventHandlerLinux::registerOsEventHandler()
{
bool isRegistered {_isSuspendRegistered};
if (!_isSuspendRegistered)
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(_log, "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (systemBus.connect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
{
Debug(_log, "Registered for suspend/resume events via service: %s", QSTRING_CSTR(service));
isRegistered = true;
}
else
{
Error(_log, "Could not register for suspend/resume events via service: %s", QSTRING_CSTR(service));
}
}
if (isRegistered)
{
_isSuspendRegistered = true;
}
}
return isRegistered;
}
void OsEventHandlerLinux::unregisterOsEventHandler()
{
if (_isSuspendRegistered)
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(_log, "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (systemBus.disconnect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
{
Debug(_log, "Unregistered for suspend/resume events via service: %s", QSTRING_CSTR(service));
_isSuspendRegistered = false;
}
else
{
Error(_log, "Could not unregister for suspend/resume events via service: %s", QSTRING_CSTR(service));
}
}
}
}
bool OsEventHandlerLinux::registerLockHandler()
{
bool isRegistered {_isLockRegistered};
if (!_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "The lock/unlock feature is not supported by your system configuration");
}
else
{
DbusSignalsMap::const_iterator iter = dbusSignals.find("ScreenSaver");
while (iter != dbusSignals.end() && iter.key() == "ScreenSaver") {
QString service = iter.value().service;
if (sessionBus.connect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
{
Debug(_log, "Registered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isRegistered = true;
}
else
{
Error(_log, "Could not register for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
}
}
if (isRegistered)
{
_isLockRegistered = true;
}
return isRegistered;
}
void OsEventHandlerLinux::unregisterLockHandler()
{
bool isUnregistered {false};
if (_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "The lock/unlock feature is not supported by your system configuration");
}
else
{
DbusSignalsMap::const_iterator iter = dbusSignals.find("ScreenSaver");
while (iter != dbusSignals.end() && iter.key() == "ScreenSaver") {
QString service = iter.value().service;
if (sessionBus.disconnect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
{
Debug(_log, "Unregistered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isUnregistered = true;
}
else
{
Error(_log, "Could not unregister for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
if (isUnregistered)
{
_isLockRegistered = false;
}
}
}
}
#endif // HYPERION_HAS_DBUS
#endif // __linux__

View File

@ -2,6 +2,8 @@
#include <grabber/VideoWrapper.h> #include <grabber/VideoWrapper.h>
#include <events/EventHandler.h>
// qt includes // qt includes
#include <QTimer> #include <QTimer>
@ -15,10 +17,15 @@ VideoWrapper::VideoWrapper()
{ {
// register the image type // register the image type
qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>"); qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
qRegisterMetaType<Event>("Event");
// Handle the image in the captured thread (Media Foundation/V4L2) using a direct connection // Handle the image in the captured thread (Media Foundation/V4L2) using a direct connection
connect(&_grabber, SIGNAL(newFrame(const Image<ColorRgb>&)), this, SLOT(newFrame(const Image<ColorRgb>&)), Qt::DirectConnection); connect(&_grabber, SIGNAL(newFrame(const Image<ColorRgb>&)), this, SLOT(newFrame(const Image<ColorRgb>&)), Qt::DirectConnection);
connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection); connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection);
connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection);
QObject::connect(EventHandler::getInstance(), &EventHandler::signalEvent, this, &VideoWrapper::handleEvent);
} }
VideoWrapper::~VideoWrapper() VideoWrapper::~VideoWrapper()
@ -37,15 +44,11 @@ void VideoWrapper::stop()
GrabberWrapper::stop(); GrabberWrapper::stop();
} }
#if defined(ENABLE_CEC) && !defined(ENABLE_MF) void VideoWrapper::handleEvent(Event event)
void VideoWrapper::handleCecEvent(CECEvent event)
{ {
_grabber.handleCecEvent(event); _grabber.handleEvent(event);
} }
#endif
void VideoWrapper::handleSettingsUpdate(settings::type type, const QJsonDocument& config) void VideoWrapper::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{ {
if(type == settings::V4L2 && _grabberName.startsWith("V4L2")) if(type == settings::V4L2 && _grabberName.startsWith("V4L2"))
@ -100,11 +103,6 @@ void VideoWrapper::handleSettingsUpdate(settings::type type, const QJsonDocument
obj["hardware_saturation"].toInt(0), obj["hardware_saturation"].toInt(0),
obj["hardware_hue"].toInt(0)); obj["hardware_hue"].toInt(0));
#if defined(ENABLE_CEC) && defined(ENABLE_V4L2)
// CEC Standby
_grabber.setCecDetectionEnable(obj["cecDetection"].toBool(true));
#endif
// Software frame skipping // Software frame skipping
_grabber.setFpsSoftwareDecimation(obj["fpsSoftwareDecimation"].toInt(1)); _grabber.setFpsSoftwareDecimation(obj["fpsSoftwareDecimation"].toInt(1));

View File

@ -79,8 +79,7 @@ V4L2Grabber::V4L2Grabber()
, _currentFrame(0) , _currentFrame(0)
, _noSignalCounterThreshold(40) , _noSignalCounterThreshold(40)
, _noSignalThresholdColor(ColorRgb{0,0,0}) , _noSignalThresholdColor(ColorRgb{0,0,0})
, _cecDetectionEnabled(true) , _standbyActivated(false)
, _cecStandbyActivated(false)
, _signalDetectionEnabled(true) , _signalDetectionEnabled(true)
, _noSignalDetected(false) , _noSignalDetected(false)
, _noSignalCounter(0) , _noSignalCounter(0)
@ -1035,7 +1034,7 @@ bool V4L2Grabber::process_image(const void *p, int size)
void V4L2Grabber::newThreadFrame(Image<ColorRgb> image) void V4L2Grabber::newThreadFrame(Image<ColorRgb> image)
{ {
if (_cecDetectionEnabled && _cecStandbyActivated) if (_standbyActivated)
return; return;
if (_signalDetectionEnabled) if (_signalDetectionEnabled)
@ -1203,16 +1202,6 @@ void V4L2Grabber::setSignalDetectionEnable(bool enable)
} }
} }
void V4L2Grabber::setCecDetectionEnable(bool enable)
{
if (_cecDetectionEnabled != enable)
{
_cecDetectionEnabled = enable;
if(_initialized)
Info(_log, "%s", QSTRING_CSTR(QString("CEC detection is now %1").arg(enable ? "enabled" : "disabled")));
}
}
bool V4L2Grabber::reload(bool force) bool V4L2Grabber::reload(bool force)
{ {
if (_reload || force) if (_reload || force)
@ -1231,26 +1220,24 @@ bool V4L2Grabber::reload(bool force)
return false; return false;
} }
#if defined(ENABLE_CEC) void V4L2Grabber::handleEvent(Event event)
void V4L2Grabber::handleCecEvent(CECEvent event)
{ {
switch (event) switch (event)
{ {
case CECEvent::On : case Event::Suspend:
Debug(_log,"CEC on event received"); case Event::Idle:
_cecStandbyActivated = false; Debug(_log,"Suspend/Idle event received");
return; _standbyActivated = true;
case CECEvent::Off : return;
Debug(_log,"CEC off event received"); case Event::Resume:
_cecStandbyActivated = true; case Event::ResumeIdle:
return; Debug(_log,"Resume event received");
default: break; _standbyActivated = false;
return;
default: break;
} }
} }
#endif
QJsonArray V4L2Grabber::discover(const QJsonObject& params) QJsonArray V4L2Grabber::discover(const QJsonObject& params)
{ {
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData()); DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());

View File

@ -63,23 +63,28 @@ void HyperionIManager::stopAll()
} }
} }
void HyperionIManager::suspend() void HyperionIManager::handleEvent(Event event)
{ {
Info(_log,"Suspend all instances and enabled components"); Debug(_log,"%s Event [%d] received", eventToString(event), event);
QMap<quint8, Hyperion*> instCopy = _runningInstances; switch (event) {
for(const auto instance : instCopy) case Event::Suspend:
{ toggleSuspend(true);
emit instance->suspendRequest(true); break;
}
}
void HyperionIManager::resume() case Event::Resume:
{ toggleSuspend(false);
Info(_log,"Resume all instances and enabled components"); break;
QMap<quint8, Hyperion*> instCopy = _runningInstances;
for(const auto instance : instCopy) case Event::Idle:
{ toggleIdle(true);
emit instance->suspendRequest(false); break;
case Event::ResumeIdle:
toggleIdle(false);
break;
default:
break;
} }
} }

View File

@ -91,10 +91,14 @@
{ {
"$ref": "schema-leds.json" "$ref": "schema-leds.json"
}, },
"systemEvents": "osEvents":
{ {
"$ref": "schema-systemEvents.json" "$ref": "schema-osEvents.json"
} },
"cecEvents":
{
"$ref": "schema-cecEvents.json"
}
}, },
"additionalProperties" : false "additionalProperties" : false
} }

View File

@ -23,6 +23,7 @@
<file alias="schema-leds.json">schema/schema-leds.json</file> <file alias="schema-leds.json">schema/schema-leds.json</file>
<file alias="schema-instCapture.json">schema/schema-instCapture.json</file> <file alias="schema-instCapture.json">schema/schema-instCapture.json</file>
<file alias="schema-network.json">schema/schema-network.json</file> <file alias="schema-network.json">schema/schema-network.json</file>
<file alias="schema-systemEvents.json">schema/schema-systemEvents.json</file> <file alias="schema-osEvents.json">schema/schema-osEvents.json</file>
<file alias="schema-cecEvents.json">schema/schema-cecEvents.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1,17 @@
{
"type" : "object",
"required" : true,
"title" : "edt_conf_cec_events_heading_title",
"properties" :
{
"enable" :
{
"type" : "boolean",
"required" : true,
"title" : "edt_conf_general_enable_title",
"default" : false,
"propertyOrder" : 1
}
},
"additionalProperties" : false
}

View File

@ -1,26 +1,26 @@
{ {
"type" : "object", "type" : "object",
"required" : true, "required" : true,
"title" : "edt_conf_system_events_heading_title", "title" : "edt_conf_os_events_heading_title",
"properties": { "properties": {
"suspendEnable": { "suspendEnable": {
"type": "boolean", "type": "boolean",
"required": true, "required": true,
"title": "edt_conf_system_events_suspendEnable_title", "title": "edt_conf_os_events_suspendEnable_title",
"default": true, "default": true,
"propertyOrder": 1 "propertyOrder": 1
}, },
"lockEnable": { "lockEnable": {
"type": "boolean", "type": "boolean",
"required": true, "required": true,
"title": "edt_conf_system_events_lockEnable_title", "title": "edt_conf_os_events_lockEnable_title",
"default": true, "default": true,
"propertyOrder": 2 "propertyOrder": 2
}, },
"suspendOnLockEnable": { "suspendOnLockEnable": {
"type": "boolean", "type": "boolean",
"required": false, "required": false,
"title": "edt_conf_system_events_suspendOnLockEnable_title", "title": "edt_conf_os_events_suspendOnLockEnable_title",
"default": false, "default": false,
"options": { "options": {
"dependencies": { "dependencies": {

View File

@ -36,6 +36,8 @@ void JsonClientConnection::readRequest()
// remove message data from buffer // remove message data from buffer
_receiveBuffer = _receiveBuffer.mid(bytes); _receiveBuffer = _receiveBuffer.mid(bytes);
std::cout << "JsonClientConnection::readRequest | [" << _socket->peerAddress().toString().toStdString() << "] Received: [" << message.toStdString() << "]" << std::endl;
// handle message // handle message
_jsonAPI->handleMessage(message); _jsonAPI->handleMessage(message);
@ -49,6 +51,8 @@ qint64 JsonClientConnection::sendMessage(QJsonObject message)
QJsonDocument writer(message); QJsonDocument writer(message);
QByteArray data = writer.toJson(QJsonDocument::Compact) + "\n"; QByteArray data = writer.toJson(QJsonDocument::Compact) + "\n";
std::cout << "JsonClientConnection::sendMessage | [" << _socket->peerAddress().toString().toStdString() << "] Send: [" << data.constData() << "]" << std::endl;
if (!_socket || (_socket->state() != QAbstractSocket::ConnectedState)) return 0; if (!_socket || (_socket->state() != QAbstractSocket::ConnectedState)) return 0;
return _socket->write(data.data(), data.size()); return _socket->write(data.data(), data.size());
} }

View File

@ -30,29 +30,17 @@ if (APPLE)
set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endif(APPLE) endif(APPLE)
if (UNIX)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET )
if (Qt${QT_VERSION_MAJOR}DBus_FOUND)
set(hyperiond_POWER_MNG_DBUS "Qt${QT_VERSION_MAJOR}::DBus")
endif()
endif(UNIX)
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
console.h console.h
hyperiond.h hyperiond.h
systray.h systray.h
hyperiond.cpp hyperiond.cpp
systray.cpp systray.cpp
SuspendHandler.cpp
main.cpp main.cpp
${hyperiond_WIN_RC_PATH} ${hyperiond_WIN_RC_PATH}
${BUNDLE_RESOURCE_FILES} ${BUNDLE_RESOURCE_FILES}
) )
if (UNIX AND NOT APPLE AND Qt${QT_VERSION_MAJOR}DBus_FOUND)
target_compile_definitions(${PROJECT_NAME} PUBLIC HYPERION_HAS_DBUS)
endif()
# promote hyperiond as GUI app # promote hyperiond as GUI app
if (WIN32) if (WIN32)
target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup) target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
@ -66,11 +54,11 @@ target_link_libraries(${PROJECT_NAME}
ssdp ssdp
database database
resources resources
events
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
${hyperiond_POWER_MNG_DBUS}
) )
if(ENABLE_EFFECTENGINE) if(ENABLE_EFFECTENGINE)
@ -119,7 +107,7 @@ if (ENABLE_MF)
endif (ENABLE_MF) endif (ENABLE_MF)
if (ENABLE_AUDIO) if (ENABLE_AUDIO)
target_link_libraries(hyperiond audio-grabber) target_link_libraries(${PROJECT_NAME} audio-grabber)
endif() endif()
if (ENABLE_AMLOGIC) if (ENABLE_AMLOGIC)

View File

@ -1,637 +0,0 @@
#include "SuspendHandler.h"
#include <QtGlobal>
#include <QJsonDocument>
#include <QJsonObject>
#include <hyperion/HyperionIManager.h>
#include <utils/Logger.h>
#include <iostream>
#if defined(_WIN32)
#include <QCoreApplication>
#include <QWidget>
#include <windows.h>
#include <wtsapi32.h>
#pragma comment( lib, "wtsapi32.lib" )
#endif
SuspendHandlerBase::SuspendHandlerBase()
: _isSuspendEnabled(false)
, _isLockEnabled(false)
, _isSuspendApiEnabled(false)
, _isIdleApiEnabled(false)
, _isSuspendOnLock(false)
, _isSuspendRegistered(false)
, _isLockRegistered(false)
, _isSuspendApiRegistered(false)
, _isIdleApiRegistered(false)
, _isSuspended(false)
, _isIdle(false)
, _isLocked (false)
{
_log = Logger::getInstance("EVENTS");
}
SuspendHandlerBase::~SuspendHandlerBase()
{
unregisterLockHandler();
unregisterSuspendHandler();
unregisterIdleApiHandler();
unregisterSuspendApiHandler();
}
void SuspendHandlerBase::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::SYSTEMEVENTS)
{
const QJsonObject& obj = config.object();
//Suspend on lock or go into idle mode
bool prevIsSuspendOnLock = _isSuspendOnLock;
_isSuspendOnLock = obj["suspendOnLockEnable"].toBool(false);
//Handle OS event related configurations
_isSuspendEnabled = obj["suspendEnable"].toBool(true);
if (_isSuspendEnabled)
{
// Listen to suspend/resume/idle events received by the OS
registerSuspendHandler();
}
else
{
unregisterSuspendHandler();
}
_isLockEnabled = obj["lockEnable"].toBool(true);
if (_isLockEnabled || _isSuspendOnLock != prevIsSuspendOnLock)
{
// Listen to lock/screensaver events received by the OS
registerLockHandler();
}
else
{
unregisterLockHandler();
}
//Handle API event related configurations
_isSuspendApiEnabled = obj["suspendApiEnable"].toBool(true);
if (_isSuspendApiEnabled)
{
// Listen to suspend/resume/idle events received by the OS
registerSuspendApiHandler();
}
else
{
unregisterSuspendApiHandler();
}
_isIdleApiEnabled = obj["idleApiEnable"].toBool(true);
if (_isIdleApiEnabled)
{
// Listen to lock/screensaver events received by the OS
registerIdleApiHandler();
}
else
{
unregisterIdleApiHandler();
}
}
}
bool SuspendHandlerBase::registerSuspendHandler()
{
if (!_isSuspendRegistered)
{
QObject::connect(this, &SuspendHandlerBase::suspendEvent, HyperionIManager::getInstance(), &HyperionIManager::suspend);
QObject::connect(this, &SuspendHandlerBase::resumeEvent, HyperionIManager::getInstance(), &HyperionIManager::resume);
Info(_log, "Registered for suspend/resume events.");
_isSuspendRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
QObject::disconnect(this, &SuspendHandlerBase::suspendEvent, HyperionIManager::getInstance(), &HyperionIManager::suspend);
QObject::disconnect(this, &SuspendHandlerBase::resumeEvent, HyperionIManager::getInstance(), &HyperionIManager::resume);
Info(_log, "Unregistered for suspend/resume events.");
_isSuspendRegistered = false;
}
}
bool SuspendHandlerBase::registerLockHandler()
{
QObject::disconnect(this, &SuspendHandlerBase::lockedEvent,nullptr, nullptr);
if (_isSuspendOnLock)
{
QObject::connect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleSuspend);
}
else
{
QObject::connect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
}
QObject::connect(this, &SuspendHandlerBase::idleEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
Info(_log, "Registered for lock/unlock events. %s on lock event.", _isSuspendOnLock ? "Suspend" : "Idle");
_isLockRegistered = true;
return true;
}
void SuspendHandlerBase::unregisterLockHandler()
{
if (_isLockRegistered)
{
QObject::disconnect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleSuspend);
QObject::disconnect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
QObject::disconnect(this, &SuspendHandlerBase::idleEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
Info(_log, "Unregistered for lock/unlock events.");
_isLockRegistered = false;
}
}
bool SuspendHandlerBase::registerSuspendApiHandler()
{
if (!_isSuspendApiRegistered)
{
QObject::connect(HyperionIManager::getInstance(), &HyperionIManager::triggerSuspend, this, QOverload<bool>::of(&SuspendHandler::suspend));
QObject::connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleSuspend, this, &SuspendHandler::toggleSuspend);
Info(_log, "Registered for suspend/resume API events.");
_isSuspendApiRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterSuspendApiHandler()
{
if (_isSuspendApiRegistered)
{
QObject::disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerSuspend, this, QOverload<bool>::of(&SuspendHandler::suspend));
QObject::disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleSuspend, this, &SuspendHandler::toggleSuspend);
Info(_log, "Unregistered for suspend/resume API events.");
_isSuspendApiRegistered = false;
}
}
bool SuspendHandlerBase::registerIdleApiHandler()
{
if (!_isIdleApiRegistered)
{
QObject::connect(HyperionIManager::getInstance(), &HyperionIManager::triggerIdle, this, &SuspendHandler::idle);
QObject::connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleIdle, this, &SuspendHandler::toggleIdle);
Info(_log, "Registered for idle API events.");
_isIdleApiRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterIdleApiHandler()
{
if (_isIdleApiRegistered)
{
QObject::disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerIdle, this, &SuspendHandler::idle);
QObject::disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleIdle, this, &SuspendHandler::toggleIdle);
Info(_log, "Unregistered for idle API events.");
_isIdleApiRegistered = false;
}
}
void SuspendHandlerBase::suspend()
{
suspend(true);
}
void SuspendHandlerBase::suspend(bool sleep)
{
if (sleep)
{
if (!_isSuspended)
{
_isSuspended = true;
Info(_log, "Suspend event received - Hyperion is going to sleep");
emit suspendEvent();
}
else
{
Debug(_log, "Suspend event ignored - already suspended");
}
}
else
{
if (_isSuspended || _isIdle)
{
Info(_log, "Resume event received - Hyperion is going into working mode");
emit resumeEvent();
_isSuspended = false;
_isIdle = false;
}
else
{
Debug(_log, "Resume event ignored - not in suspend nor idle mode");
}
}
}
void SuspendHandlerBase::resume()
{
suspend(false);
}
void SuspendHandlerBase::toggleSuspend()
{
Debug(_log, "Toggle suspend event received");
if (!_isSuspended)
{
suspend(true);
}
else
{
suspend(false);
}
}
void SuspendHandlerBase::idle(bool isIdle)
{
if (!_isSuspended)
{
if (isIdle)
{
if (!_isIdle)
{
_isIdle = true;
Info(_log, "Idle event received");
emit idleEvent(isIdle);
}
}
else
{
if (_isIdle)
{
Info(_log, "Resume from idle event recevied");
emit idleEvent(isIdle);
_isIdle = false;
}
}
}
else
{
Debug(_log, "Idle event ignored - Hyperion is suspended");
}
}
void SuspendHandlerBase::toggleIdle()
{
Debug(_log, "Toggle idle event received");
if (!_isIdle)
{
idle(true);
}
else
{
idle(false);
}
}
void SuspendHandlerBase::lock(bool isLocked)
{
if (!_isSuspended)
{
if (isLocked)
{
if (!_isLocked)
{
_isLocked = true;
Info(_log, "Screen lock event received");
emit lockedEvent(isLocked);
}
}
else
{
if (_isLocked)
{
Info(_log, "Screen unlock event received");
emit lockedEvent(isLocked);
_isLocked = false;
}
}
}
else
{
Debug(_log, "Screen lock event ignored - Hyperion is suspended");
}
}
#if defined(_WIN32)
SuspendHandlerWindows::SuspendHandlerWindows()
: _notifyHandle(NULL)
{
}
SuspendHandlerWindows::~SuspendHandlerWindows()
{
unregisterLockHandler();
unregisterSuspendHandler();
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool SuspendHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, qintptr* /*result*/)
#else
bool SuspendHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, long int* /*result*/)
#endif
{
MSG* msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_WTSSESSION_CHANGE:
switch (msg->wParam)
{
case WTS_SESSION_LOCK:
emit lock(true);
return true;
break;
case WTS_SESSION_UNLOCK:
emit lock(false);
return true;
break;
}
break;
case WM_POWERBROADCAST:
switch (msg->wParam)
{
case PBT_APMRESUMESUSPEND:
emit suspend(false);
return true;
break;
case PBT_APMSUSPEND:
emit suspend(true);
return true;
break;
}
break;
}
return false;
}
bool SuspendHandlerWindows::registerSuspendHandler()
{
bool isRegistered{ _isSuspendRegistered };
if (!_isSuspendRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
_notifyHandle = RegisterSuspendResumeNotification(handle, DEVICE_NOTIFY_WINDOW_HANDLE);
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->installNativeEventFilter(this);
}
else
{
Error(_log, "Could not register for suspend/resume events!");
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerSuspendHandler();
}
}
return isRegistered;
}
void SuspendHandlerWindows::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->removeNativeEventFilter(this);
UnregisterSuspendResumeNotification(_notifyHandle);
}
_notifyHandle = NULL;
SuspendHandlerBase::unregisterSuspendHandler();
}
}
bool SuspendHandlerWindows::registerLockHandler()
{
bool isRegistered{ _isLockRegistered };
if (!_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
if (WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION))
{
isRegistered = true;
}
else
{
Error(_log, "Could not register for lock/unlock events!");
}
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerLockHandler();
}
return isRegistered;
}
void SuspendHandlerWindows::unregisterLockHandler()
{
if (_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
WTSUnRegisterSessionNotification(handle);
SuspendHandlerBase::unregisterLockHandler();
}
}
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
#include <QDBusConnection>
struct dBusSignals
{
QString service;
QString path;
QString interface;
QString name;
};
typedef QMultiMap<QString, dBusSignals> DbusSignalsMap;
// Constants
namespace {
const DbusSignalsMap dbusSignals = {
//system signals
{"Suspend", {"org.freedesktop.login1","/org/freedesktop/login1","org.freedesktop.login1.Manager","PrepareForSleep"}},
//Session signals
{"ScreenSaver", {"org.freedesktop.ScreenSaver","/org/freedesktop/ScreenSaver","org.freedesktop.ScreenSaver","ActiveChanged"}},
{"ScreenSaver", {"org.gnome.ScreenSaver","/org/gnome/ScreenSaver","org.gnome.ScreenSaver","ActiveChanged"}},
};
} //End of constants
SuspendHandlerLinux::SuspendHandlerLinux()
{
}
bool SuspendHandlerLinux::registerSuspendHandler()
{
bool isRegistered {_isSuspendRegistered};
if (!_isSuspendRegistered)
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(_log, "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (systemBus.connect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
{
Debug(_log, "Registered for suspend/resume events via service: %s", QSTRING_CSTR(service));
isRegistered = true;
}
else
{
Error(_log, "Could not register for suspend/resume events via service: %s", QSTRING_CSTR(service));
}
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerSuspendHandler();
}
}
return isRegistered;
}
void SuspendHandlerLinux::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(_log, "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (systemBus.disconnect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
{
Debug(_log, "Unregistered for suspend/resume events via service: %s", QSTRING_CSTR(service));
SuspendHandlerBase::unregisterSuspendHandler();
}
else
{
Error(_log, "Could not unregister for suspend/resume events via service: %s", QSTRING_CSTR(service));
}
}
}
}
bool SuspendHandlerLinux::registerLockHandler()
{
bool isRegistered {_isLockRegistered};
if (!_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "The lock/unlock feature is not supported by your system configuration");
}
else
{
DbusSignalsMap::const_iterator iter = dbusSignals.find("ScreenSaver");
while (iter != dbusSignals.end() && iter.key() == "ScreenSaver") {
QString service = iter.value().service;
if (sessionBus.connect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
{
Debug(_log, "Registered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isRegistered = true;
}
else
{
Error(_log, "Could not register for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
}
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerLockHandler();
}
return isRegistered;
}
void SuspendHandlerLinux::unregisterLockHandler()
{
bool isUnregistered {false};
if (_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "The lock/unlock feature is not supported by your system configuration");
}
else
{
DbusSignalsMap::const_iterator iter = dbusSignals.find("ScreenSaver");
while (iter != dbusSignals.end() && iter.key() == "ScreenSaver") {
QString service = iter.value().service;
if (sessionBus.disconnect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
{
Debug(_log, "Unregistered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isUnregistered = true;
}
else
{
Error(_log, "Could not unregister for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
if (isUnregistered)
{
SuspendHandlerBase::unregisterLockHandler();
}
}
}
}
#endif

View File

@ -1,127 +0,0 @@
#ifndef SUSPENDHANDLER_H
#define SUSPENDHANDLER_H
#include <QObject>
#include <QJsonDocument>
#if defined(_WIN32)
#include <QAbstractNativeEventFilter>
#include <QAbstractEventDispatcher>
#include <QWidget>
#include <windows.h>
#endif
#include <utils/settings.h>
class Logger;
class SuspendHandlerBase : public QObject {
Q_OBJECT
public:
SuspendHandlerBase();
~SuspendHandlerBase() override;
public slots:
void suspend(bool sleep);
void suspend();
void resume();
void toggleSuspend();
void idle(bool isIdle);
void toggleIdle();
void lock(bool isLocked);
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
signals:
void suspendEvent();
void resumeEvent();
void lockedEvent(bool);
void idleEvent(bool);
protected:
virtual bool registerSuspendHandler();
virtual void unregisterSuspendHandler();
virtual bool registerLockHandler();
virtual void unregisterLockHandler();
virtual bool registerSuspendApiHandler();
virtual void unregisterSuspendApiHandler();
virtual bool registerIdleApiHandler();
virtual void unregisterIdleApiHandler();
bool _isSuspendEnabled;
bool _isLockEnabled;
bool _isSuspendApiEnabled;
bool _isIdleApiEnabled;
bool _isSuspendOnLock;
bool _isSuspendRegistered;
bool _isLockRegistered;
bool _isSuspendApiRegistered;
bool _isIdleApiRegistered;
Logger * _log {};
private:
bool _isSuspended;
bool _isIdle;
bool _isLocked;
};
#if defined(_WIN32)
class SuspendHandlerWindows : public SuspendHandlerBase, public QAbstractNativeEventFilter {
public:
SuspendHandlerWindows();
~SuspendHandlerWindows() override;
protected:
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result) override;
#else
bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
#endif
private:
bool registerSuspendHandler() override;
void unregisterSuspendHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
QWidget _widget;
HPOWERNOTIFY _notifyHandle;
};
using SuspendHandler = SuspendHandlerWindows;
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
class SuspendHandlerLinux : public SuspendHandlerBase {
Q_OBJECT
public:
SuspendHandlerLinux();
private:
bool registerSuspendHandler() override;
void unregisterSuspendHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
};
using SuspendHandler = SuspendHandlerLinux;
#else
using SuspendHandler = SuspendHandlerBase;
#endif
#endif // SUSPENDHANDLER_H

View File

@ -97,7 +97,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
#ifdef ENABLE_CEC #ifdef ENABLE_CEC
, _cecHandler(nullptr) , _cecHandler(nullptr)
#endif #endif
, _suspendHandler(nullptr) , _eventHandler(nullptr)
, _osEventHandler(nullptr)
, _currVideoMode(VideoMode::VIDEO_2D) , _currVideoMode(VideoMode::VIDEO_2D)
{ {
HyperionDaemon::daemon = this; HyperionDaemon::daemon = this;
@ -119,8 +120,6 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
handleSettingsUpdate(settings::LOGGER, getSetting(settings::LOGGER)); handleSettingsUpdate(settings::LOGGER, getSetting(settings::LOGGER));
} }
createCecHandler();
//Create MdnsBrowser singleton in main tread to ensure thread affinity during destruction //Create MdnsBrowser singleton in main tread to ensure thread affinity during destruction
#ifdef ENABLE_MDNS #ifdef ENABLE_MDNS
MdnsBrowser::getInstance(); MdnsBrowser::getInstance();
@ -178,7 +177,7 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
startNetworkServices(); startNetworkServices();
// init events services // init events services
handleSettingsUpdate(settings::SYSTEMEVENTS, getSetting(settings::SYSTEMEVENTS)); handleSettingsUpdate(settings::OSEVENTS, getSetting(settings::OSEVENTS));
} }
HyperionDaemon::~HyperionDaemon() HyperionDaemon::~HyperionDaemon()
@ -234,7 +233,10 @@ void HyperionDaemon::handleInstanceStateChange(InstanceState state, quint8 insta
connect(_sslWebserver, &WebServer::publishService, _mDNSProvider, &MdnsProvider::publishService); connect(_sslWebserver, &WebServer::publishService, _mDNSProvider, &MdnsProvider::publishService);
#endif #endif
sslWsThread->start(); sslWsThread->start();
//startCecHandler();
} }
break; break;
case InstanceState::H_STOPPED: case InstanceState::H_STOPPED:
@ -263,6 +265,8 @@ void HyperionDaemon::freeObjects()
{ {
Debug(_log, "Cleaning up Hyperion before quit."); Debug(_log, "Cleaning up Hyperion before quit.");
stopCecHandler();
#ifdef ENABLE_MDNS #ifdef ENABLE_MDNS
if (_mDNSProvider != nullptr) if (_mDNSProvider != nullptr)
{ {
@ -333,19 +337,7 @@ void HyperionDaemon::freeObjects()
_sslWebserver = nullptr; _sslWebserver = nullptr;
} }
#ifdef ENABLE_CEC delete _osEventHandler;
if (_cecHandler != nullptr)
{
auto cecHandlerThread = _cecHandler->thread();
cecHandlerThread->quit();
cecHandlerThread->wait();
delete cecHandlerThread;
delete _cecHandler;
_cecHandler = nullptr;
}
#endif
delete _suspendHandler;
// stop Hyperions (non blocking) // stop Hyperions (non blocking)
_instanceManager->stopAll(); _instanceManager->stopAll();
@ -693,19 +685,6 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
else if (settingsType == settings::V4L2) else if (settingsType == settings::V4L2)
{ {
#ifdef ENABLE_CEC
const QJsonObject& grabberConfig = config.object();
if (_cecHandler != nullptr && grabberConfig["cecDetection"].toBool(false))
{
QMetaObject::invokeMethod(_cecHandler, "start", Qt::QueuedConnection);
}
else
{
QMetaObject::invokeMethod(_cecHandler, "stop", Qt::QueuedConnection);
}
#endif
#if defined(ENABLE_V4L2) || defined(ENABLE_MF) #if defined(ENABLE_V4L2) || defined(ENABLE_MF)
if (_videoGrabber == nullptr) if (_videoGrabber == nullptr)
{ {
@ -743,18 +722,28 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
Debug(_log, "Audio capture not supported on this platform"); Debug(_log, "Audio capture not supported on this platform");
#endif #endif
} }
else if (settingsType == settings::SYSTEMEVENTS) else if (settingsType == settings::OSEVENTS)
{ {
// Create suspend handler if (_eventHandler == nullptr)
if (_suspendHandler == nullptr)
{ {
_suspendHandler = new SuspendHandler(); _eventHandler = EventHandler::getInstance();
_suspendHandler->handleSettingsUpdate(settings::SYSTEMEVENTS, getSetting(settings::SYSTEMEVENTS)); Debug(_log, "Hyperion event handler created");
connect(this, &HyperionDaemon::settingsChanged, _suspendHandler, &SuspendHandler::handleSettingsUpdate);
Debug(_log, "SuspendHandler created");
} }
// Create suspend handler
if (_osEventHandler == nullptr)
{
_osEventHandler = new OsEventHandler();
_osEventHandler->handleSettingsUpdate(settings::OSEVENTS, getSetting(settings::OSEVENTS));
connect(this, &HyperionDaemon::settingsChanged, _osEventHandler, &OsEventHandler::handleSettingsUpdate);
Debug(_log, "Operating System event handler created");
}
}
else if (settingsType == settings::CECEVENTS)
{
startCecHandler();
} }
} }
@ -929,26 +918,47 @@ void HyperionDaemon::createGrabberOsx(const QJsonObject& grabberConfig)
#endif #endif
} }
void HyperionDaemon::createCecHandler() void HyperionDaemon::startCecHandler()
{ {
#if defined(ENABLE_V4L2) && defined(ENABLE_CEC) #if defined(ENABLE_CEC)
_cecHandler = new CECHandler; if (_cecHandler == nullptr)
{
_cecHandler = new CECHandler;
QThread* thread = new QThread(this); QThread* cecHandlerThread = new QThread(this);
thread->setObjectName("CECThread"); cecHandlerThread->setObjectName("CECThread");
_cecHandler->moveToThread(thread); _cecHandler->moveToThread(cecHandlerThread);
thread->start();
connect(_cecHandler, &CECHandler::cecEvent, [&](CECEvent event) { connect(cecHandlerThread, &QThread::started, _cecHandler, &CECHandler::start);
if (_videoGrabber != nullptr) connect(cecHandlerThread, &QThread::finished, _cecHandler, &CECHandler::stop);
{
_videoGrabber->handleCecEvent(event);
}
});
Info(_log, "CEC handler created"); cecHandlerThread->start();
_cecHandler->handleSettingsUpdate(settings::CECEVENTS, getSetting(settings::CECEVENTS));
connect(this, &HyperionDaemon::settingsChanged, _cecHandler, &CECHandler::handleSettingsUpdate);
Info(_log, "CEC event handler created");
}
#else #else
Debug(_log, "The CEC handler is not supported on this platform"); Debug(_log, "The CEC handler is not supported on this platform");
#endif #endif
} }
void HyperionDaemon::stopCecHandler()
{
#if defined(ENABLE_CEC)
if (_cecHandler != nullptr)
{
disconnect(_cecHandler, &CECHandler::signalEvent, _eventHandler, &EventHandler::handleEvent);
auto cecHandlerThread = _cecHandler->thread();
cecHandlerThread->quit();
cecHandlerThread->wait();
delete cecHandlerThread;
delete _cecHandler;
_cecHandler = nullptr;
}
Info(_log, "CEC handler stopped");
#endif
}

View File

@ -75,7 +75,8 @@
#include <utils/settings.h> #include <utils/settings.h>
#include <utils/Components.h> #include <utils/Components.h>
#include "SuspendHandler.h" #include <events/EventHandler.h>
#include <events/OsEventHandler.h>
class HyperionIManager; class HyperionIManager;
class SysTray; class SysTray;
@ -103,18 +104,13 @@ class HyperionDaemon : public QObject
public: public:
HyperionDaemon(const QString& rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode = false); HyperionDaemon(const QString& rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode = false);
~HyperionDaemon(); ~HyperionDaemon() override;
/// ///
/// @brief Get webserver pointer (systray) /// @brief Get webserver pointer (systray)
/// ///
WebServer *getWebServerInstance() { return _webserver; } WebServer *getWebServerInstance() { return _webserver; }
///
/// @brief Get suspense handler pointer
///
SuspendHandler* getSuspendHandlerInstance() { return _suspendHandler; }
/// ///
/// @brief Get the current videoMode /// @brief Get the current videoMode
/// ///
@ -185,10 +181,12 @@ private:
void createGrabberX11(const QJsonObject & grabberConfig); void createGrabberX11(const QJsonObject & grabberConfig);
void createGrabberXcb(const QJsonObject & grabberConfig); void createGrabberXcb(const QJsonObject & grabberConfig);
void createGrabberQt(const QJsonObject & grabberConfig); void createGrabberQt(const QJsonObject & grabberConfig);
void createCecHandler();
void createGrabberDx(const QJsonObject & grabberConfig); void createGrabberDx(const QJsonObject & grabberConfig);
void createGrabberAudio(const QJsonObject & grabberConfig); void createGrabberAudio(const QJsonObject & grabberConfig);
void startCecHandler();
void stopCecHandler();
Logger* _log; Logger* _log;
HyperionIManager* _instanceManager; HyperionIManager* _instanceManager;
AuthManager* _authManager; AuthManager* _authManager;
@ -216,7 +214,8 @@ private:
#ifdef ENABLE_CEC #ifdef ENABLE_CEC
CECHandler* _cecHandler; CECHandler* _cecHandler;
#endif #endif
SuspendHandler* _suspendHandler; EventHandler* _eventHandler;
OsEventHandler* _osEventHandler;
#if defined(ENABLE_FLATBUF_SERVER) #if defined(ENABLE_FLATBUF_SERVER)
FlatBufferServer* _flatBufferServer; FlatBufferServer* _flatBufferServer;

View File

@ -1,5 +1,4 @@
#include <cassert> #include <cassert>
#include <csignal>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -46,40 +45,12 @@
#include "hyperiond.h" #include "hyperiond.h"
#include "systray.h" #include "systray.h"
#include "SuspendHandler.h" #include <events/EventHandler.h>
using namespace commandline; using namespace commandline;
#define PERM0664 (QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther | QFileDevice::WriteOwner | QFileDevice::WriteGroup) #define PERM0664 (QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther | QFileDevice::WriteOwner | QFileDevice::WriteGroup)
#ifndef _WIN32
void signal_handler(int signum)
{
HyperionDaemon* hyperiond = HyperionDaemon::getInstance();
SuspendHandler* suspendHandler = hyperiond->getSuspendHandlerInstance();
if (signum == SIGCHLD)
{
// only quit when a registered child process is gone
// currently this feature is not active ...
}
else if (signum == SIGUSR1)
{
if (suspendHandler != nullptr)
{
suspendHandler->suspend();
}
}
else if (signum == SIGUSR2)
{
if (suspendHandler != nullptr)
{
suspendHandler->resume();
}
}
}
#endif
QCoreApplication* createApplication(int &argc, char *argv[]) QCoreApplication* createApplication(int &argc, char *argv[])
{ {
bool isGuiApp = false; bool isGuiApp = false;
@ -150,11 +121,6 @@ int main(int argc, char** argv)
DefaultSignalHandler::install(); DefaultSignalHandler::install();
#ifndef _WIN32
signal(SIGCHLD, signal_handler);
signal(SIGUSR1, signal_handler);
signal(SIGUSR2, signal_handler);
#endif
// force the locale // force the locale
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
QLocale::setDefault(QLocale::c()); QLocale::setDefault(QLocale::c());

View File

@ -22,10 +22,11 @@
#endif #endif
#include <webserver/WebServer.h> #include <webserver/WebServer.h>
#include <hyperion/PriorityMuxer.h> #include <hyperion/PriorityMuxer.h>
#include <events/EventHandler.h>
#include "hyperiond.h" #include "hyperiond.h"
#include "systray.h" #include "systray.h"
#include "SuspendHandler.h"
SysTray::SysTray(HyperionDaemon *hyperiond) SysTray::SysTray(HyperionDaemon *hyperiond)
: QWidget() : QWidget()
@ -33,7 +34,6 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
, _hyperiond(hyperiond) , _hyperiond(hyperiond)
, _hyperion(nullptr) , _hyperion(nullptr)
, _instanceManager(HyperionIManager::getInstance()) , _instanceManager(HyperionIManager::getInstance())
, _suspendHandler (hyperiond->getSuspendHandlerInstance())
, _webPort(8090) , _webPort(8090)
{ {
Q_INIT_RESOURCE(resources); Q_INIT_RESOURCE(resources);
@ -84,13 +84,16 @@ void SysTray::createTrayIcon()
restartAction->setIcon(QPixmap(":/restart.svg")); restartAction->setIcon(QPixmap(":/restart.svg"));
connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(12); }); connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(12); });
// TODO: Check if can be done with SystemEvents
suspendAction = new QAction(tr("&Suspend"), this); suspendAction = new QAction(tr("&Suspend"), this);
suspendAction->setIcon(QPixmap(":/suspend.svg")); suspendAction->setIcon(QPixmap(":/suspend.svg"));
connect(suspendAction, &QAction::triggered, _suspendHandler, QOverload<>::of(&SuspendHandler::suspend)); connect(suspendAction, &QAction::triggered, EventHandler::getInstance(), QOverload<>::of(&EventHandler::suspend));
resumeAction = new QAction(tr("&Resume"), this); resumeAction = new QAction(tr("&Resume"), this);
resumeAction->setIcon(QPixmap(":/resume.svg")); resumeAction->setIcon(QPixmap(":/resume.svg"));
connect(resumeAction, &QAction::triggered, _suspendHandler, &SuspendHandler::resume);
connect(resumeAction, &QAction::triggered, EventHandler::getInstance(), &EventHandler::resume);
colorAction = new QAction(tr("&Color"), this); colorAction = new QAction(tr("&Color"), this);
colorAction->setIcon(QPixmap(":/color.svg")); colorAction->setIcon(QPixmap(":/color.svg"));

View File

@ -12,7 +12,7 @@
#include <hyperion/Hyperion.h> #include <hyperion/Hyperion.h>
#include <hyperion/HyperionIManager.h> #include <hyperion/HyperionIManager.h>
#include "SuspendHandler.h" #include <events/EventHandler.h>
class HyperionDaemon; class HyperionDaemon;
@ -22,13 +22,13 @@ class SysTray : public QWidget
public: public:
SysTray(HyperionDaemon *hyperiond); SysTray(HyperionDaemon *hyperiond);
~SysTray(); ~SysTray() override;
public slots: public slots:
void showColorDialog(); void showColorDialog();
void setColor(const QColor & color); void setColor(const QColor & color);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event) override;
void settings() const; void settings() const;
#if defined(ENABLE_EFFECTENGINE) #if defined(ENABLE_EFFECTENGINE)
void setEffect(); void setEffect();
@ -42,7 +42,7 @@ private slots:
/// ///
/// @brief is called whenever the webserver changes the port /// @brief is called whenever the webserver changes the port
/// ///
void webserverPortChanged(quint16 port) { _webPort = port; }; void webserverPortChanged(quint16 port) { _webPort = port; }
/// ///
/// @brief is called whenever a hyperion instance state changes /// @brief is called whenever a hyperion instance state changes
@ -84,6 +84,4 @@ private:
Hyperion *_hyperion; Hyperion *_hyperion;
HyperionIManager *_instanceManager; HyperionIManager *_instanceManager;
quint16 _webPort; quint16 _webPort;
SuspendHandler *_suspendHandler;
}; };