Merge remote-tracking branch 'origin/master' into ftdi_basic

This commit is contained in:
LordGrey
2024-05-25 23:35:13 +02:00
388 changed files with 20045 additions and 12428 deletions

View File

@@ -14,11 +14,15 @@
// qt includes
#include <QString>
class QTimer;
class JsonCB;
class JsonCallbacks;
class HyperionIManager;
const QString NO_AUTH = "No Authorization";
// Constants
namespace {
const char NO_AUTHORIZATION[] = "No Authorization";;
}
///
/// @brief API for Hyperion to be inherted from a child class with specific protocol implementations
@@ -31,205 +35,214 @@ const QString NO_AUTH = "No Authorization";
class API : public QObject
{
Q_OBJECT
Q_OBJECT
public:
#include <api/apiStructs.h>
// workaround Q_ARG std::map template issues
typedef std::map<int, registerData> MapRegister;
typedef QMap<QString, AuthManager::AuthDefinition> MapAuthDefs;
///
/// Constructor
///
///@ param The parent Logger
/// @param localConnection Is this a local network connection? Use utils/NetOrigin to check that
/// @param parent Parent QObject
///
API(Logger *log, bool localConnection, QObject *parent);
protected:
///
/// @brief Initialize the API
/// This call is REQUIRED!
///
void init();
///
/// @brief Set a single color
/// @param[in] priority The priority of the written color
/// @param[in] ledColor The color to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given color [ms]
/// @param[in] origin The setter
///
void setColor(int priority, const std::vector<uint8_t> &ledColors, int timeout_ms = -1, const QString &origin = "API", hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set a image
/// @param[in] data The command data
/// @param[in] comp The component that should be used
/// @param[out] replyMsg The replyMsg on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @return True on success
///
bool setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Clear a priority in the Muxer, if -1 all priorities are cleared
/// @param priority The priority to clear
/// @param replyMsg the message on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @return True on success
///
bool clearPriority(int priority, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set a new component state
/// @param comp The component name
/// @param compState The new state of the comp
/// @param replyMsg The reply on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @ return True on success
///
bool setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set a ledToImageMapping type
/// @param type mapping type string
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setLedMappingType(int type, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set the 2D/3D modes type
/// @param mode The VideoMode
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setVideoMode(VideoMode mode, hyperion::Components callerComp = hyperion::COMP_INVALID);
#if defined(ENABLE_EFFECTENGINE)
///
/// @brief Set an effect
/// @param dat The effect data
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// REQUIRED dat fields: effectName, priority, duration, origin
/// @return True on success else false
///
bool setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
#endif
///
/// @brief Set source auto select enabled or disabled
/// @param sate The new state
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setSourceAutoSelect(bool state, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set the visible priority to given priority
/// @param priority The priority to set
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setVisiblePriority(int priority, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Register a input or update the meta data of a previous register call
/// ATTENTION: Check unregisterInput() method description !!!
/// @param[in] priority The priority of the channel
/// @param[in] component The component of the channel
/// @param[in] origin Who set the channel (CustomString@IP)
/// @param[in] owner Specific owner string, might be empty
/// @param[in] callerComp The component that call this (e.g. PROTO/FLAT)
///
void registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp);
///
/// @brief Revoke a registerInput() call by priority. We maintain all registered priorities in this scope
/// ATTENTION: This is MANDATORY if you change (priority change) or stop(clear/timeout) DURING lifetime. If this class destructs it's not needed
/// @param priority The priority to unregister
///
void unregisterInput(int priority);
///
/// @brief Handle the instance switching
/// @param inst The requested instance
/// @return True on success else false
///
bool setHyperionInstance(quint8 inst);
// workaround Q_ARG std::map template issues
typedef std::map<int, registerData> MapRegister;
typedef QMap<QString, AuthManager::AuthDefinition> MapAuthDefs;
///
/// @brief Check if Hyperion ist enabled
/// @return True when enabled else false
///
bool isHyperionEnabled();
/// Constructor
///
///@ param The parent Logger
/// @param localConnection Is this a local network connection? Use utils/NetOrigin to check that
/// @param parent Parent QObject
///
API(Logger *log, bool localConnection, QObject *parent);
///
/// @brief Get all instances data
/// @return The instance data
///
QVector<QVariantMap> getAllInstanceData();
protected:
///
/// @brief Initialize the API
/// This call is REQUIRED!
///
void init();
///
/// @brief Start instance
/// @param index The instance index
/// @param tan The tan
/// @return True on success else false
///
bool startInstance(quint8 index, int tan = 0);
virtual void stopDataConnections() = 0;
///
/// @brief Stop instance
/// @param index The instance index
///
void stopInstance(quint8 index);
///
/// @brief Set a single color
/// @param[in] priority The priority of the written color
/// @param[in] ledColor The color to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given color [ms]
/// @param[in] origin The setter
///
void setColor(int priority, const std::vector<uint8_t> &ledColors, int timeout_ms = -1, const QString &origin = "API", hyperion::Components callerComp = hyperion::COMP_INVALID);
//////////////////////////////////
/// AUTH / ADMINISTRATION METHODS
//////////////////////////////////
///
/// @brief Set a image
/// @param[in] data The command data
/// @param[in] comp The component that should be used
/// @param[out] replyMsg The replyMsg on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @return True on success
///
bool setImage(ImageCmdData &data, hyperion::Components comp, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Delete instance. Requires ADMIN ACCESS
/// @param index The instance index
/// @param replyMsg The reply Msg
/// @return False with reply
///
bool deleteInstance(quint8 index, QString &replyMsg);
///
/// @brief Clear a priority in the Muxer, if -1 all priorities are cleared
/// @param priority The priority to clear
/// @param replyMsg the message on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @return True on success
///
bool clearPriority(int priority, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Create instance. Requires ADMIN ACCESS
/// @param name With given name
/// @return False with reply
///
QString createInstance(const QString &name);
///
/// @brief Set a new component state
/// @param comp The component name
/// @param compState The new state of the comp
/// @param replyMsg The reply on failure
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// @ return True on success
///
bool setComponentState(const QString &comp, bool &compState, QString &replyMsg, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Rename an instance. Requires ADMIN ACCESS
/// @param index The instance index
/// @param name With given name
/// @return False with reply
///
QString setInstanceName(quint8 index, const QString &name);
///
/// @brief Set a ledToImageMapping type
/// @param type mapping type string
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setLedMappingType(int type, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set the 2D/3D modes type
/// @param mode The VideoMode
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setVideoMode(VideoMode mode, hyperion::Components callerComp = hyperion::COMP_INVALID);
#if defined(ENABLE_EFFECTENGINE)
///
/// @brief Delete an effect. Requires ADMIN ACCESS
/// @param name The effect name
/// @return True on success else false
///
QString deleteEffect(const QString &name);
///
/// @brief Delete an effect. Requires ADMIN ACCESS
/// @param name The effect name
/// @return True on success else false
///
QString saveEffect(const QJsonObject &data);
///
/// @brief Set an effect
/// @param dat The effect data
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// REQUIRED dat fields: effectName, priority, duration, origin
/// @return True on success else false
///
bool setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
#endif
///
/// @brief Save settings object. Requires ADMIN ACCESS
/// @param data The data object
///
///
/// @brief Set source auto select enabled or disabled
/// @param sate The new state
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setSourceAutoSelect(bool state, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set the visible priority to given priority
/// @param priority The priority to set
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
///
void setVisiblePriority(int priority, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Register a input or update the meta data of a previous register call
/// ATTENTION: Check unregisterInput() method description !!!
/// @param[in] priority The priority of the channel
/// @param[in] component The component of the channel
/// @param[in] origin Who set the channel (CustomString@IP)
/// @param[in] owner Specific owner string, might be empty
/// @param[in] callerComp The component that call this (e.g. PROTO/FLAT)
///
void registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp);
///
/// @brief Revoke a registerInput() call by priority. We maintain all registered priorities in this scope
/// ATTENTION: This is MANDATORY if you change (priority change) or stop(clear/timeout) DURING lifetime. If this class destructs it's not needed
/// @param priority The priority to unregister
///
void unregisterInput(int priority);
///
/// @brief Handle the instance switching
/// @param inst The requested instance
/// @return True on success else false
///
bool setHyperionInstance(quint8 inst);
///
/// @brief Check if Hyperion ist enabled
/// @return True when enabled else false
///
bool isHyperionEnabled();
///
/// @brief Get all instances data
/// @return The instance data
///
QVector<QVariantMap> getAllInstanceData() const;
///
/// @brief Get the current instances index
/// @return The instance index set
///
quint8 getCurrentInstanceIndex() const { return _currInstanceIndex; }
///
/// @brief Start instance
/// @param index The instance index
/// @param tan The tan
/// @return True on success else false
///
bool startInstance(quint8 index, int tan = 0);
///
/// @brief Stop instance
/// @param index The instance index
///
void stopInstance(quint8 index);
//////////////////////////////////
/// AUTH / ADMINISTRATION METHODS
//////////////////////////////////
///
/// @brief Delete instance. Requires ADMIN ACCESS
/// @param index The instance index
/// @param replyMsg The reply Msg
/// @return False with reply
///
bool deleteInstance(quint8 index, QString &replyMsg);
///
/// @brief Create instance. Requires ADMIN ACCESS
/// @param name With given name
/// @return False with reply
///
QString createInstance(const QString &name);
///
/// @brief Rename an instance. Requires ADMIN ACCESS
/// @param index The instance index
/// @param name With given name
/// @return False with reply
///
QString setInstanceName(quint8 index, const QString &name);
#if defined(ENABLE_EFFECTENGINE)
///
/// @brief Delete an effect. Requires ADMIN ACCESS
/// @param name The effect name
/// @return True on success else false
///
QString deleteEffect(const QString &name);
///
/// @brief Delete an effect. Requires ADMIN ACCESS
/// @param name The effect name
/// @return True on success else false
///
QString saveEffect(const QJsonObject &data);
#endif
///
/// @brief Save settings object. Requires ADMIN ACCESS
/// @param data The data object
///
bool saveSettings(const QJsonObject &data);
///
@@ -238,171 +251,189 @@ protected:
///
bool restoreSettings(const QJsonObject &data);
///
/// @brief Test if we are authorized to use the interface
/// @return The result
///
bool isAuthorized() { return _authorized; };
///
/// @brief Set the authorizationn state
/// @param authorized True, if authorized
///
void setAuthorization(bool authorized) { _authorized = authorized; }
///
/// @brief Test if we are authorized to use the admin interface
/// @return The result
///
bool isAdminAuthorized() { return _adminAuthorized; };
///
/// @brief Test if we are authorized to use the interface
/// @return The result
///
bool isAuthorized() const { return _authorized; }
///
/// @brief Update the Password of Hyperion. Requires ADMIN ACCESS
/// @param password Old password
/// @param newPassword New password
/// @return True on success else false
///
bool updateHyperionPassword(const QString &password, const QString &newPassword);
///
/// @brief Set the authorizationn state for admin activities
/// @param authorized True, if authorized
///
void setAdminAuthorization(bool adminAuthorized) { _adminAuthorized = adminAuthorized; }
///
/// @brief Get a new token from AuthManager. Requires ADMIN ACCESS
/// @param comment The comment of the request
/// @param def The final definition
/// @return Empty string on success else error message
///
QString createToken(const QString &comment, AuthManager::AuthDefinition &def);
///
/// @brief Test if we are authorized to use admin activites
/// @return The result
///
bool isAdminAuthorized() const { return _adminAuthorized; }
///
/// @brief Rename a token by given id. Requires ADMIN ACCESS
/// @param id The id of the token
/// @param comment The new comment
/// @return Empty string on success else error message
///
QString renameToken(const QString &id, const QString &comment);
///
/// @brief Return, if connection is from local network segment
/// @return The result
///
bool islocalConnection() const { return _localConnection; }
///
/// @brief Delete a token by given id. Requires ADMIN ACCESS
/// @param id The id of the token
/// @return Empty string on success else error message
///
QString deleteToken(const QString &id);
///
/// @brief Update the Password of Hyperion. Requires ADMIN ACCESS
/// @param password Old password
/// @param newPassword New password
/// @return True on success else false
///
bool updateHyperionPassword(const QString &password, const QString &newPassword);
///
/// @brief Set a new token request
/// @param comment The comment
/// @param id The id
///
/// @brief Get a new token from AuthManager. Requires ADMIN ACCESS
/// @param comment The comment of the request
/// @param def The final definition
/// @return Empty string on success else error message
///
QString createToken(const QString &comment, AuthManager::AuthDefinition &def);
///
/// @brief Rename a token by given id. Requires ADMIN ACCESS
/// @param tokenId The id of the token
/// @param comment The new comment
/// @return Empty string on success else error message
///
QString renameToken(const QString &tokenId, const QString &comment);
///
/// @brief Delete a token by given id. Requires ADMIN ACCESS
/// @param tokenId The id of the token
/// @return Empty string on success else error message
///
QString deleteToken(const QString &tokenId);
///
/// @brief Set a new token request
/// @param comment The comment
/// @param tokenId The id of the token
/// @param tan The tan
///
void setNewTokenRequest(const QString &comment, const QString &id, const int &tan);
///
void setNewTokenRequest(const QString &comment, const QString &tokenId, const int &tan);
///
/// @brief Cancel new token request
/// @param comment The comment
/// @param id The id
///
void cancelNewTokenRequest(const QString &comment, const QString &id);
///
/// @brief Cancel new token request
/// @param comment The comment
/// @param tokenId The id of the token
///
void cancelNewTokenRequest(const QString &comment, const QString &tokenId);
///
/// @brief Handle a pending token request. Requires ADMIN ACCESS
/// @param id The id fo the request
/// @param accept True when it should be accepted, else false
/// @return True on success
bool handlePendingTokenRequest(const QString &id, bool accept);
///
/// @brief Get the current List of Tokens. Requires ADMIN ACCESS
/// @param def returns the defintions
/// @return True on success
///
bool getTokenList(QVector<AuthManager::AuthDefinition> &def);
///
/// @brief Get all current pending token requests. Requires ADMIN ACCESS
/// @return True on success
///
bool getPendingTokenRequests(QVector<AuthManager::AuthDefinition> &map);
///
/// @brief Is User Token Authorized. On success this will grant acces to API and ADMIN API
/// @param userToken The user Token
/// @return True on succes
///
bool isUserTokenAuthorized(const QString &userToken);
///
/// @brief Get the current User Token (session token). Requires ADMIN ACCESS
/// @param userToken The user Token
/// @return True on success
///
bool getUserToken(QString &userToken);
///
/// @brief Is a token authorized. On success this will grant acces to the API (NOT ADMIN API)
/// @param token The user Token
///
/// @brief Handle a pending token request. Requires ADMIN ACCESS
/// @param tokenId The id fo the request
/// @param accept True when it should be accepted, else false
/// @return True on success
///
bool isTokenAuthorized(const QString &token);
bool handlePendingTokenRequest(const QString &tokenId, bool accept);
///
/// @brief Is User authorized. On success this will grant acces to the API and ADMIN API
/// @param password The password of the User
/// @return True if authorized
///
bool isUserAuthorized(const QString &password);
///
/// @brief Get the current List of Tokens. Requires ADMIN ACCESS
/// @param def returns the defintions
/// @return True on success
///
bool getTokenList(QVector<AuthManager::AuthDefinition> &def);
///
/// @brief Test if Hyperion has the default PW
/// @return The result
///
bool hasHyperionDefaultPw();
///
/// @brief Get all current pending token requests. Requires ADMIN ACCESS
/// @return True on success
///
bool getPendingTokenRequests(QVector<AuthManager::AuthDefinition> &map);
///
/// @brief Logout revokes all authorizations
///
void logout();
///
/// @brief Is User Token Authorized. On success this will grant acces to API and ADMIN API
/// @param userToken The user Token
/// @return True on succes
///
bool isUserTokenAuthorized(const QString &userToken);
/// Reflect auth status of this client
bool _authorized;
bool _adminAuthorized;
///
/// @brief Get the current User Token (session token). Requires ADMIN ACCESS
/// @param userToken The user Token
/// @return True on success
///
bool getUserToken(QString &userToken);
/// Is this a local connection
bool _localConnection;
///
/// @brief Is a token authorized. On success this will grant acces to the API (NOT ADMIN API)
/// @param token The user Token
/// @return True on success
///
bool isTokenAuthorized(const QString &token);
AuthManager *_authManager;
HyperionIManager *_instanceManager;
///
/// @brief Is User authorized. On success this will grant acces to the API and ADMIN API
/// @param password The password of the User
/// @return True if authorized
///
bool isUserAuthorized(const QString &password);
Logger *_log;
Hyperion *_hyperion;
///
/// @brief Test if Hyperion has the default PW
/// @return The result
///
bool hasHyperionDefaultPw();
///
/// @brief Logout revokes all authorizations
///
void logout();
AuthManager *_authManager;
HyperionIManager *_instanceManager;
Logger *_log;
Hyperion *_hyperion;
signals:
///
/// @brief The API might decide to block connections for security reasons, this emitter should close the socket
///
void forceClose();
///
/// @brief The API might decide to block connections for security reasons, this emitter should close the socket
///
void forceClose();
///
/// @brief Emits whenever a new Token request is pending. This signal is just active when ADMIN ACCESS has been granted
/// @param id The id of the request
/// @param comment The comment of the request; If the commen is EMPTY the request has been revoked by the caller. So remove it from the pending list
///
void onPendingTokenRequest(const QString &id, const QString &comment);
///
/// @brief Emits whenever a new Token request is pending. This signal is just active when ADMIN ACCESS has been granted
/// @param tokenId The id of the request
/// @param comment The comment of the request; If the commen is EMPTY the request has been revoked by the caller. So remove it from the pending list
///
void onPendingTokenRequest(const QString &tokenId, const QString &comment);
///
/// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance it will emit.
/// @param success If true the request was accepted else false and no token was created
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
/// @param tan The tan that was part of the request
///
void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
///
/// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance it will emit.
/// @param success If true the request was accepted else false and no token was created
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param tokenId The id that was part of the request
/// @param tan The tan that was part of the request
///
void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &tokenId, const int &tan);
///
/// @brief Handle emits from HyperionIManager of startInstance request, just if QObject matches with this instance it will emit.
/// @param tan The tan that was part of the request
///
void onStartInstanceResponse(const int &tan);
///
/// @brief Handle emits from HyperionIManager of startInstance request, just if QObject matches with this instance it will emit.
/// @param tan The tan that was part of the request
///
void onStartInstanceResponse(const int &tan);
private:
void stopDataConnectionss();
// Contains all active register call data
std::map<int, registerData> _activeRegisters;
/// Reflect authorization status of this client
bool _authorized;
bool _adminAuthorized;
// current instance index
quint8 _currInstanceIndex;
/// Is this a local connection
bool _localConnection;
// Contains all active register call data
std::map<int, registerData> _activeRegisters;
// current instance index
quint8 _currInstanceIndex;
};

View File

@@ -2,18 +2,24 @@
// parent class
#include <api/API.h>
#include <api/JsonApiCommand.h>
#include <events/EventEnum.h>
// hyperion includes
#include <utils/Components.h>
#include <hyperion/Hyperion.h>
#include <hyperion/HyperionIManager.h>
#include <utils/RgbChannelAdjustment.h>
// qt includes
#include <QJsonObject>
#include <QString>
#include <QSharedPointer>
#include <QScopedPointer>
class QTimer;
class JsonCB;
class JsonCallbacks;
class AuthManager;
class JsonAPI : public API
@@ -45,40 +51,24 @@ public:
void initialize();
public slots:
///
/// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled)
/// @param ledColors The current led colors
///
void streamLedcolorsUpdate(const std::vector<ColorRgb> &ledColors);
///
/// @brief Push images whenever hyperion emits (if enabled)
/// @param image The current image
///
void setImage(const Image<ColorRgb> &image);
///
/// @brief Process and push new log messages from logger (if enabled)
///
void incommingLogMessage(const Logger::T_LOG_MESSAGE &);
private slots:
///
/// @brief Handle emits from API of a new Token request.
/// @param id The id of the request
/// @param identifier The identifier of the request
/// @param comment The comment which needs to be accepted
///
void newPendingTokenRequest(const QString &id, const QString &comment);
void issueNewPendingTokenRequest(const QString &identifier, const QString &comment);
///
/// @brief Handle emits from AuthManager of accepted/denied/timeouts token request, just if QObject matches with this instance we are allowed to send response.
/// @param success If true the request was accepted else false and no token was created
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
/// @param identifier The identifier that was part of the request
/// @param tan The tan that was part of the request
///
void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &identifier, const int &tan);
///
/// @brief Handle whenever the state of a instance (HyperionIManager) changes according to enum instanceState
@@ -100,51 +90,14 @@ signals:
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);
///
/// 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();
void signalEvent(Event event);
private:
// true if further callbacks are forbidden (http)
bool _noListener;
/// The peer address of the client
QString _peerAddress;
// The JsonCB instance which handles data subscription/notifications
JsonCB *_jsonCB;
// streaming buffers
QJsonObject _streaming_leds_reply;
QJsonObject _streaming_image_reply;
QJsonObject _streaming_logging_reply;
/// flag to determine state of log streaming
bool _streaming_logging_activated;
/// timer for led color refresh
QTimer *_ledStreamTimer;
/// led stream connection handle
QMetaObject::Connection _ledStreamConnection;
/// the current streaming led values
std::vector<ColorRgb> _currentLedValues;
void handleCommand(const JsonApiCommand& cmd, const QJsonObject &message);
void handleInstanceCommand(const JsonApiCommand& cmd, const QJsonObject &message);
///
/// @brief Handle the switches of Hyperion instances
@@ -159,14 +112,14 @@ private:
///
/// @param message the incoming message
///
void handleColorCommand(const QJsonObject &message, const QString &command, int tan);
void handleColorCommand(const QJsonObject& message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Image message
///
/// @param message the incoming message
///
void handleImageCommand(const QJsonObject &message, const QString &command, int tan);
void handleImageCommand(const QJsonObject &message, const JsonApiCommand& cmd);
#if defined(ENABLE_EFFECTENGINE)
///
@@ -174,21 +127,21 @@ private:
///
/// @param message the incoming message
///
void handleEffectCommand(const QJsonObject &message, const QString &command, int tan);
void handleEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Effect message (Write JSON Effect)
///
/// @param message the incoming message
///
void handleCreateEffectCommand(const QJsonObject &message, const QString &command, int tan);
void handleCreateEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Effect message (Delete JSON Effect)
///
/// @param message the incoming message
///
void handleDeleteEffectCommand(const QJsonObject &message, const QString &command, int tan);
void handleDeleteEffectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
#endif
///
@@ -196,158 +149,250 @@ private:
///
/// @param message the incoming message
///
void handleSysInfoCommand(const QJsonObject &message, const QString &command, int tan);
void handleSysInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Server info message
///
/// @param message the incoming message
///
void handleServerInfoCommand(const QJsonObject &message, const QString &command, int tan);
void handleServerInfoCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Clear message
///
/// @param message the incoming message
///
void handleClearCommand(const QJsonObject &message, const QString &command, int tan);
void handleClearCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Clearall message
///
/// @param message the incoming message
///
void handleClearallCommand(const QJsonObject &message, const QString &command, int tan);
void handleClearallCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Adjustment message
///
/// @param message the incoming message
///
void handleAdjustmentCommand(const QJsonObject &message, const QString &command, int tan);
void handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON SourceSelect message
///
/// @param message the incoming message
///
void handleSourceSelectCommand(const QJsonObject &message, const QString &command, int tan);
void handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON GetConfig message and check subcommand
///
/// @param message the incoming message
///
void handleConfigCommand(const QJsonObject &message, const QString &command, int tan);
void handleConfigCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON GetSchema message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleSchemaGetCommand(const QJsonObject &message, const QString &command, int tan);
void handleSchemaGetCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON SetConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleConfigSetCommand(const QJsonObject &message, const QString &command, int tan);
void handleConfigSetCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON RestoreConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleConfigRestoreCommand(const QJsonObject &message, const QString &command, int tan);
void handleConfigRestoreCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON Component State message
///
/// @param message the incoming message
///
void handleComponentStateCommand(const QJsonObject &message, const QString &command, int tan);
void handleComponentStateCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Led Colors message
///
/// @param message the incoming message
///
void handleLedColorsCommand(const QJsonObject &message, const QString &command, int tan);
void handleLedColorsCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Logging message
///
/// @param message the incoming message
///
void handleLoggingCommand(const QJsonObject &message, const QString &command, int tan);
void handleLoggingCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Processing message
///
/// @param message the incoming message
///
void handleProcessingCommand(const QJsonObject &message, const QString &command, int tan);
void handleProcessingCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON VideoMode message
///
/// @param message the incoming message
///
void handleVideoModeCommand(const QJsonObject &message, const QString &command, int tan);
void handleVideoModeCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON plugin message
///
/// @param message the incoming message
///
void handleAuthorizeCommand(const QJsonObject &message, const QString &command, int tan);
void handleAuthorizeCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON instance message
///
/// @param message the incoming message
///
void handleInstanceCommand(const QJsonObject &message, const QString &command, int tan);
void handleInstanceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON Led Device message
///
/// @param message the incoming message
///
void handleLedDeviceCommand(const QJsonObject &message, const QString &command, int tan);
void handleLedDeviceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message regarding Input Sources (Grabbers)
///
/// @param message the incoming message
///
void handleInputSourceCommand(const QJsonObject& message, const QString& command, int tan);
void handleInputSourceCommand(const QJsonObject& message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message to request remote hyperion servers providing a given hyperion service
///
/// @param message the incoming message
///
void handleServiceCommand(const QJsonObject &message, const QString &command, int tan);
void handleServiceCommand(const QJsonObject &message, const JsonApiCommand& cmd);
/// Handle an incoming JSON message for actions related to the overall Hyperion system
///
/// @param message the incoming message
///
void handleSystemCommand(const QJsonObject &message, const QString &command, int tan);
void handleSystemCommand(const QJsonObject &message, const JsonApiCommand& cmd);
///
/// Handle an incoming JSON message of unknown type
///
void handleNotImplemented(const QString &command, int tan);
void applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment);
void applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment);
void applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel);
void applyTransforms(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment);
template<typename T>
void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(bool));
template<typename T>
void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double));
template<typename T>
void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t));
void handleTokenRequired(const JsonApiCommand& cmd);
void handleAdminRequired(const JsonApiCommand& cmd);
void handleNewPasswordRequired(const JsonApiCommand& cmd);
void handleLogout(const JsonApiCommand& cmd);
void handleNewPassword(const QJsonObject &message, const JsonApiCommand& cmd);
void handleCreateToken(const QJsonObject &message, const JsonApiCommand& cmd);
void handleRenameToken(const QJsonObject &message, const JsonApiCommand& cmd);
void handleDeleteToken(const QJsonObject &message, const JsonApiCommand& cmd);
void handleRequestToken(const QJsonObject &message, const JsonApiCommand& cmd);
void handleGetPendingTokenRequests(const JsonApiCommand& cmd);
void handleAnswerRequest(const QJsonObject &message, const JsonApiCommand& cmd);
void handleGetTokenList(const JsonApiCommand& cmd);
void handleLogin(const QJsonObject &message, const JsonApiCommand& cmd);
void handleLedDeviceDiscover(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
void handleLedDeviceGetProperties(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
void handleLedDeviceIdentify(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
void handleLedDeviceAddAuthorization(LedDevice& ledDevice, const QJsonObject& message, const JsonApiCommand& cmd);
QJsonObject getBasicCommandReply(bool success, const QString &command, int tan, InstanceCmd::Type isInstanceCmd) const;
///
/// Send a standard reply indicating success
///
void sendSuccessReply(const QString &command = "", int tan = 0);
void sendSuccessReply(const JsonApiCommand& cmd);
///
/// Send a standard reply indicating success
///
void sendSuccessReply(const QString &command = "", int tan = 0, InstanceCmd::Type isInstanceCmd = InstanceCmd::No);
///
/// Send a standard reply indicating success with data
///
void sendSuccessDataReply(const QJsonDocument &doc, const QString &command = "", int tan = 0);
void sendSuccessDataReply(const QJsonValue &infoData, const JsonApiCommand& cmd);
///
/// Send a standard reply indicating success with data
///
void sendSuccessDataReply(const QJsonValue &infoData, const QString &command = "", int tan = 0, InstanceCmd::Type isInstanceCmd = InstanceCmd::No);
///
/// Send a standard reply indicating success with data and error details
///
void sendSuccessDataReplyWithError(const QJsonValue &infoData, const JsonApiCommand& cmd, const QStringList& errorDetails = {});
///
/// Send a standard reply indicating success with data and error details
///
void sendSuccessDataReplyWithError(const QJsonValue &infoData, const QString &command = "", int tan = 0, const QStringList& errorDetails = {}, InstanceCmd::Type isInstanceCmd = InstanceCmd::No);
///
/// Send a message with data.
/// Note: To be used as a new message and not as a response to a previous request.
///
void sendNewRequest(const QJsonValue &infoData, const JsonApiCommand& cmd);
///
/// Send a message with data
/// Note: To be used as a new message and not as a response to a previous request.
///
void sendNewRequest(const QJsonValue &infoData, const QString &command, InstanceCmd::Type isInstanceCmd = InstanceCmd::No);
///
/// Send an error message back to the client
///
/// @param error String describing the error
///
void sendErrorReply(const QString &error, const QString &command = "", int tan = 0);
void sendErrorReply(const QString &error, const JsonApiCommand& cmd);
///
/// Send an error message back to the client
///
/// @param error String describing the error
/// @param errorDetails additional information detailing the error scenario
///
void sendErrorReply(const QString &error, const QStringList& errorDetails, const JsonApiCommand& cmd);
///
/// Send an error message back to the client
///
/// @param error String describing the error
/// @param errorDetails additional information detailing the error scenario
///
void sendErrorReply(const QString &error, const QStringList& errorDetails = {}, const QString &command = "", int tan = 0, InstanceCmd::Type isInstanceCmd = InstanceCmd::No);
void sendNoAuthorization(const JsonApiCommand& cmd);
///
/// @brief Kill all signal/slot connections to stop possible data emitter
///
void stopDataConnections();
void stopDataConnections() override;
static QString findCommand (const QString& jsonS);
static int findTan (const QString& jsonString);
// true if further callbacks are forbidden (http)
bool _noListener;
/// The peer address of the client
QString _peerAddress;
// The JsonCallbacks instance which handles data subscription/notifications
QSharedPointer<JsonCallbacks> _jsonCB;
};

View File

@@ -0,0 +1,332 @@
#ifndef JSONAPICOMMAND_H
#define JSONAPICOMMAND_H
#include <QMap>
#include <QPair>
#include <QString>
class Command {
public:
enum Type {
Unknown,
Adjustment,
Authorize,
Clear,
ClearAll,
Color,
ComponentState,
Config,
Correction,
CreateEffect,
DeleteEffect,
Effect,
Image,
InputSource,
Instance,
LedColors,
LedDevice,
Logging,
Processing,
ServerInfo,
Service,
SourceSelect,
SysInfo,
System,
Temperature,
Transform,
VideoMode
};
static QString toString(Type type) {
switch (type) {
case Adjustment: return "adjustment";
case Authorize: return "authorize";
case Clear: return "clear";
case ClearAll: return "clearall";
case Color: return "color";
case ComponentState: return "componentstate";
case Config: return "config";
case Correction: return "correction";
case CreateEffect: return "create-effect";
case DeleteEffect: return "delete-effect";
case Effect: return "effect";
case Image: return "image";
case InputSource: return "inputsource";
case Instance: return "instance";
case LedColors: return "ledcolors";
case LedDevice: return "leddevice";
case Logging: return "logging";
case Processing: return "processing";
case ServerInfo: return "serverinfo";
case SourceSelect: return "sourceselect";
case SysInfo: return "sysinfo";
case System: return "system";
case Temperature: return "temperature";
case Transform: return "transform";
case VideoMode: return "videomode";
case Service: return "service";
default: return "unknown";
}
}
};
class SubCommand {
public:
enum Type {
Unknown,
Empty,
AdminRequired,
AddAuthorization,
AnswerRequest,
CreateInstance,
CreateToken,
DeleteInstance,
DeleteToken,
Discover,
GetConfig,
GetInfo,
GetPendingTokenRequests,
GetProperties,
GetSchema,
GetSubscriptionCommands,
GetSubscriptions,
GetTokenList,
Identify,
Idle,
ImageStreamStart,
ImageStreamStop,
LedStreamStart,
LedStreamStop,
Login,
Logout,
NewPassword,
NewPasswordRequired,
Reload,
RenameToken,
RequestToken,
Restart,
RestoreConfig,
Resume,
SaveName,
SetConfig,
Start,
StartInstance,
Stop,
StopInstance,
Subscribe,
Suspend,
SwitchTo,
ToggleIdle,
ToggleSuspend,
TokenRequired,
Unsubscribe
};
static QString toString(Type type) {
switch (type) {
case Empty: return "";
case AdminRequired: return "adminRequired";
case AddAuthorization: return "addAuthorization";
case AnswerRequest: return "answerRequest";
case CreateInstance: return "createInstance";
case CreateToken: return "createToken";
case DeleteInstance: return "deleteInstance";
case DeleteToken: return "deleteToken";
case Discover: return "discover";
case GetConfig: return "getconfig";
case GetInfo: return "getInfo";
case GetPendingTokenRequests: return "getPendingTokenRequests";
case GetProperties: return "getProperties";
case GetSchema: return "getschema";
case GetSubscriptionCommands: return "getSubscriptionCommands";
case GetSubscriptions: return "getSubscriptions";
case GetTokenList: return "getTokenList";
case Identify: return "identify";
case Idle: return "idle";
case ImageStreamStart: return "imagestream-start";
case ImageStreamStop: return "imagestream-stop";
case LedStreamStart: return "ledstream-start";
case LedStreamStop: return "ledstream-stop";
case Login: return "login";
case Logout: return "logout";
case NewPassword: return "newPassword";
case NewPasswordRequired: return "newPasswordRequired";
case Reload: return "reload";
case RenameToken: return "renameToken";
case RequestToken: return "requestToken";
case Restart: return "restart";
case RestoreConfig: return "restoreconfig";
case Resume: return "resume";
case SaveName: return "saveName";
case SetConfig: return "setconfig";
case Start: return "start";
case StartInstance: return "startInstance";
case Stop: return "stop";
case StopInstance: return "stopInstance";
case Subscribe: return "subscribe";
case Suspend: return "suspend";
case SwitchTo: return "switchTo";
case ToggleIdle: return "toggleIdle";
case ToggleSuspend: return "toggleSuspend";
case TokenRequired: return "tokenRequired";
case Unsubscribe: return "unsubscribe";
default: return "unknown";
}
}
};
class Authorization {
public:
enum Type {
Admin,
Yes,
No
};
};
class NoListenerCmd {
public:
enum Type {
No,
Yes
};
};
class InstanceCmd {
public:
enum Type {
No,
Yes,
Multi
};
};
class JsonApiCommand {
public:
JsonApiCommand()
: command(Command::Unknown),
subCommand(SubCommand::Unknown),
tan(0),
authorization(Authorization::Admin),
isInstanceCmd(InstanceCmd::No),
isNolistenerCmd(NoListenerCmd::Yes)
{}
JsonApiCommand(Command::Type command, SubCommand::Type subCommand,
Authorization::Type authorization,
InstanceCmd::Type isInstanceCmd,
NoListenerCmd::Type isNolistenerCmd,
int tan = 0)
: command(command),
subCommand(subCommand),
tan(tan),
authorization(authorization),
isInstanceCmd(isInstanceCmd),
isNolistenerCmd(isNolistenerCmd)
{}
Command::Type getCommand() const { return command; }
SubCommand::Type getSubCommand() const { return subCommand; }
InstanceCmd::Type instanceCmd() const { return isInstanceCmd; }
int getTan() const { return tan; }
QString toString() const {
QString cmd = Command::toString(command);
if (subCommand > SubCommand::Empty) {
cmd += QString("-%2").arg(SubCommand::toString(subCommand));
}
return cmd;
}
Command::Type command;
SubCommand::Type subCommand;
int tan;
Authorization::Type authorization;
InstanceCmd::Type isInstanceCmd;
NoListenerCmd::Type isNolistenerCmd;
};
typedef QMap<QPair<QString, QString>, JsonApiCommand> CommandLookupMap;
class ApiCommandRegister {
public:
static const CommandLookupMap& getCommandLookup() {
static const CommandLookupMap commandLookup {
{ {"adjustment", ""}, { Command::Adjustment, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"authorize", "adminRequired"}, { Command::Authorize, SubCommand::AdminRequired, Authorization::No, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "answerRequest"}, { Command::Authorize, SubCommand::AnswerRequest, Authorization::Admin, InstanceCmd::No, NoListenerCmd::No} },
{ {"authorize", "createToken"}, { Command::Authorize, SubCommand::CreateToken, Authorization::Admin, InstanceCmd::No, NoListenerCmd::No} },
{ {"authorize", "deleteToken"}, { Command::Authorize, SubCommand::DeleteToken, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "getPendingTokenRequests"}, { Command::Authorize, SubCommand::GetPendingTokenRequests, Authorization::Admin, InstanceCmd::No, NoListenerCmd::No} },
{ {"authorize", "getTokenList"}, { Command::Authorize, SubCommand::GetTokenList, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "login"}, { Command::Authorize, SubCommand::Login, Authorization::No, InstanceCmd::No, NoListenerCmd::No} },
{ {"authorize", "logout"}, { Command::Authorize, SubCommand::Logout, Authorization::No, InstanceCmd::No, NoListenerCmd::No} },
{ {"authorize", "newPassword"}, { Command::Authorize, SubCommand::NewPassword, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "newPasswordRequired"}, { Command::Authorize, SubCommand::NewPasswordRequired, Authorization::No, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "renameToken"}, { Command::Authorize, SubCommand::RenameToken, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "requestToken"}, { Command::Authorize, SubCommand::RequestToken, Authorization::No, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"authorize", "tokenRequired"}, { Command::Authorize, SubCommand::TokenRequired, Authorization::No, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"clear", ""}, { Command::Clear, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"clearall", ""}, { Command::ClearAll, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"color", ""}, { Command::Color, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"componentstate", ""}, { Command::ComponentState, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"config", "getconfig"}, { Command::Config, SubCommand::GetConfig, Authorization::Admin, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"config", "getschema"}, { Command::Config, SubCommand::GetSchema, Authorization::Admin, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"config", "reload"}, { Command::Config, SubCommand::Reload, Authorization::Admin, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"config", "restoreconfig"}, { Command::Config, SubCommand::RestoreConfig, Authorization::Admin, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"config", "setconfig"}, { Command::Config, SubCommand::SetConfig, Authorization::Admin, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"correction", ""}, { Command::Correction, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"create-effect", ""}, { Command::CreateEffect, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"delete-effect", ""}, { Command::DeleteEffect, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"effect", ""}, { Command::Effect, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"image", ""}, { Command::Image, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"inputsource", "discover"}, { Command::InputSource, SubCommand::Discover, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"inputsource", "getProperties"}, { Command::InputSource, SubCommand::GetProperties, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "createInstance"}, { Command::Instance, SubCommand::CreateInstance, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "deleteInstance"}, { Command::Instance, SubCommand::DeleteInstance, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "saveName"}, { Command::Instance, SubCommand::SaveName, Authorization::Admin, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "startInstance"}, { Command::Instance, SubCommand::StartInstance, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "stopInstance"}, { Command::Instance, SubCommand::StopInstance, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"instance", "switchTo"}, { Command::Instance, SubCommand::SwitchTo, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"ledcolors", "imagestream-start"}, { Command::LedColors, SubCommand::ImageStreamStart, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"ledcolors", "imagestream-stop"}, { Command::LedColors, SubCommand::ImageStreamStop, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"ledcolors", "ledstream-start"}, { Command::LedColors, SubCommand::LedStreamStart, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"ledcolors", "ledstream-stop"}, { Command::LedColors, SubCommand::LedStreamStop, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"leddevice", "addAuthorization"}, { Command::LedDevice, SubCommand::AddAuthorization, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"leddevice", "discover"}, { Command::LedDevice, SubCommand::Discover, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"leddevice", "getProperties"}, { Command::LedDevice, SubCommand::GetProperties, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"leddevice", "identify"}, { Command::LedDevice, SubCommand::Identify, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"logging", "start"}, { Command::Logging, SubCommand::Start, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"logging", "stop"}, { Command::Logging, SubCommand::Stop, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"processing", ""}, { Command::Processing, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"serverinfo", ""}, { Command::ServerInfo, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"serverinfo", "getInfo"}, { Command::ServerInfo, SubCommand::GetInfo, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"serverinfo", "subscribe"}, { Command::ServerInfo, SubCommand::Subscribe, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::No} },
{ {"serverinfo", "unsubscribe"}, { Command::ServerInfo, SubCommand::Unsubscribe, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::No} },
{ {"serverinfo", "getSubscriptions"}, { Command::ServerInfo, SubCommand::GetSubscriptions, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::No} },
{ {"serverinfo", "getSubscriptionCommands"}, { Command::ServerInfo, SubCommand::GetSubscriptionCommands, Authorization::No, InstanceCmd::No, NoListenerCmd::No} },
{ {"service", "discover"}, { Command::Service, SubCommand::Discover, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"sourceselect", ""}, { Command::SourceSelect, SubCommand::Empty, Authorization::Yes, InstanceCmd::Multi, NoListenerCmd::Yes} },
{ {"sysinfo", ""}, { Command::SysInfo, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "restart"}, { Command::System, SubCommand::Restart, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "resume"}, { Command::System, SubCommand::Resume, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "suspend"}, { Command::System, SubCommand::Suspend, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "toggleSuspend"}, { Command::System, SubCommand::ToggleSuspend, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "idle"}, { Command::System, SubCommand::Idle, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"system", "toggleIdle"}, { Command::System, SubCommand::ToggleIdle, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} },
{ {"temperature", ""}, { Command::Temperature, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"transform", ""}, { Command::Transform, SubCommand::Empty, Authorization::Yes, InstanceCmd::Yes, NoListenerCmd::Yes} },
{ {"videomode", ""}, { Command::VideoMode, SubCommand::Empty, Authorization::Yes, InstanceCmd::No, NoListenerCmd::Yes} }
};
return commandLookup;
}
static JsonApiCommand getCommandInfo(const QString& command, const QString& subCommand) {
return getCommandLookup().value({command, subCommand});
}
};
#endif // JSONAPICOMMAND_H

View File

@@ -0,0 +1,135 @@
#ifndef JSONAPISUBSCRIPTION_H
#define JSONAPISUBSCRIPTION_H
#include <HyperionConfig.h> // Required to determine the cmake options
#include <QMap>
#include <QString>
class Subscription {
public:
enum Type {
Unknown,
AdjustmentUpdate,
ComponentsUpdate,
#if defined(ENABLE_EFFECTENGINE)
EffectsUpdate,
#endif
EventUpdate,
ImageToLedMappingUpdate,
ImageUpdate,
InstanceUpdate,
LedColorsUpdate,
LedsUpdate,
LogMsgUpdate,
PrioritiesUpdate,
SettingsUpdate,
TokenUpdate,
VideomodeUpdate
};
static QString toString(Type type) {
switch (type) {
case AdjustmentUpdate: return "adjustment-update";
case ComponentsUpdate: return "components-update";
#if defined(ENABLE_EFFECTENGINE)
case EffectsUpdate: return "effects-update";
#endif
case EventUpdate: return "event-update";
case ImageToLedMappingUpdate: return "imageToLedMapping-update";
case ImageUpdate: return "ledcolors-imagestream-update";
case InstanceUpdate: return "instance-update";
case LedColorsUpdate: return "ledcolors-ledstream-update";
case LedsUpdate: return "leds-update";
case LogMsgUpdate: return "logmsg-update";
case PrioritiesUpdate: return "priorities-update";
case SettingsUpdate: return "settings-update";
case TokenUpdate: return "token-update";
case VideomodeUpdate: return "videomode-update";
default: return "unknown";
}
}
static bool isInstanceSpecific(Type type) {
switch (type) {
case AdjustmentUpdate:
case ComponentsUpdate:
#if defined(ENABLE_EFFECTENGINE)
case EffectsUpdate:
#endif
case ImageToLedMappingUpdate:
case ImageUpdate:
case LedColorsUpdate:
case LedsUpdate:
case PrioritiesUpdate:
case SettingsUpdate:
return true;
case EventUpdate:
case InstanceUpdate:
case LogMsgUpdate:
case TokenUpdate:
case VideomodeUpdate:
default:
return false;
}
}
};
class JsonApiSubscription {
public:
JsonApiSubscription()
: cmd(Subscription::Unknown),
isAll(false)
{}
JsonApiSubscription(Subscription::Type cmd, bool isAll)
: cmd(cmd),
isAll(isAll)
{}
Subscription::Type getSubscription() const { return cmd; }
bool isPartOfAll() const { return isAll; }
QString toString() const {
return Subscription::toString(cmd);
}
Subscription::Type cmd;
bool isAll;
};
typedef QMap<QString, JsonApiSubscription> SubscriptionLookupMap;
class ApiSubscriptionRegister {
public:
static const SubscriptionLookupMap& getSubscriptionLookup() {
static const SubscriptionLookupMap subscriptionLookup {
{ {"adjustment-update"}, { Subscription::AdjustmentUpdate, true} },
{ {"components-update"}, { Subscription::ComponentsUpdate, true} },
#if defined(ENABLE_EFFECTENGINE)
{ {"effects-update"}, { Subscription::EffectsUpdate, true} },
#endif
{ {"event-update"}, { Subscription::EventUpdate, true} },
{ {"imageToLedMapping-update"}, { Subscription::ImageToLedMappingUpdate, true} },
{ {"ledcolors-imagestream-update"}, { Subscription::ImageUpdate, false} },
{ {"ledcolors-ledstream-update"}, { Subscription::LedColorsUpdate, false} },
{ {"instance-update"}, { Subscription::InstanceUpdate, true} },
{ {"leds-update"}, { Subscription::LedsUpdate, true} },
{ {"logmsg-update"}, { Subscription::LogMsgUpdate, false} },
{ {"priorities-update"}, { Subscription::PrioritiesUpdate, true} },
{ {"settings-update"}, { Subscription::SettingsUpdate, true} },
{ {"token-update"}, { Subscription::TokenUpdate, true} },
{ {"videomode-update"}, { Subscription::VideomodeUpdate, true} }
};
return subscriptionLookup;
}
static JsonApiSubscription getSubscriptionInfo(const QString& subscription) {
return getSubscriptionLookup().value({subscription});
}
};
#endif // JSONAPISUBSCRIPTION_H

View File

@@ -1,51 +1,82 @@
#pragma once
#include "api/JsonApiSubscription.h"
#include <api/API.h>
#include <events/EventEnum.h>
// qt incl
#include <QObject>
#include <QJsonObject>
#include <QSet>
// components def
#include <utils/Components.h>
// videModes
#include <utils/VideoMode.h>
// settings
#include <utils/settings.h>
// AuthManager
#include <hyperion/AuthManager.h>
#include <hyperion/PriorityMuxer.h>
class Hyperion;
class ComponentRegister;
class PriorityMuxer;
class JsonCB : public QObject
class JsonCallbacks : public QObject
{
Q_OBJECT
public:
JsonCB(QObject* parent);
JsonCallbacks(Logger* log, const QString& peerAddress, QObject* parent);
///
/// @brief Subscribe to future data updates given by cmd
/// @param cmd The cmd which will be subscribed for
/// @param unsubscribe Revert subscription
/// @param cmd The cmd which will be subscribed for
/// @return True on success, false if not found
///
bool subscribeFor(const QString& cmd, bool unsubscribe = false);
bool subscribe(const QString& cmd);
///
/// @brief Subscribe to future data updates given by subscription list
/// @param type Array of subscriptionsm
///
QStringList subscribe(const QJsonArray& subscriptions);
///
/// @brief Subscribe to future data updates given by cmd
/// @param cmd The cmd which will be subscribed to
/// @return True on success, false if not found
///
bool subscribe(Subscription::Type subscription);
///
/// @brief Unsubscribe to future data updates given by cmd
/// @param cmd The cmd which will be unsubscribed
/// @return True on success, false if not found
///
bool unsubscribe(const QString& cmd);
///
/// @brief Unsubscribe to future data updates given by subscription list
/// @param type Array of subscriptions
///
QStringList unsubscribe(const QJsonArray& subscriptions);
///
/// @brief Unsubscribe to future data updates given by cmd
/// @param cmd The cmd which will be subscribed to
/// @return True on success, false if not found
///
bool unsubscribe(Subscription::Type cmd);
///
/// @brief Get all possible commands to subscribe for
/// @param fullList Return all possible commands or those not triggered by API requests (subscriptions="ALL")
/// @return The list of commands
///
QStringList getCommands() { return _availableCommands; };
QStringList getCommands(bool fullList = true) const;
///
/// @brief Get all subscribed commands
/// @return The list of commands
///
QStringList getSubscribedCommands() { return _subscribedCommands; };
QStringList getSubscribedCommands() const;
///
/// @brief Reset subscriptions, disconnect all signals
@@ -124,18 +155,49 @@ private slots:
///
void handleTokenChange(const QVector<AuthManager::AuthDefinition> &def);
///
/// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled)
/// @param ledColors The current led colors
///
void handleLedColorUpdate(const std::vector<ColorRgb> &ledColors);
///
/// @brief Is called whenever the current Hyperion instance pushes new image update (if enabled)
/// @param image The current image
///
void handleImageUpdate(const Image<ColorRgb> &image);
///
/// @brief Process and push new log messages from logger (if enabled)
///
void handleLogMessageUpdate(const Logger::T_LOG_MESSAGE &);
///
/// @brief Is called whenever an event is triggert
/// @param image The current event
///
void handleEventUpdate(const Event &event);
private:
/// pointer of Hyperion instance
/// construct callback msg
void doCallback(Subscription::Type cmd, const QVariant& data);
Logger *_log;
Hyperion* _hyperion;
/// The peer address of the client
QString _peerAddress;
/// pointer of comp register
ComponentRegister* _componentRegister;
/// priority muxer instance
PriorityMuxer* _prioMuxer;
/// contains all available commands
QStringList _availableCommands;
/// contains active subscriptions
QStringList _subscribedCommands;
/// construct callback msg
void doCallback(const QString& cmd, const QVariant& data);
QSet<Subscription::Type> _subscribedCommands;
/// flag to determine state of log streaming
bool _islogMsgStreamingActive;
};

43
include/api/JsonInfo.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef JSONINFO_H
#define JSONINFO_H
#include <utils/Logger.h>
#include <hyperion/Hyperion.h>
#include <hyperion/HyperionIManager.h>
#include <QJsonObject>
#include <QJsonArray>
class JsonInfo
{
public:
static QJsonArray getAdjustmentInfo(const Hyperion* hyperion, Logger* log);
static QJsonArray getPrioritiestInfo(const Hyperion* hyperion);
static QJsonArray getPrioritiestInfo(int currentPriority, const PriorityMuxer::InputsMap& activeInputs);
static QJsonArray getEffects(const Hyperion* hyperion);
static QJsonArray getAvailableScreenGrabbers();
static QJsonArray getAvailableVideoGrabbers();
static QJsonArray getAvailableAudioGrabbers();
static QJsonObject getGrabbers(const Hyperion* hyperion);
static QJsonObject getAvailableLedDevices();
static QJsonObject getCecInfo();
static QJsonArray getServices();
static QJsonArray getComponents(const Hyperion* hyperion);
static QJsonArray getInstanceInfo();
static QJsonArray getActiveEffects(const Hyperion* hyperion);
static QJsonArray getActiveColors(const Hyperion* hyperion);
static QJsonArray getTransformationInfo(const Hyperion* hyperion);
static QJsonObject getSystemInfo(const Hyperion* hyperion);
QJsonObject discoverSources (const QString& sourceType, const QJsonObject& params);
private:
template<typename GrabberType>
void discoverGrabber(QJsonArray& inputs, const QJsonObject& params) const;
QJsonArray discoverScreenInputs(const QJsonObject& params) const;
QJsonArray discoverVideoInputs(const QJsonObject& params) const;
QJsonArray discoverAudioInputs(const QJsonObject& params) const;
};
#endif // JSONINFO_H

View File

@@ -2,6 +2,9 @@
#include <QString>
#include <QByteArray>
#include <QJsonObject>
#include <utils/Components.h>
struct ImageCmdData
{

View File

@@ -110,7 +110,7 @@ namespace hyperion
}
// Construct result
BlackBorder detectedBorder;
BlackBorder detectedBorder{};
detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1;
detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
detectedBorder.verticalSize = firstNonBlackXPixelIndex;
@@ -167,7 +167,7 @@ namespace hyperion
}
// Construct result
BlackBorder detectedBorder;
BlackBorder detectedBorder{};
detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1;
detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
detectedBorder.verticalSize = firstNonBlackXPixelIndex;
@@ -224,7 +224,7 @@ namespace hyperion
}
// Construct result
BlackBorder detectedBorder;
BlackBorder detectedBorder{};
detectedBorder.unknown = firstNonBlackXPixelIndex == -1 || firstNonBlackYPixelIndex == -1;
detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
detectedBorder.verticalSize = firstNonBlackXPixelIndex;
@@ -267,7 +267,7 @@ namespace hyperion
}
// Construct result
BlackBorder detectedBorder;
BlackBorder detectedBorder{};
detectedBorder.unknown = firstNonBlackYPixelIndex == -1;
detectedBorder.horizontalSize = firstNonBlackYPixelIndex;
detectedBorder.verticalSize = 0;

View File

@@ -1,4 +1,7 @@
#pragma once
#ifndef BLACK_BORDER_PROCESSOR_H
#define BLACK_BORDER_PROCESSOR_H
#include <memory>
// QT includes
#include <QJsonObject>
@@ -24,7 +27,7 @@ namespace hyperion
Q_OBJECT
public:
BlackBorderProcessor(Hyperion* hyperion, QObject* parent);
~BlackBorderProcessor() override;
///
/// Return the current (detected) border
/// @return The current border
@@ -141,7 +144,7 @@ namespace hyperion
QString _detectionMode;
/// The black-border detector
BlackBorderDetector* _detector;
std::unique_ptr<BlackBorderDetector> _detector;
/// The current detected border
BlackBorder _currentBorder;
@@ -162,3 +165,5 @@ namespace hyperion
};
} // end namespace hyperion
#endif // BLACK_BORDER_PROCESSOR_H

View File

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

View File

@@ -2,12 +2,14 @@
#include <QObject>
#include <QVector>
#include <QMap>
#include <iostream>
#include <libcec/cec.h>
#include <cec/CECEvent.h>
#include <utils/settings.h>
#include <events/EventEnum.h>
using CECCallbacks = CEC::ICECCallbacks;
using CECAdapter = CEC::ICECAdapter;
@@ -30,19 +32,28 @@ class CECHandler : public QObject
{
Q_OBJECT
public:
CECHandler();
CECHandler(const QJsonDocument& config, QObject * parent = nullptr);
~CECHandler() override;
QString scan() const;
public slots:
bool start();
void stop();
signals:
void cecEvent(CECEvent event);
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
private:
signals:
void signalEvent(Event event);
private:
bool enable();
void disable();
/* CEC Callbacks */
static void onCecLogMessage (void * context, const CECLogMessage * message);
static void onCecKeyPress (void * context, const CECKeyPress * key);
@@ -57,6 +68,11 @@ private:
bool openAdapter(const CECAdapterDescriptor & descriptor);
void printAdapter(const CECAdapterDescriptor & descriptor) const;
// CEC Event Strings per https://github.com/Pulse-Eight/libcec/blob/master/src/libcec/CECTypeUtils.h
void triggerAction(const QString& cecEvent);
QJsonDocument _config;
/* CEC Helpers */
CECCallbacks getCallbacks() const;
CECConfig getConfig() const;
@@ -65,5 +81,15 @@ private:
CECCallbacks _cecCallbacks {};
CECConfig _cecConfig {};
bool _isInitialised;
bool _isOpen;
bool _isEnabled;
int _buttonReleaseDelayMs;
int _buttonRepeatRateMs;
int _doubleTapTimeoutMs;
QMap<QString,Event> _cecEventActionMap;
Logger * _logger {};
};

View File

@@ -36,6 +36,11 @@ public:
: Option(other), validator(validator)
{}
~ValidatorOption()
{
delete validator;
}
virtual const QValidator *getValidator() const;
virtual bool validate(Parser & parser, QString &value) override;
};

View File

@@ -8,6 +8,11 @@
#include <QDateTime>
#include <QUuid>
namespace hyperion {
const char DEFAULT_USER[] = "Hyperion";
const char DEFAULT_PASSWORD[] = "hyperion";
}
///
/// @brief Authentication table interface
///
@@ -149,10 +154,10 @@ public:
inline bool resetHyperionUser()
{
QVariantMap map;
map["password"] = calcPasswordHashOfUser("Hyperion", "hyperion");
map["password"] = calcPasswordHashOfUser(hyperion::DEFAULT_USER, hyperion::DEFAULT_PASSWORD);
VectorPair cond;
cond.append(CPair("user", "Hyperion"));
cond.append(CPair("user", hyperion::DEFAULT_USER));
return updateRecord(cond, map);
}

View File

@@ -112,6 +112,8 @@ public:
list << "jsonServer" << "protoServer" << "flatbufServer" << "forwarder" << "webConfig" << "network"
// capture
<< "framegrabber" << "grabberV4L2" << "grabberAudio"
//Events
<< "osEvents" << "cecEvents" << "schedEvents"
// other
<< "logger" << "general";

View File

@@ -0,0 +1,53 @@
#ifndef EVENTENUM_H
#define EVENTENUM_H
#include <QString>
enum class Event
{
Unknown,
Suspend,
Resume,
ToggleSuspend,
Idle,
ResumeIdle,
ToggleIdle,
Reload,
Restart,
Quit
};
inline const char* eventToString(Event event)
{
switch (event)
{
case Event::Suspend: return "Suspend";
case Event::Resume: return "Resume";
case Event::ToggleSuspend: return "ToggleSuspend";
case Event::Idle: return "Idle";
case Event::Quit: return "Quit";
case Event::ResumeIdle: return "ResumeIdle";
case Event::ToggleIdle: return "ToggleIdle";
case Event::Reload: return "Reload";
case Event::Restart: return "Restart";
case Event::Unknown:
default: return "Unknown";
}
}
inline Event stringToEvent(const QString& event)
{
if (event.compare("Suspend")==0) return Event::Suspend;
if (event.compare("Resume")==0) return Event::Resume;
if (event.compare("ToggleSuspend")==0) return Event::ToggleSuspend;
if (event.compare("Idle")==0) return Event::Idle;
if (event.compare("Quit")==0) return Event::Quit;
if (event.compare("ResumeIdle")==0) return Event::ResumeIdle;
if (event.compare("ToggleIdle")==0) return Event::ToggleIdle;
if (event.compare("Reload")==0) return Event::Reload;
if (event.compare("Restart")==0) return Event::Restart;
return Event::Unknown;
}
#endif // EVENTENUM_H

View File

@@ -0,0 +1,54 @@
#ifndef EVENTHANDLER_H
#define EVENTHANDLER_H
#include <utils/settings.h>
#include <events/EventEnum.h>
#include <QObject>
class Logger;
class EventHandler : public QObject
{
Q_OBJECT
public:
~EventHandler() override;
static QScopedPointer<EventHandler>& getInstance();
public slots:
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:
EventHandler();
EventHandler(const EventHandler&) = delete;
EventHandler& operator=(const EventHandler&) = delete;
static QScopedPointer<EventHandler> instance;
bool _isSuspended;
bool _isIdle;
};
#endif // EVENTHANDLER_H

View File

@@ -0,0 +1,55 @@
#ifndef EVENTSCHEDULER_H
#define EVENTSCHEDULER_H
#include <QObject>
#include <QJsonDocument>
#include <QTime>
#include <QTimer>
#include <events/EventEnum.h>
#include <utils/settings.h>
class Logger;
class EventScheduler : public QObject
{
Q_OBJECT
public:
EventScheduler();
~EventScheduler() override;
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
signals:
void signalEvent(Event event);
private slots:
void handleEvent(int timerIndex);
private:
struct timeEvent
{
QTime time;
Event action;
};
bool enable();
void disable();
int getMillisecondsToNextScheduledTime(const QTime& time);
void clearTimers();
QJsonDocument _config;
bool _isEnabled;
QList<timeEvent> _scheduledEvents;
QList<QTimer*> _timers;
Logger * _log {};
};
#endif // EVENTSCHEDULER_H

View File

@@ -0,0 +1,143 @@
#ifndef OSEVENTHANDLER_H
#define OSEVENTHANDLER_H
#include <QObject>
#include <QJsonDocument>
#include <events/EventEnum.h>
#if defined(_WIN32)
#include <QAbstractNativeEventFilter>
#include <QAbstractEventDispatcher>
#include <QWidget>
#include <windows.h>
#include <powrprof.h>
#endif
#include <utils/settings.h>
class Logger;
class OsEventHandlerBase : public QObject
{
Q_OBJECT
public:
OsEventHandlerBase();
virtual ~OsEventHandlerBase();
public slots:
void suspend(bool sleep);
void lock(bool isLocked);
void quit();
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;
bool _isService;
Logger* _log{};
};
#if defined(_WIN32)
class OsEventHandlerWindows : public OsEventHandlerBase, public QAbstractNativeEventFilter
{
public:
OsEventHandlerWindows();
~OsEventHandlerWindows();
void handleSuspendResumeEvent(bool sleep);
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
bool registerOsEventHandler() override;
void unregisterOsEventHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
private:
static OsEventHandlerWindows* getInstance();
static DEVICE_NOTIFY_CALLBACK_ROUTINE handlePowerNotifications;
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;
#elif defined(__APPLE__)
class OsEventHandlerMacOS : public OsEventHandlerBase
{
Q_OBJECT
public:
OsEventHandlerMacOS();
private:
bool registerOsEventHandler() override;
void unregisterOsEventHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
void* _sleepEventHandler;
void* _lockEventHandler;
};
using OsEventHandler = OsEventHandlerMacOS;
#else
using OsEventHandler = OsEventHandlerBase;
#endif
#endif // OSEVENTHANDLER_H

View File

@@ -0,0 +1,58 @@
#ifndef GRABBERCONFIG_H
#define GRABBERCONFIG_H
#if defined(ENABLE_MF)
#include <grabber/video/mediafoundation/MFGrabber.h>
#elif defined(ENABLE_V4L2)
#include <grabber/video/v4l2/V4L2Grabber.h>
#endif
#if defined(ENABLE_AUDIO)
#include <grabber/audio/AudioGrabber.h>
#ifdef WIN32
#include <grabber/audio/AudioGrabberWindows.h>
#endif
#ifdef __linux__
#include <grabber/audio/AudioGrabberLinux.h>
#endif
#endif
#ifdef ENABLE_QT
#include <grabber/qt/QtGrabber.h>
#endif
#ifdef ENABLE_DX
#include <grabber/directx/directXGrabber.h>
#endif
#if defined(ENABLE_X11)
#include <grabber/x11/X11Grabber.h>
#endif
#if defined(ENABLE_XCB)
#include <grabber/xcb/XcbGrabber.h>
#endif
#if defined(ENABLE_DX)
#include <grabber/directx/DirectXGrabber.h>
#endif
#if defined(ENABLE_FB)
#include <grabber/framebuffer/FramebufferFrameGrabber.h>
#endif
#if defined(ENABLE_DISPMANX)
#include <grabber/dispmanx/DispmanxFrameGrabber.h>
#endif
#if defined(ENABLE_AMLOGIC)
#include <grabber/amlogic/AmlogicGrabber.h>
#endif
#if defined(ENABLE_OSX)
#include <grabber/osx/OsxFrameGrabber.h>
#endif
#endif // GRABBERCONFIG_H

View File

@@ -1,93 +0,0 @@
#pragma once
#ifndef __APPLE__
/*
* this is a mock up for compiling and testing osx wrapper on no osx platform.
* this will show a test image and rotate the colors.
*
* see https://github.com/phracker/MacOSX-SDKs/blob/master/MacOSX10.8.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers
*
*/
#include <utils/Image.h>
#include <utils/ColorRgb.h>
enum _CGError {
kCGErrorSuccess = 0,
kCGErrorFailure = 1000,
kCGErrorIllegalArgument = 1001,
kCGErrorInvalidConnection = 1002,
kCGErrorInvalidContext = 1003,
kCGErrorCannotComplete = 1004,
kCGErrorNotImplemented = 1006,
kCGErrorRangeCheck = 1007,
kCGErrorTypeCheck = 1008,
kCGErrorInvalidOperation = 1010,
kCGErrorNoneAvailable = 1011,
/* Obsolete errors. */
kCGErrorNameTooLong = 1005,
kCGErrorNoCurrentPoint = 1009,
kCGErrorApplicationRequiresNewerSystem = 1015,
kCGErrorApplicationNotPermittedToExecute = 1016,
kCGErrorApplicationIncorrectExecutableFormatFound = 1023,
kCGErrorApplicationIsLaunching = 1024,
kCGErrorApplicationAlreadyRunning = 1025,
kCGErrorApplicationCanOnlyBeRunInOneSessionAtATime = 1026,
kCGErrorClassicApplicationsMustBeLaunchedByClassic = 1027,
kCGErrorForkFailed = 1028,
kCGErrorRetryRegistration = 1029,
kCGErrorFirst = 1000,
kCGErrorLast = 1029
};
typedef int32_t CGError;
typedef double CGFloat;
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
struct CGPoint {
float x;
float y;
};
typedef struct CGPoint CGPoint;
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;
typedef CGError CGDisplayErr;
typedef uint32_t CGDirectDisplayID;
typedef uint32_t CGDisplayCount;;
typedef struct CGDisplayMode *CGDisplayModeRef;
typedef Image<ColorRgb> CGImage;
typedef CGImage* CGImageRef;
typedef unsigned char CFData;
typedef CFData* CFDataRef;
const int kCGDirectMainDisplay = 0;
CGError CGGetActiveDisplayList(uint32_t maxDisplays, CGDirectDisplayID *activeDisplays, uint32_t *displayCount);
CGDisplayModeRef CGDisplayCopyDisplayMode(CGDirectDisplayID display);
CGRect CGDisplayBounds(CGDirectDisplayID display);
void CGDisplayModeRelease(CGDisplayModeRef mode);
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display);
void CGImageRelease(CGImageRef image);
CGImageRef CGImageGetDataProvider(CGImageRef image);
CFDataRef CGDataProviderCopyData(CGImageRef image);
unsigned char* CFDataGetBytePtr(CFDataRef imgData);
unsigned CGImageGetWidth(CGImageRef image);
unsigned CGImageGetHeight(CGImageRef image);
unsigned CGImageGetBitsPerPixel(CGImageRef image);
unsigned CGImageGetBytesPerRow(CGImageRef image);
void CFRelease(CFDataRef imgData);
#endif

View File

@@ -1,29 +0,0 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/XcbGrabber.h>
// some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions
#ifdef None
#undef None
#endif
class XcbWrapper: public GrabberWrapper
{
public:
XcbWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
~XcbWrapper() override;
public slots:
void action() override;
private:
XcbGrabber _grabber;
bool _init;
};

View File

@@ -4,7 +4,7 @@
#include <utils/ColorBgr.h>
#include <utils/ColorRgba.h>
#include <hyperion/Grabber.h>
#include <grabber/FramebufferFrameGrabber.h>
#include <grabber/framebuffer/FramebufferFrameGrabber.h>
///
///

View File

@@ -1,7 +1,7 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/AmlogicGrabber.h>
#include <grabber/amlogic/AmlogicGrabber.h>
///
/// The Amlogic uses an instance of the AmlogicGrabber to obtain ImageRgb's from the
@@ -12,15 +12,23 @@ class AmlogicWrapper : public GrabberWrapper
{
Q_OBJECT
public:
static constexpr const char* GRABBERTYPE = "Amlogic";
///
/// Constructs the Amlogic frame grabber
///
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] pixelDecimation Decimation factor for image [pixels]///
///
AmlogicWrapper(int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ);
AmlogicWrapper(int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION);
///
/// Constructs the Amlogic frame grabber from configuration settings
///
AmlogicWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
public slots:
///

View File

@@ -6,7 +6,7 @@
#include <alsa/asoundlib.h>
// Hyperion-utils includes
#include <grabber/AudioGrabber.h>
#include <grabber/audio/AudioGrabber.h>
///
/// @brief The Linux Audio capture implementation
@@ -18,74 +18,69 @@ class AudioGrabberLinux : public AudioGrabber
AudioGrabberLinux();
~AudioGrabberLinux() override;
///
///
/// Process audio buffer
///
void processAudioBuffer(snd_pcm_sframes_t frames);
///
///
/// Is Running Flag
///
std::atomic<bool> _isRunning;
///
///
/// Current capture device
///
snd_pcm_t * _captureDevice;
public slots:
///
///
/// Start audio capturing session
///
/// @returns true if successful
bool start() override;
///
///
/// Stop audio capturing session
///
void stop() override;
///
///
/// Discovery audio devices
///
QJsonArray discover(const QJsonObject& params) override;
private:
///
///
/// Refresh audio devices
///
void refreshDevices();
///
///
/// Configure current audio capture interface
///
bool configureCaptureInterface();
///
///
/// Get device name from path
///
QString getDeviceName(const QString& devicePath) const;
///
///
/// Current sample rate
///
unsigned int _sampleRate;
///
///
/// Audio capture thread
///
pthread_t _audioThread;
///
///
/// ALSA device configuration parameters
///
snd_pcm_hw_params_t * _captureDeviceConfig;
};
///
/// Audio processing thread function
///
static void* AudioThreadRunner(void* params);
#endif // AUDIOGRABBERLINUX_H

View File

@@ -2,7 +2,7 @@
#define AUDIOGRABBERWINDOWS_H
// Hyperion-utils includes
#include <grabber/AudioGrabber.h>
#include <grabber/audio/AudioGrabber.h>
#include <DSound.h>
///
@@ -14,7 +14,7 @@ class AudioGrabberWindows : public AudioGrabber
AudioGrabberWindows();
~AudioGrabberWindows() override;
public slots:
bool start() override;
void stop() override;
@@ -39,8 +39,8 @@ class AudioGrabberWindows : public AudioGrabber
HANDLE notificationEvent;
std::atomic<bool> isRunning{ false };
static BOOL CALLBACK DirectSoundEnumProcessor(LPGUID deviceIdGuid, LPCTSTR deviceDescStr,
LPCTSTR deviceModelStr, LPVOID context)
static BOOL CALLBACK DirectSoundEnumProcessor(LPGUID deviceIdGuid, LPCWSTR deviceDescStr,
LPCWSTR deviceModelStr, LPVOID context)
{
// Skip undefined audio devices
if (deviceIdGuid == NULL)
@@ -50,12 +50,15 @@ static BOOL CALLBACK DirectSoundEnumProcessor(LPGUID deviceIdGuid, LPCTSTR devic
AudioGrabber::DeviceProperties device;
// Process Device Information
QString deviceName = QString::fromWCharArray(deviceDescStr);
// Process Device ID
LPOLESTR deviceIdStr;
HRESULT res = StringFromCLSID(*deviceIdGuid, &deviceIdStr);
if (FAILED(res))
{
Error(Logger::getInstance("AUDIOGRABBER"), "Failed to get CLSID-string for %s with error: 0x%08x: %s", deviceDescStr, res, std::system_category().message(res).c_str());
Error(Logger::getInstance("AUDIOGRABBER"), "Failed to get CLSID-string for %s with error: 0x%08x: %s", QSTRING_CSTR(deviceName), res, std::system_category().message(res).c_str());
return FALSE;
}
@@ -63,10 +66,7 @@ static BOOL CALLBACK DirectSoundEnumProcessor(LPGUID deviceIdGuid, LPCTSTR devic
CoTaskMemFree(deviceIdStr);
// Process Device Information
QString deviceName = QString::fromLocal8Bit(deviceDescStr);
Debug(Logger::getInstance("AUDIOGRABBER"), "Found Audio Device: %s", deviceDescStr);
Debug(Logger::getInstance("AUDIOGRABBER"), "Found Audio Device: %s", QSTRING_CSTR(deviceName));
device.id = deviceId;
device.name = deviceName;

View File

@@ -3,14 +3,14 @@
#include <hyperion/GrabberWrapper.h>
#ifdef WIN32
#include <grabber/AudioGrabberWindows.h>
#include <grabber/audio/AudioGrabberWindows.h>
#endif
#ifdef __linux__
#include <grabber/AudioGrabberLinux.h>
#include <grabber/audio/AudioGrabberLinux.h>
#endif
///
///
/// Audio Grabber wrapper
///
class AudioWrapper : public GrabberWrapper
@@ -32,7 +32,7 @@ class AudioWrapper : public GrabberWrapper
///
~AudioWrapper() override;
///
///
/// Settings update handler
///
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
@@ -43,13 +43,13 @@ class AudioWrapper : public GrabberWrapper
///
void action() override;
///
///
/// Start audio capturing session
///
/// @returns true if successful
bool start() override;
///
///
/// Stop audio capturing session
///
void stop() override;

View File

@@ -1,11 +1,13 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/DirectXGrabber.h>
#include <grabber/directx/DirectXGrabber.h>
class DirectXWrapper: public GrabberWrapper
{
public:
static constexpr const char* GRABBERTYPE = "DirectX";
///
/// Constructs the DirectX grabber with a specified grab size and update rate.
///
@@ -25,6 +27,11 @@ public:
int cropTop=0, int cropBottom=0
);
///
/// Constructs the QT frame grabber from configuration settings
///
DirectXWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
///
/// Destructor of this DirectX grabber. Releases any claimed resources.
///

View File

@@ -36,9 +36,9 @@ public:
///
/// @brief Determine if the bcm library is available.
///
/// @return Zero, on success (i.e. library is present), else negative
/// @return true, on success (i.e. library is present), else false
///
bool isAvailable();
bool isAvailable() override;
///
/// @brief Opens the input device.

View File

@@ -3,7 +3,7 @@
// Utils includes
#include <utils/ColorRgba.h>
#include <hyperion/GrabberWrapper.h>
#include <grabber/DispmanxFrameGrabber.h>
#include <grabber/dispmanx/DispmanxFrameGrabber.h>
///
/// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the
@@ -13,6 +13,9 @@ class DispmanxWrapper: public GrabberWrapper
{
Q_OBJECT
public:
static constexpr const char* GRABBERTYPE = "DispmanX";
///
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
///
@@ -23,9 +26,12 @@ public:
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
bool screenInit();
///
/// Constructs the QT frame grabber from configuration settings
///
DispmanxWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
bool available = false;
bool screenInit();
///
/// Starts the grabber which produces led values with the specified update rate

View File

@@ -17,7 +17,7 @@ public:
///
/// @param[in] device The framebuffer device name/path
///
FramebufferFrameGrabber(const QString & device="/dev/fb0");
FramebufferFrameGrabber(int deviceIdx = 0);
~FramebufferFrameGrabber() override;
@@ -45,7 +45,7 @@ public:
///@brief Set new width and height for framegrabber, overwrite Grabber.h implementation
bool setWidthHeight(int width, int height) override;
QString getPath() const {return _fbDevice;}
QString getPath() const {return QString("/dev/fb%1").arg(_input);}
///
/// @brief Discover Framebuffer screens available (for configuration).
@@ -62,7 +62,7 @@ private:
bool closeDevice();
bool getScreenInfo();
/// Framebuffer device e.g. /dev/fb0
// /// Framebuffer device e.g. /dev/fb0
QString _fbDevice;
int _fbfd;

View File

@@ -1,7 +1,7 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/FramebufferFrameGrabber.h>
#include <grabber/framebuffer/FramebufferFrameGrabber.h>
///
/// The FramebufferWrapper uses an instance of the FramebufferFrameGrabber to obtain ImageRgb's from the
@@ -12,18 +12,26 @@ class FramebufferWrapper: public GrabberWrapper
{
Q_OBJECT
public:
static constexpr const char* GRABBERTYPE = "FB";
///
/// Constructs the framebuffer frame grabber with a specified grab size and update rate.
///
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] device Framebuffer device name/path
/// @param[in] deviceIdx Framebuffer device index
/// @param[in] pixelDecimation Decimation factor for image [pixels]
///
FramebufferWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
const QString & device = "/dev/fb0",
int deviceIdx = 0,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
///
/// Constructs the QT frame grabber from configuration settings
///
FramebufferWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
public slots:
///
/// Performs a single frame grab and computes the led-colors

View File

@@ -1,11 +1,7 @@
#pragma once
// OSX includes
#ifdef __APPLE__
#include <CoreGraphics/CoreGraphics.h>
#else
#include <grabber/OsxFrameGrabberMock.h>
#endif
// Utils includes
#include <utils/ColorRgb.h>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/OsxFrameGrabber.h>
#include <grabber/osx/OsxFrameGrabber.h>
///
/// The OsxWrapper uses an instance of the OsxFrameGrabber to obtain ImageRgb's from the displayed content.
@@ -11,6 +11,8 @@ class OsxWrapper: public GrabberWrapper
{
Q_OBJECT
public:
static constexpr const char* GRABBERTYPE = "OSX";
///
/// Constructs the osx frame grabber with a specified grab size and update rate.
///
@@ -23,6 +25,12 @@ public:
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION
);
///
/// Constructs the QT frame grabber from configuration settings
///
OsxWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
public slots:
///
/// Performs a single frame grab and computes the led-colors

View File

@@ -113,8 +113,8 @@ private:
int _display;
int _numberOfSDisplays;
int _calculatedWidth;
int _calculatedHeight;
int _screenWidth;
int _screenHeight;
int _src_x;
int _src_y;
int _src_x_max;

View File

@@ -1,14 +1,20 @@
#pragma once
#include <QJsonObject>
#include <QStringLiteral>
#include <hyperion/GrabberWrapper.h>
#include <grabber/QtGrabber.h>
#include <grabber/qt/QtGrabber.h>
///
/// The QtWrapper uses QtFramework API's to get a picture from system
///
class QtWrapper: public GrabberWrapper
{
public:
static constexpr const char* GRABBERTYPE = "Qt";
///
/// Constructs the QT frame grabber with a specified grab size and update rate.
///
@@ -19,7 +25,6 @@ public:
/// @param[in] cropRight Remove from right [pixels]
/// @param[in] cropTop Remove from top [pixels]
/// @param[in] cropBottom Remove from bottom [pixels]
///
QtWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int display=0,
@@ -28,6 +33,11 @@ public:
int cropTop=0, int cropBottom=0
);
///
/// Constructs the QT frame grabber from configuration settings
///
QtWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
///
/// Starts the grabber which produces led values with the specified update rate
///

View File

@@ -136,11 +136,11 @@ class EncoderThreadManager : public QObject
public:
explicit EncoderThreadManager(QObject *parent = nullptr)
: QObject(parent)
, _threadCount(static_cast<unsigned long>(qMax(QThread::idealThreadCount(), DEFAULT_THREAD_COUNT)))
, _threadCount(qMax(QThread::idealThreadCount(), DEFAULT_THREAD_COUNT))
, _threads(nullptr)
{
_threads = new Thread<EncoderThread>*[_threadCount];
for (unsigned long i = 0; i < _threadCount; i++)
for (int i = 0; i < _threadCount; i++)
{
_threads[i] = new Thread<EncoderThread>(new EncoderThread, this);
_threads[i]->setObjectName("Encoder " + QString::number(i));
@@ -151,7 +151,7 @@ public:
{
if (_threads != nullptr)
{
for(unsigned long i = 0; i < _threadCount; i++)
for(int i = 0; i < _threadCount; i++)
{
_threads[i]->deleteLater();
_threads[i] = nullptr;
@@ -165,18 +165,18 @@ public:
void start()
{
if (_threads != nullptr)
for (unsigned long i = 0; i < _threadCount; i++)
for (int i = 0; i < _threadCount; i++)
connect(_threads[i]->thread(), &EncoderThread::newFrame, this, &EncoderThreadManager::newFrame);
}
void stop()
{
if (_threads != nullptr)
for(unsigned long i = 0; i < _threadCount; i++)
for(int i = 0; i < _threadCount; i++)
disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr);
}
unsigned long _threadCount;
int _threadCount;
Thread<EncoderThread>** _threads;
signals:

View File

@@ -4,13 +4,9 @@
#include <hyperion/GrabberWrapper.h>
#if defined(ENABLE_MF)
#include <grabber/MFGrabber.h>
#include <grabber/video/mediafoundation/MFGrabber.h>
#elif defined(ENABLE_V4L2)
#include <grabber/V4L2Grabber.h>
#endif
#if defined(ENABLE_CEC)
#include <cec/CECEvent.h>
#include <grabber/video/v4l2/V4L2Grabber.h>
#endif
class VideoWrapper : public GrabberWrapper
@@ -25,10 +21,6 @@ public slots:
bool start() override;
void stop() override;
#if defined(ENABLE_CEC)
void handleCecEvent(CECEvent event);
#endif
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) override;
private slots:

View File

@@ -21,7 +21,7 @@
#include <hyperion/Grabber.h>
// decoder thread includes
#include <grabber/EncoderThread.h>
#include <grabber/video/EncoderThread.h>
/// Forward class declaration
class SourceReaderCB;
@@ -119,7 +119,7 @@ private:
QAtomicInt _currentFrame;
ColorRgb _noSignalThresholdColor;
bool _signalDetectionEnabled,
_noSignalDetected,
_signalDetected,
_initialized,
_reload;
double _x_frac_min,

View File

@@ -1,5 +1,11 @@
#pragma once
#define NOFRAME_BENCH
#ifdef FRAME_BENCH
#include <QElapsedTimer>
#endif
// stl includes
#include <vector>
#include <map>
@@ -19,14 +25,12 @@
#include <utils/Components.h>
// decoder thread includes
#include <grabber/EncoderThread.h>
#include <grabber/video/EncoderThread.h>
// Determine the cmake options
#include <HyperionConfig.h>
#if defined(ENABLE_CEC)
#include <cec/CECEvent.h>
#endif
#include <events/EventEnum.h>
///
/// Capture class for V4L2 devices
@@ -77,13 +81,10 @@ public:
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold = 50);
void setSignalDetectionOffset( double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
void setCecDetectionEnable(bool enable);
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
///
/// @brief Discover available V4L2 USB devices (for configuration).
/// @param[in] params Parameters used to overwrite discovery default behaviour
@@ -97,10 +98,6 @@ public slots:
void stop();
void newThreadFrame(Image<ColorRgb> image);
#if defined(ENABLE_CEC)
void handleCecEvent(CECEvent event);
#endif
signals:
void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
@@ -167,7 +164,7 @@ private:
// signal detection
int _noSignalCounterThreshold;
ColorRgb _noSignalThresholdColor;
bool _cecDetectionEnabled, _cecStandbyActivated, _signalDetectionEnabled, _noSignalDetected;
bool _standbyActivated, _signalDetectionEnabled, _signalDetected;
int _noSignalCounter;
int _brightness, _contrast, _saturation, _hue;
double _x_frac_min;
@@ -175,6 +172,9 @@ private:
double _x_frac_max;
double _y_frac_max;
#ifdef FRAME_BENCH
QElapsedTimer _frameTimer;
#endif
QSocketNotifier *_streamNotifier;
bool _initialized, _reload;

View File

@@ -57,7 +57,7 @@ public:
///
/// @brief Apply new width/height values, overwrite Grabber.h implementation as X11 doesn't use width/height, just pixelDecimation to calc dimensions
///
bool setWidthHeight(int width, int height) override { return true; }
bool setWidthHeight(int /*width*/, int /*height*/) override { return true; }
///
/// @brief Apply new pixelDecimation
@@ -109,19 +109,19 @@ private:
Picture _srcPicture;
Picture _dstPicture;
int _XRandREventBase;
int _xRandREventBase;
XTransform _transform;
unsigned _calculatedWidth;
unsigned _calculatedHeight;
unsigned _src_x;
unsigned _src_y;
int _screenWidth;
int _screenHeight;
int _src_x;
int _src_y;
bool _XShmAvailable;
bool _XShmPixmapAvailable;
bool _XRenderAvailable;
bool _XRandRAvailable;
bool _xShmAvailable;
bool _xShmPixmapAvailable;
bool _xRenderAvailable;
bool _xRandRAvailable;
bool _isWayland;
Logger * _logger;

View File

@@ -1,13 +1,12 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/X11Grabber.h>
#include <grabber/x11/X11Grabber.h>
// some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions
#ifdef None
#undef None
#endif
///
/// The X11Wrapper uses an instance of the X11Grabber to obtain ImageRgb's from the displayed content.
/// This ImageRgb is processed to a ColorRgb for each led and committed to the attached Hyperion.
@@ -15,6 +14,8 @@
class X11Wrapper: public GrabberWrapper
{
public:
static constexpr const char* GRABBERTYPE = "X11";
///
/// Constructs the X11 frame grabber with a specified grab size and update rate.
///
@@ -27,6 +28,11 @@ public:
int cropTop=0, int cropBottom=0
);
///
/// Constructs the X11 frame grabber from configuration settings
///
X11Wrapper(const QJsonDocument& grabberConfig = QJsonDocument());
///
/// Destructor of this frame grabber. Releases any claimed resources.
///

View File

@@ -0,0 +1,47 @@
#pragma once
#include <hyperion/GrabberWrapper.h>
#include <grabber/xcb/XcbGrabber.h>
// some include of xorg defines "None" this is also used by QT and has to be undefined to avoid collisions
#ifdef None
#undef None
#endif
class XcbWrapper: public GrabberWrapper
{
public:
static constexpr const char* GRABBERTYPE = "XCB";
///
/// Constructs the XCB frame grabber with a specified grab size and update rate.
///
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] pixelDecimation Decimation factor for image [pixels]
/// @param[in] cropLeft Remove from left [pixels]
/// @param[in] cropRight Remove from right [pixels]
/// @param[in] cropTop Remove from top [pixels]
/// @param[in] cropBottom Remove from bottom [pixels]
///
XcbWrapper( int updateRate_Hz=GrabberWrapper::DEFAULT_RATE_HZ,
int pixelDecimation=GrabberWrapper::DEFAULT_PIXELDECIMATION,
int cropLeft=0, int cropRight=0,
int cropTop=0, int cropBottom=0
);
///
/// Constructs the XCB frame grabber from configuration settings
///
XcbWrapper(const QJsonDocument& grabberConfig = QJsonDocument());
~XcbWrapper() override;
public slots:
void action() override;
private:
XcbGrabber _grabber;
bool _init;
};

View File

@@ -3,6 +3,8 @@
#include <utils/Logger.h>
#include <utils/settings.h>
#include <db/AuthTable.h>
//qt
#include <QMap>
#include <QVector>
@@ -41,24 +43,12 @@ public:
///
QString getID() const { return _uuid; }
///
/// @brief Check authorization is required according to the user setting
/// @return True if authorization required else false
///
bool isAuthRequired() const { return _authRequired; }
///
/// @brief Check if authorization is required for local network connections
/// @return True if authorization required else false
///
bool isLocalAuthRequired() const { return _localAuthRequired; }
///
/// @brief Check if authorization is required for local network connections for admin access
/// @return True if authorization required else false
///
bool isLocalAdminAuthRequired() const { return _localAdminAuthRequired; }
///
/// @brief Reset Hyperion user
/// @return True on success else false
@@ -172,7 +162,7 @@ public slots:
/// @param usr the defined user
/// @return The token
///
QString getUserToken(const QString &usr = "Hyperion") const;
QString getUserToken(const QString &usr = hyperion::DEFAULT_USER) const;
///
/// @brief Get all available token entries
@@ -230,15 +220,9 @@ private:
/// All pending requests
QMap<QString, AuthDefinition> _pendingRequests;
/// Reflect state of global auth
bool _authRequired;
/// Reflect state of local auth
bool _localAuthRequired;
/// Reflect state of local admin auth
bool _localAdminAuthRequired;
/// Timer for counting against pendingRequest timeouts
QTimer *_timer;

View File

@@ -43,6 +43,16 @@ public:
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
}
///
/// @brief Disconnect from connected signals
/// Disconnect should be done before other priorities invoke methods during shutdown
///
void disconnect()
{
QObject::disconnect(_prioMuxer, &PriorityMuxer::prioritiesChanged, nullptr, nullptr);
QObject::disconnect(_hyperion, nullptr, nullptr, nullptr);
}
///
/// @brief Check, if background effect processing is enabled.
/// @return True, background effect processing is enabled.

View File

@@ -16,21 +16,21 @@ public:
QString _id;
/// The BLACK (RGB-Channel) adjustment
RgbChannelAdjustment _rgbBlackAdjustment;
RgbChannelAdjustment _rgbBlackAdjustment {0, 0, 0, "black"};
/// The WHITE (RGB-Channel) adjustment
RgbChannelAdjustment _rgbWhiteAdjustment;
RgbChannelAdjustment _rgbWhiteAdjustment{255, 255, 255, "white"};
/// The RED (RGB-Channel) adjustment
RgbChannelAdjustment _rgbRedAdjustment;
RgbChannelAdjustment _rgbRedAdjustment {255, 0, 0 , "red"};
/// The GREEN (RGB-Channel) adjustment
RgbChannelAdjustment _rgbGreenAdjustment;
RgbChannelAdjustment _rgbGreenAdjustment {0, 255, 0, "green"};
/// The BLUE (RGB-Channel) adjustment
RgbChannelAdjustment _rgbBlueAdjustment;
RgbChannelAdjustment _rgbBlueAdjustment {0, 0, 255, "blue"};
/// The CYAN (RGB-Channel) adjustment
RgbChannelAdjustment _rgbCyanAdjustment;
RgbChannelAdjustment _rgbCyanAdjustment {0, 255, 255, "cyan"};
/// The MAGENTA (RGB-Channel) adjustment
RgbChannelAdjustment _rgbMagentaAdjustment;
RgbChannelAdjustment _rgbMagentaAdjustment {255, 0, 255, "magenta"};
/// The YELLOW (RGB-Channel) adjustment
RgbChannelAdjustment _rgbYellowAdjustment;
RgbChannelAdjustment _rgbYellowAdjustment {255, 255, 0, "yellow"};
RgbTransform _rgbTransform;
OkhsvTransform _okhsvTransform;

View File

@@ -11,6 +11,8 @@
#include <utils/Logger.h>
#include <utils/Components.h>
#include <events/EventEnum.h>
///
/// @brief The Grabber class is responsible to apply image resizes (with or without ImageResampler)
@@ -111,6 +113,17 @@ public:
QString getGrabberName() const { return _grabberName; }
///
/// @brief Determine if the grabber is available.
///
/// @return true, on success (i.e. library is present), else false
///
virtual bool isAvailable() { return _isAvailable; }
public slots:
virtual void handleEvent(Event event) {}
protected slots:
///
/// @brief Set device in error state
@@ -162,10 +175,15 @@ protected:
// Device states
/// Is the device available?
bool _isAvailable;
/// Is the device enabled?
bool _isEnabled;
/// Is the device in error state and stopped?
bool _isDeviceInError;
};

View File

@@ -6,6 +6,7 @@
#include <QString>
#include <QStringList>
#include <QMultiMap>
#include <QScopedPointer>
#include <utils/Logger.h>
#include <utils/Components.h>
@@ -18,6 +19,8 @@
#include <grabber/GrabberType.h>
#include <events/EventEnum.h>
class Grabber;
class GlobalSignals;
class QTimer;
@@ -29,6 +32,14 @@ class GrabberWrapper : public QObject
{
Q_OBJECT
public:
static constexpr const char* GRABBERTYPE = "Base";
template<typename GrabberType>
static QSharedPointer<GrabberType> create(const QJsonDocument& config) {
return QSharedPointer<GrabberType>::create(config);
}
GrabberWrapper(const QString& grabberName, Grabber * ggrabber,int updateRate_Hz = DEFAULT_RATE_HZ);
~GrabberWrapper() override;
@@ -68,6 +79,11 @@ public:
///
virtual bool isActive() const;
virtual bool isAvailable() { return _isAvailable; }
QString getName() { return _grabberName; }
///
/// @brief Get active grabber name
/// @param hyperionInd The instance index
@@ -89,8 +105,8 @@ public:
template <typename Grabber_T>
bool transferFrame(Grabber_T &grabber)
{
unsigned w = grabber.getImageWidth();
unsigned h = grabber.getImageHeight();
int w = grabber.getImageWidth();
int h = grabber.getImageHeight();
if ( _image.width() != w || _image.height() != h)
{
_image.resize(w, h);
@@ -139,6 +155,8 @@ public slots:
///
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
void handleEvent(Event event);
signals:
///
/// @brief Emit the final processed image
@@ -181,7 +199,7 @@ protected:
Logger * _log;
/// The timer for generating events with the specified update rate
QTimer* _timer;
QScopedPointer<QTimer> _timer;
/// The calculated update rate [ms]
int _updateInterval_ms;
@@ -190,4 +208,6 @@ protected:
/// The image used for grabbing frames
Image<ColorRgb> _image;
bool _isAvailable;
};

View File

@@ -67,6 +67,7 @@ class Hyperion : public QObject
Q_OBJECT
public:
/// Type definition of the info structure used by the priority muxer
using InputsMap = PriorityMuxer::InputsMap;
using InputInfo = PriorityMuxer::InputInfo;
///
@@ -107,7 +108,7 @@ public:
///
QString getActiveDeviceType() const;
bool getReadOnlyMode() {return _readOnlyMode; }
bool getReadOnlyMode() const {return _readOnlyMode; }
public slots:
@@ -235,13 +236,13 @@ public slots:
/// @param priority The priority channel of the effect
/// @param timeout The timeout of the effect (after the timout, the effect will be cleared)
int setEffect(const QString &effectName
, const QJsonObject &args
, int priority
, int timeout = PriorityMuxer::ENDLESS
, const QString &pythonScript = ""
, const QString &origin="System"
, const QString &imageData = ""
);
, const QJsonObject &args
, int priority
, int timeout = PriorityMuxer::ENDLESS
, const QString &pythonScript = ""
, const QString &origin="System"
, const QString &imageData = ""
);
/// Get the list of available effects
/// @return The list of available effects
@@ -303,7 +304,14 @@ public slots:
QList<int> getActivePriorities() const;
///
/// Returns the information of a specific priorrity channel
/// Returns the information of all priority channels.
///
/// @return The information fo all priority channels
///
PriorityMuxer::InputsMap getPriorityInfo() const;
///
/// Returns the information of a specific priority channel
///
/// @param[in] priority The priority channel
///
@@ -346,7 +354,7 @@ public slots:
/// @brief Get the component Register
/// return Component register pointer
///
ComponentRegister* getComponentRegister() { return _componentRegister; }
ComponentRegister* getComponentRegister() const { return _componentRegister; }
///
/// @brief Called from components to update their current state. DO NOT CALL FROM USERS

View File

@@ -5,6 +5,7 @@
#include <utils/VideoMode.h>
#include <utils/settings.h>
#include <utils/Components.h>
#include <events/EventEnum.h>
// qt
#include <QMap>
@@ -54,10 +55,16 @@ public slots:
Hyperion* getHyperionInstance(quint8 instance = 0);
///
/// @brief Get instance data of all instaces in db + running state
/// @brief Get instance data of all instances in db + running state
///
QVector<QVariantMap> getInstanceData() const;
///
/// @brief Get all instance indicies of running instances
///
QList<quint8> getRunningInstanceIdx() const;
///
/// @brief Start a Hyperion instance
/// @param instance Instance index
@@ -74,20 +81,10 @@ public slots:
bool stopInstance(quint8 inst);
///
/// @brief Suspend (disable) all Hyperion instances
/// @brief Handle an Hyperion Event
/// @param event Event to be processed
///
void suspend();
///
/// @brief Resume (resume) all Hyperion instances
///
void resume();
///
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio (user is not interacting with the system
/// @param isIdle, If true all instances toggle to idle, else to resume
///
void toggleIdle(bool isIdle);
void handleEvent(Event event);
///
/// @brief Toggle the state of all Hyperion instances
@@ -141,10 +138,6 @@ signals:
///
void startInstanceResponse(QObject *caller, const int &tan);
void triggerSuspend(bool isSuspend);
void triggerToggleSuspend();
void triggerIdle(bool isIdle);
void triggerToggleIdle();
signals:
///////////////////////////////////////
@@ -186,6 +179,18 @@ private slots:
///
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:
friend class HyperionDaemon;
///

View File

@@ -413,9 +413,13 @@ namespace hyperion
}
// Compute the average of each color channel
const uint8_t avgRed = uint8_t(std::min(std::lround(sqrt(static_cast<double>(cummRed/pixelNum))), 255L));
const uint8_t avgGreen = uint8_t(std::min(std::lround(sqrt(static_cast<double>(cummGreen/pixelNum))), 255L));
const uint8_t avgBlue = uint8_t(std::min(std::lround(sqrt(static_cast<double>(cummBlue/pixelNum))), 255L));
#ifdef WIN32
#undef min
#endif
const uint8_t avgRed = static_cast<uint8_t>(std::min(std::lround(std::sqrt(static_cast<double>(cummRed / pixelNum))), 255L));
const uint8_t avgGreen = static_cast<uint8_t>(std::min(std::lround(sqrt(static_cast<double>(cummGreen / pixelNum))), 255L));
const uint8_t avgBlue = static_cast<uint8_t>(std::min(std::lround(sqrt(static_cast<double>(cummBlue / pixelNum))), 255L));
// Return the computed color
return {avgRed, avgGreen, avgBlue};
@@ -551,7 +555,7 @@ namespace hyperion
if (pixelNum > 0)
{
// initial cluster with different colors
auto clusters = std::unique_ptr< ColorCluster<ColorRgbScalar> >(new ColorCluster<ColorRgbScalar>[_clusterCount]);
std::unique_ptr<ColorCluster<ColorRgbScalar>[]> clusters(new ColorCluster<ColorRgbScalar>[_clusterCount]);
for(int k = 0; k < _clusterCount; ++k)
{
clusters.get()[k].newColor = DEFAULT_CLUSTER_COLORS[k];

View File

@@ -10,6 +10,7 @@
// QT includes
#include <QString>
#include <QJsonArray>
// Forward class declarations
namespace Json { class Value; }
@@ -73,7 +74,7 @@ inline ColorOrder stringToColorOrder(const QString & order)
}
///
/// The Led structure contains the definition of the image portion used to determine a single led's
/// The Led structure contains the definition of the image portion used to determine a single LED's
/// color.
/// @verbatim
/// |--------------------image--|
@@ -89,39 +90,66 @@ inline ColorOrder stringToColorOrder(const QString & order)
///
struct Led
{
/// The minimum vertical scan line included for this leds color
/// The minimum vertical scan line included for this LEDs color
double minX_frac;
/// The maximum vertical scan line included for this leds color
/// The maximum vertical scan line included for this LEDs color
double maxX_frac;
/// The minimum horizontal scan line included for this leds color
/// The minimum horizontal scan line included for this LEDs color
double minY_frac;
/// The maximum horizontal scan line included for this leds color
/// The maximum horizontal scan line included for this LEDs color
double maxY_frac;
/// A LEDs at {0,0,0,0} is not visible and therefore treated as blacklisted
bool isBlacklisted {false};
/// the color order
ColorOrder colorOrder;
};
///
/// The LedString contains the image integration information of the leds
/// The LedString contains the image integration information of the LEDs
///
class LedString
{
public:
///
/// Returns the led specifications
/// Returns the LED specifications
///
/// @return The list with led specifications
///
std::vector<Led>& leds();
///
/// Returns the led specifications
/// Returns the LED specifications
///
/// @return The list with led specifications
///
const std::vector<Led>& leds() const;
///
/// Returns the IDs of blacklisted LEDs
///
/// @return ID List of blacklisted LEDs
///
std::vector<int>& blacklistedLedIds();
///
/// Returns the IDs of blacklisted LEDs
///
/// @return ID List of blacklisted LEDs
///
const std::vector<int>& blacklistedLedIds() const;
///
/// Check, if teh layout has blacklisted LEDs configured
///
/// @return True, if blacklisted LEDs are configured
///
bool hasBlackListedLeds ();
static LedString createLedString(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder);
private:
/// The list with led specifications
std::vector<Led> mLeds;
/// The list with LED specifications
std::vector<Led> _leds;
/// The list containing IDs of blacklisted LED
std::vector<int> _blacklistedLedIds;
};

View File

@@ -141,6 +141,13 @@ public:
///
QList<int> getPriorities() const;
///
/// Returns the information of all priority channels.
///
/// @return The information fo all priority channels
///
InputsMap getInputInfo() const;
///
/// Returns the information of a specified priority channel.
/// If a priority is no longer available the _lowestPriorityInfo (255) is returned

View File

@@ -2,7 +2,6 @@
#define MDNS_BROWSER_H
#include <chrono>
#include <type_traits>
#include <qmdnsengine/server.h>
#include <qmdnsengine/service.h>
@@ -16,6 +15,10 @@
// Qt includes
#include <QObject>
#include <QByteArray>
#include <QMap>
#include <QJsonArray>
#include <QScopedPointer>
#include <QSharedPointer>
// Utility includes
#include <utils/Logger.h>
@@ -24,15 +27,12 @@
namespace {
constexpr std::chrono::milliseconds DEFAULT_DISCOVER_TIMEOUT{ 500 };
constexpr std::chrono::milliseconds DEFAULT_ADDRESS_RESOLVE_TIMEOUT{ 1000 };
} //End of constants
} // End of constants
class MdnsBrowser : public QObject
{
Q_OBJECT
// Run MdnsBrowser as singleton
private:
///
/// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon
@@ -40,25 +40,20 @@ private:
///
// Run MdnsBrowser as singleton
MdnsBrowser(QObject* parent = nullptr);
~MdnsBrowser() override;
public:
static MdnsBrowser& getInstance()
{
static MdnsBrowser* instance = new MdnsBrowser();
return *instance;
}
MdnsBrowser(const MdnsBrowser&) = delete;
MdnsBrowser(MdnsBrowser&&) = delete;
MdnsBrowser& operator=(const MdnsBrowser&) = delete;
MdnsBrowser& operator=(MdnsBrowser&&) = delete;
static QScopedPointer<MdnsBrowser> instance;
public:
~MdnsBrowser() override;
static QScopedPointer<MdnsBrowser>& getInstance();
QMdnsEngine::Service getFirstService(const QByteArray& serviceType, const QString& filter = ".*", const std::chrono::milliseconds waitTime = DEFAULT_DISCOVER_TIMEOUT) const;
QJsonArray getServicesDiscoveredJson(const QByteArray& serviceType, const QString& filter = ".*", const std::chrono::milliseconds waitTime = std::chrono::milliseconds{ 0 }) const;
void printCache(const QByteArray& name = QByteArray(), quint16 type = QMdnsEngine::ANY) const;
public slots:
@@ -109,8 +104,9 @@ private:
QMdnsEngine::Server _server;
QMdnsEngine::Cache _cache;
QSharedPointer<QMdnsEngine::Resolver> _resolver;
QMap<QByteArray, QMdnsEngine::Browser*> _browsedServiceTypes;
QMap<QByteArray, QSharedPointer<QMdnsEngine::Browser>> _browsedServiceTypes;
};
#endif // MDNSBROWSER_H

View File

@@ -9,6 +9,7 @@
// Qt includes
#include <QObject>
#include <QByteArray>
#include <QScopedPointer>
// Utility includes
#include <utils/Logger.h>
@@ -41,11 +42,11 @@ private:
/// The logger instance for mDNS-Service
Logger* _log;
QMdnsEngine::Server* _server;
QMdnsEngine::Hostname* _hostname;
QScopedPointer<QMdnsEngine::Server> _server;
QScopedPointer<QMdnsEngine::Hostname> _hostname;
/// map of services provided
QMap<QByteArray, QMdnsEngine::Provider*> _providedServiceTypes;
QMap<QByteArray, QSharedPointer<QMdnsEngine::Provider>> _providedServiceTypes;
};
#endif // MDNSPROVIDER_H

View File

@@ -15,9 +15,8 @@ public:
{
}
Image(unsigned width, unsigned height) :
Image(int width, int height) :
Image(width, height, Pixel_T())
{
}
@@ -28,7 +27,7 @@ public:
/// @param height The height of the image
/// @param background The color of the image
///
Image(unsigned width, unsigned height, const Pixel_T background) :
Image(int width, int height, const Pixel_T background) :
_d_ptr(new ImageData<Pixel_T>(width, height, background))
{
}
@@ -78,7 +77,7 @@ public:
///
/// @return The width of the image
///
inline unsigned width() const
inline int width() const
{
return _d_ptr->width();
}
@@ -88,7 +87,7 @@ public:
///
/// @return The height of the image
///
inline unsigned height() const
inline int height() const
{
return _d_ptr->height();
}
@@ -111,7 +110,7 @@ public:
///
/// @return const reference to specified pixel
///
uint8_t blue(unsigned pixel) const
uint8_t blue(int pixel) const
{
return _d_ptr->blue(pixel);
}
@@ -121,7 +120,7 @@ public:
///
/// @param x The x index
/// @param y The y index
const Pixel_T& operator()(unsigned x, unsigned y) const
const Pixel_T& operator()(int x, int y) const
{
return _d_ptr->operator()(x, y);
}
@@ -129,7 +128,7 @@ public:
///
/// @return reference to specified pixel
///
Pixel_T& operator()(unsigned x, unsigned y)
Pixel_T& operator()(int x, int y)
{
return _d_ptr->operator()(x, y);
}
@@ -137,7 +136,7 @@ public:
/// Resize the image
/// @param width The width of the image
/// @param height The height of the image
void resize(unsigned width, unsigned height)
void resize(int width, int height)
{
_d_ptr->resize(width, height);
}
@@ -198,12 +197,11 @@ private:
///
/// @return The index into the underlying data-vector
///
inline unsigned toIndex(unsigned x, unsigned y) const
inline int toIndex(int x, int y) const
{
return _d_ptr->toIndex(x, y);
}
private:
QSharedDataPointer<ImageData<Pixel_T>> _d_ptr;
};

View File

@@ -1,12 +1,9 @@
#pragma once
// STL includes
#include <vector>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <cassert>
#include <type_traits>
#include <utils/ColorRgb.h>
// QT includes
@@ -24,10 +21,10 @@ class ImageData : public QSharedData
public:
typedef Pixel_T pixel_type;
ImageData(unsigned width, unsigned height, const Pixel_T background) :
ImageData(int width, int height, const Pixel_T background) :
_width(width),
_height(height),
_pixels(new Pixel_T[width * height + 1])
_pixels(new Pixel_T[static_cast<size_t>(width) * static_cast<size_t>(height)])
{
std::fill(_pixels, _pixels + width * height, background);
}
@@ -36,9 +33,9 @@ public:
QSharedData(other),
_width(other._width),
_height(other._height),
_pixels(new Pixel_T[other._width * other._height + 1])
_pixels(new Pixel_T[static_cast<size_t>(other._width) * static_cast<size_t>(other._height)])
{
memcpy(_pixels, other._pixels, static_cast<ulong>(other._width) * static_cast<ulong>(other._height) * sizeof(Pixel_T));
memcpy(_pixels, other._pixels, static_cast<size_t>(other._width) * static_cast<size_t>(other._height) * sizeof(Pixel_T));
}
ImageData& operator=(ImageData rhs)
@@ -74,52 +71,57 @@ public:
delete[] _pixels;
}
inline unsigned width() const
inline int width() const
{
return _width;
}
inline unsigned height() const
inline int height() const
{
return _height;
}
uint8_t red(unsigned pixel) const
uint8_t red(int pixel) const
{
return (_pixels + pixel)->red;
}
uint8_t green(unsigned pixel) const
uint8_t green(int pixel) const
{
return (_pixels + pixel)->green;
}
uint8_t blue(unsigned pixel) const
uint8_t blue(int pixel) const
{
return (_pixels + pixel)->blue;
}
const Pixel_T& operator()(unsigned x, unsigned y) const
const Pixel_T& operator()(int x, int y) const
{
return _pixels[toIndex(x,y)];
}
Pixel_T& operator()(unsigned x, unsigned y)
Pixel_T& operator()(int x, int y)
{
return _pixels[toIndex(x,y)];
}
void resize(unsigned width, unsigned height)
void resize(int width, int height)
{
if (width == _width && height == _height)
return;
if ((width * height) > unsigned((_width * _height)))
{
delete[] _pixels;
_pixels = new Pixel_T[width*height + 1];
return;
}
// Allocate a new buffer without initializing the content
Pixel_T* newPixels = new Pixel_T[static_cast<size_t>(width) * static_cast<size_t>(height)];
// Release the old buffer without copying data
delete[] _pixels;
// Update the pointer to the new buffer
_pixels = newPixels;
_width = width;
_height = height;
}
@@ -137,11 +139,13 @@ public:
void toRgb(ImageData<ColorRgb>& image) const
{
if (image.width() != _width || image.height() != _height)
{
image.resize(_width, _height);
}
const unsigned imageSize = _width * _height;
const int imageSize = _width * _height;
for (unsigned idx = 0; idx < imageSize; idx++)
for (int idx = 0; idx < imageSize; idx++)
{
const Pixel_T & color = _pixels[idx];
image.memptr()[idx] = ColorRgb{color.red, color.green, color.blue};
@@ -157,26 +161,22 @@ public:
{
if (_width != 1 || _height != 1)
{
_width = 1;
_height = 1;
delete[] _pixels;
_pixels = new Pixel_T[2];
resize(1,1);
}
memset(_pixels, 0, static_cast<unsigned long>(_width) * static_cast<unsigned long>(_height) * sizeof(Pixel_T));
// Set the single pixel to the default background
_pixels[0] = Pixel_T();
}
private:
inline unsigned toIndex(unsigned x, unsigned y) const
inline int toIndex(int x, int y) const
{
return y * _width + x;
}
private:
/// The width of the image
unsigned _width;
int _width;
/// The height of the image
unsigned _height;
int _height;
/// The pixels of the image
Pixel_T* _pixels;
};

View File

@@ -3,6 +3,8 @@
#include <utils/FileUtils.h>
#include <QJsonObject>
#include <QPair>
#include <QStringList>
#include <utils/Logger.h>
namespace JsonUtils {
@@ -14,7 +16,7 @@ namespace JsonUtils {
/// @param[in] ignError Ignore errors during file read (no log output)
/// @return true on success else false
///
bool readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError=false);
QPair<bool, QStringList> readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError=false);
///
/// @brief read a schema file and resolve $refs
@@ -33,7 +35,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);
///
/// @brief parse a json QString and get a QJsonArray. Overloaded function
@@ -42,8 +44,8 @@ namespace JsonUtils {
/// @param[out] arr Retuns the parsed QJsonArray
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);
//
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);
///
/// @brief parse a json QString and get a QJsonDocument
@@ -53,7 +55,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);
///
/// @brief Validate json data against a schema
@@ -63,7 +65,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);
///
/// @brief Validate json data against a schema
@@ -73,7 +75,7 @@ namespace JsonUtils {
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);
///
/// @brief Write json data to file

View File

@@ -6,6 +6,8 @@
#include <QMap>
#include <QAtomicInteger>
#include <QList>
#include <QJsonArray>
#include <QScopedPointer>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
#include <QRecursiveMutex>
@@ -14,8 +16,6 @@
#endif
// stl includes
#include <stdio.h>
#include <stdarg.h>
#ifdef _WIN32
#include <stdexcept>
#endif
@@ -59,7 +59,7 @@ public:
QString function;
unsigned int line;
QString fileName;
uint64_t utime;
qint64 utime;
QString message;
LogLevel level;
QString levelString;
@@ -74,7 +74,7 @@ public:
void setMinLevel(LogLevel level) { _minLevel = static_cast<int>(level); }
LogLevel getMinLevel() const { return static_cast<LogLevel>(int(_minLevel)); }
QString getName() const { return _name; }
QString getSubName() const { return _subname; }
QString getSubName() const { return _subName; }
signals:
void newLogMessage(Logger::T_LOG_MESSAGE);
@@ -95,7 +95,7 @@ private:
static QAtomicInteger<int> GLOBAL_MIN_LOG_LEVEL;
const QString _name;
const QString _subname;
const QString _subName;
const bool _syslogEnabled;
const unsigned _loggerId;
@@ -107,18 +107,28 @@ class LoggerManager : public QObject
{
Q_OBJECT
private:
// Run LoggerManager as singleton
LoggerManager();
LoggerManager(const LoggerManager&) = delete;
LoggerManager(LoggerManager&&) = delete;
LoggerManager& operator=(const LoggerManager&) = delete;
LoggerManager& operator=(LoggerManager&&) = delete;
static QScopedPointer<LoggerManager> instance;
public:
static LoggerManager* getInstance();
const QList<Logger::T_LOG_MESSAGE>* getLogMessageBuffer() const { return &_logMessageBuffer; }
~LoggerManager() override;
static QScopedPointer<LoggerManager>& getInstance();
public slots:
void handleNewLogMessage(const Logger::T_LOG_MESSAGE&);
QJsonArray getLogMessageBuffer(Logger::LogLevel filter=Logger::UNSET) const;
signals:
void newLogMessage(const Logger::T_LOG_MESSAGE&);
protected:
LoggerManager();
private:
QList<Logger::T_LOG_MESSAGE> _logMessageBuffer;
const int _loggerMaxMsgBufferSize;

View File

@@ -47,7 +47,9 @@ private slots:
private:
Logger* _log;
/// True when internet access is allowed
bool _internetAccessAllowed;
bool _isInternetAccessAllowed;
/// True when internet access is restricted by a white list
bool _isInternetAccessRestricted;
/// Whitelisted ip addresses
QList<QHostAddress> _ipWhitelist;

View File

@@ -111,7 +111,7 @@ namespace NetUtils {
if (hostname.endsWith(".local") || hostname.endsWith(".local."))
{
QHostAddress resolvedAddress;
QMetaObject::invokeMethod(&MdnsBrowser::getInstance(), "resolveAddress",
QMetaObject::invokeMethod(MdnsBrowser::getInstance().data(), "resolveAddress",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, isHostAddressOK),
Q_ARG(Logger*, log), Q_ARG(QString, hostname), Q_ARG(QHostAddress&, resolvedAddress));
@@ -163,7 +163,7 @@ namespace NetUtils {
if (hostname.endsWith("._tcp.local"))
{
//Treat hostname as service instance name that requires to be resolved into an mDNS-Hostname first
QMdnsEngine::Record service = MdnsBrowser::getInstance().getServiceInstanceRecord(hostname.toUtf8());
QMdnsEngine::Record service = MdnsBrowser::getInstance().data()->getServiceInstanceRecord(hostname.toUtf8());
if (!service.target().isEmpty())
{
Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());

View File

@@ -1,4 +1,5 @@
#pragma once
#ifndef PIXELFORMAT_H
#define PIXELFORMAT_H
#include <QString>
@@ -14,9 +15,7 @@ enum class PixelFormat {
BGR32,
NV12,
I420,
#ifdef HAVE_TURBO_JPEG
MJPEG,
#endif
NO_CHANGE
};
@@ -57,12 +56,10 @@ inline PixelFormat parsePixelFormat(const QString& pixelFormat)
{
return PixelFormat::NV12;
}
#ifdef HAVE_TURBO_JPEG
else if (format.compare("mjpeg") == 0)
{
return PixelFormat::MJPEG;
}
#endif
// return the default NO_CHANGE
return PixelFormat::NO_CHANGE;
@@ -103,12 +100,10 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
{
return "NV12";
}
#ifdef HAVE_TURBO_JPEG
else if (pixelFormat == PixelFormat::MJPEG)
{
return "MJPEG";
}
#endif
// return the default NO_CHANGE
return "NO_CHANGE";
@@ -166,3 +161,5 @@ inline QString flipModeToString(const FlipMode& flipMode)
// return the default NO_CHANGE
return "NO_CHANGE";
}
#endif // PIXELFORMAT_H

View File

@@ -3,9 +3,8 @@
#include <QString>
#include <QByteArray>
namespace Process {
void restartHyperion(int exitCode = 0);
QByteArray command_exec(const QString& cmd, const QByteArray& data = {});
namespace Process
{
void restartHyperion(int exitCode = 0);
QByteArray command_exec(const QString& cmd, const QByteArray& data = {});
}

View File

@@ -1,6 +1,6 @@
#pragma once
#define QSTRING_CSTR(str) str.toLocal8Bit().constData()
#define QSTRING_CSTR(str) str.toUtf8().constData()
typedef QList< int > QIntList;

View File

@@ -96,7 +96,7 @@ namespace hyperion {
static_cast<uint8_t>(channelConfig[0].toInt(defaultR)),
static_cast<uint8_t>(channelConfig[1].toInt(defaultG)),
static_cast<uint8_t>(channelConfig[2].toInt(defaultB)),
"ChannelAdjust_" + channelName.toUpper()
channelName
);
}
@@ -177,44 +177,6 @@ namespace hyperion {
return adjustment;
}
/**
* Construct the 'led-string' with the integration area definition per led and the color
* ordering of the RGB channels
* @param ledsConfig The configuration of the led areas
* @param deviceOrder The default RGB channel ordering
* @return The constructed ledstring
*/
static LedString createLedString(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder)
{
LedString ledString;
const QString deviceOrderStr = colorOrderToString(deviceOrder);
for (signed i = 0; i < ledConfigArray.size(); ++i)
{
const QJsonObject& ledConfig = ledConfigArray[i].toObject();
Led led;
led.minX_frac = qMax(0.0, qMin(1.0, ledConfig["hmin"].toDouble()));
led.maxX_frac = qMax(0.0, qMin(1.0, ledConfig["hmax"].toDouble()));
led.minY_frac = qMax(0.0, qMin(1.0, ledConfig["vmin"].toDouble()));
led.maxY_frac = qMax(0.0, qMin(1.0, ledConfig["vmax"].toDouble()));
// Fix if the user swapped min and max
if (led.minX_frac > led.maxX_frac)
{
std::swap(led.minX_frac, led.maxX_frac);
}
if (led.minY_frac > led.maxY_frac)
{
std::swap(led.minY_frac, led.maxY_frac);
}
// Get the order of the rgb channels for this led (default is device order)
led.colorOrder = stringToColorOrder(ledConfig["colorOrder"].toString(deviceOrderStr));
ledString.leds().push_back(led);
}
return ledString;
}
static QSize getLedLayoutGridSize(const QJsonArray& ledConfigArray)
{
std::vector<int> midPointsX;

View File

@@ -31,7 +31,9 @@ public:
if (!schemaChecker.validate(configTree).first)
{
for (int i = 0; i < messages.size(); ++i)
{
std::cout << messages[i].toStdString() << std::endl;
}
std::cerr << "Validation failed for configuration file: " << config.toStdString() << std::endl;
return -3;
@@ -61,9 +63,10 @@ public:
if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0);
int errorLine(0);
int errorColumn(0);
for( int i=0, count=qMin( error.offset,config.size()); i<count; ++i )
for(long i=0, count=qMin( error.offset,config.size()); i<count; ++i )
{
++errorColumn;
if(config.at(i) == '\n' )

View File

@@ -30,6 +30,9 @@ namespace settings {
NETWORK,
FLATBUFSERVER,
PROTOSERVER,
OSEVENTS,
CECEVENTS,
SCHEDEVENTS,
INVALID
};
@@ -42,29 +45,32 @@ namespace settings {
{
switch (type)
{
case BGEFFECT: return "backgroundEffect";
case FGEFFECT: return "foregroundEffect";
case BLACKBORDER: return "blackborderdetector";
case BOBLSERVER: return "boblightServer";
case COLOR: return "color";
case DEVICE: return "device";
case EFFECTS: return "effects";
case NETFORWARD: return "forwarder";
case SYSTEMCAPTURE: return "framegrabber";
case GENERAL: return "general";
case V4L2: return "grabberV4L2";
case AUDIO: return "grabberAudio";
case JSONSERVER: return "jsonServer";
case LEDCONFIG: return "ledConfig";
case LEDS: return "leds";
case LOGGER: return "logger";
case SMOOTHING: return "smoothing";
case WEBSERVER: return "webConfig";
case INSTCAPTURE: return "instCapture";
case NETWORK: return "network";
case FLATBUFSERVER: return "flatbufServer";
case PROTOSERVER: return "protoServer";
default: return "invalid";
case BGEFFECT: return "backgroundEffect";
case FGEFFECT: return "foregroundEffect";
case BLACKBORDER: return "blackborderdetector";
case BOBLSERVER: return "boblightServer";
case COLOR: return "color";
case DEVICE: return "device";
case EFFECTS: return "effects";
case NETFORWARD: return "forwarder";
case SYSTEMCAPTURE: return "framegrabber";
case GENERAL: return "general";
case V4L2: return "grabberV4L2";
case AUDIO: return "grabberAudio";
case JSONSERVER: return "jsonServer";
case LEDCONFIG: return "ledConfig";
case LEDS: return "leds";
case LOGGER: return "logger";
case SMOOTHING: return "smoothing";
case WEBSERVER: return "webConfig";
case INSTCAPTURE: return "instCapture";
case NETWORK: return "network";
case FLATBUFSERVER: return "flatbufServer";
case PROTOSERVER: return "protoServer";
case OSEVENTS: return "osEvents";
case CECEVENTS: return "cecEvents";
case SCHEDEVENTS: return "schedEvents";
default: return "invalid";
}
}
@@ -97,6 +103,9 @@ namespace settings {
else if (type == "network") return NETWORK;
else if (type == "flatbufServer") return FLATBUFSERVER;
else if (type == "protoServer") return PROTOSERVER;
else if (type == "osEvents") return OSEVENTS;
else if (type == "cecEvents") return CECEVENTS;
else if (type == "schedEvents") return SCHEDEVENTS;
else return INVALID;
}
}

View File

@@ -4,6 +4,7 @@
#include <QObject>
#include <QString>
#include <QJsonDocument>
#include <QScopedPointer>
// hyperion / utils
#include <utils/Logger.h>
@@ -64,7 +65,7 @@ public slots:
void onServerStopped ();
void onServerStarted (quint16 port);
void onServerError (QString msg);
void onServerError (const QString& msg);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
@@ -90,13 +91,8 @@ private:
QString _baseUrl;
quint16 _port;
StaticFileServing* _staticFileServing;
QtHttpServer* _server;
QScopedPointer<QtHttpServer> _server;
bool _inited = false;
const QString WEBSERVER_DEFAULT_PATH = ":/webconfig";
const QString WEBSERVER_DEFAULT_CRT_PATH = ":/hyperion.crt";
const QString WEBSERVER_DEFAULT_KEY_PATH = ":/hyperion.key";
quint16 WEBSERVER_DEFAULT_PORT = 8090;
};
#endif // WEBSERVER_H