mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
* Fix #604 and #605 Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * clear current prio on color command Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * Fix QTimer threading issues * Call QTimer start() stop() from QEvent Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * send initial color/image to WebUI hide error message when opening webbrowser Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * added streaming timer to update WebUI Preview Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * remove QMetaObject::invokeMethod() Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * added parent to streaming timers Signed-off-by: Paulchen-Panther <Paulchen-Panter@protonmail.com> * header cleanup
This commit is contained in:
parent
c419f305f3
commit
24495bbc65
@ -2,21 +2,17 @@
|
|||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <utils/Logger.h>
|
#include <utils/Logger.h>
|
||||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
|
#include <hyperion/HyperionIManager.h>
|
||||||
|
|
||||||
// qt includes
|
// qt includes
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QMutex>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
// HyperionInstanceManager
|
class QTimer;
|
||||||
#include <hyperion/HyperionIManager.h>
|
|
||||||
|
|
||||||
class JsonCB;
|
class JsonCB;
|
||||||
class AuthManager;
|
class AuthManager;
|
||||||
class HyperionIManager;
|
|
||||||
|
|
||||||
class JsonAPI : public QObject
|
class JsonAPI : public QObject
|
||||||
{
|
{
|
||||||
@ -43,15 +39,20 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// @brief is called whenever the current Hyperion instance pushes new led raw values (if enabled)
|
/// @brief Is called whenever the current Hyperion instance pushes new led raw values (if enabled)
|
||||||
/// @param ledColors The current ledColors
|
/// @param ledColors The current led colors
|
||||||
///
|
///
|
||||||
void streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors);
|
void streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors);
|
||||||
|
|
||||||
/// push images whenever hyperion emits (if enabled)
|
///
|
||||||
|
/// @brief Push images whenever hyperion emits (if enabled)
|
||||||
|
/// @param image The current image
|
||||||
|
///
|
||||||
void setImage(const Image<ColorRgb> & image);
|
void setImage(const Image<ColorRgb> & image);
|
||||||
|
|
||||||
/// process and push new log messages from logger (if enabled)
|
///
|
||||||
|
/// @brief Process and push new log messages from logger (if enabled)
|
||||||
|
///
|
||||||
void incommingLogMessage(const Logger::T_LOG_MESSAGE&);
|
void incommingLogMessage(const Logger::T_LOG_MESSAGE&);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@ -128,17 +129,23 @@ private:
|
|||||||
/// flag to determine state of log streaming
|
/// flag to determine state of log streaming
|
||||||
bool _streaming_logging_activated;
|
bool _streaming_logging_activated;
|
||||||
|
|
||||||
/// mutex to determine state of image streaming
|
/// timer for live video refresh
|
||||||
QMutex _image_stream_mutex;
|
QTimer* _imageStreamTimer;
|
||||||
|
|
||||||
/// mutex to determine state of led streaming
|
/// image stream connection handle
|
||||||
QMutex _led_stream_mutex;
|
QMetaObject::Connection _imageStreamConnection;
|
||||||
|
|
||||||
/// timeout for live video refresh
|
/// the current streaming image
|
||||||
volatile qint64 _image_stream_timeout;
|
Image<ColorRgb> _currentImage;
|
||||||
|
|
||||||
/// timeout for led color refresh
|
/// timer for led color refresh
|
||||||
volatile qint64 _led_stream_timeout;
|
QTimer* _ledStreamTimer;
|
||||||
|
|
||||||
|
/// led stream connection handle
|
||||||
|
QMetaObject::Connection _ledStreamConnection;
|
||||||
|
|
||||||
|
/// the current streaming led values
|
||||||
|
std::vector<ColorRgb> _currentLedValues;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Handle the switches of Hyperion instances
|
/// @brief Handle the switches of Hyperion instances
|
||||||
|
@ -245,6 +245,17 @@ public:
|
|||||||
return (ssize_t) _width * _height * sizeof(Pixel_T);
|
return (ssize_t) _width * _height * sizeof(Pixel_T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the image
|
||||||
|
//
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
_width = 1;
|
||||||
|
_height = 1;
|
||||||
|
_pixels = new Pixel_T[2];
|
||||||
|
_endOfPixels = _pixels + 1;
|
||||||
|
memset(_pixels, 0, _width * _height * sizeof(Pixel_T));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
"type" : "bool"
|
"type" : "bool"
|
||||||
},
|
},
|
||||||
"interval": {
|
"interval": {
|
||||||
"type" : "integer"
|
"type" : "integer",
|
||||||
|
"required" : false,
|
||||||
|
"minimum": 50
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -12,17 +12,16 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDateTime>
|
#include <QTimer>
|
||||||
#include <QHostInfo>
|
|
||||||
#include <QMutexLocker>
|
|
||||||
|
|
||||||
// hyperion includes
|
// hyperion includes
|
||||||
#include <utils/jsonschema/QJsonFactory.h>
|
|
||||||
#include <utils/SysInfo.h>
|
|
||||||
#include <HyperionConfig.h>
|
|
||||||
#include <utils/ColorSys.h>
|
|
||||||
#include <leddevice/LedDeviceWrapper.h>
|
#include <leddevice/LedDeviceWrapper.h>
|
||||||
#include <hyperion/GrabberWrapper.h>
|
#include <hyperion/GrabberWrapper.h>
|
||||||
|
#include <utils/jsonschema/QJsonFactory.h>
|
||||||
|
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||||
|
#include <HyperionConfig.h>
|
||||||
|
#include <utils/SysInfo.h>
|
||||||
|
#include <utils/ColorSys.h>
|
||||||
#include <utils/Process.h>
|
#include <utils/Process.h>
|
||||||
#include <utils/JsonUtils.h>
|
#include <utils/JsonUtils.h>
|
||||||
|
|
||||||
@ -53,8 +52,8 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, const bool& localConnection,
|
|||||||
, _hyperion(nullptr)
|
, _hyperion(nullptr)
|
||||||
, _jsonCB(nullptr)
|
, _jsonCB(nullptr)
|
||||||
, _streaming_logging_activated(false)
|
, _streaming_logging_activated(false)
|
||||||
, _image_stream_timeout(0)
|
, _imageStreamTimer(new QTimer(this))
|
||||||
, _led_stream_timeout(0)
|
, _ledStreamTimer(new QTimer(this))
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(JSONRPC_schemas);
|
Q_INIT_RESOURCE(JSONRPC_schemas);
|
||||||
|
|
||||||
@ -1018,28 +1017,68 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& message, const QString &
|
|||||||
// create result
|
// create result
|
||||||
QString subcommand = message["subcommand"].toString("");
|
QString subcommand = message["subcommand"].toString("");
|
||||||
|
|
||||||
|
// max 20 Hz (50ms) interval for streaming (default: 10 Hz (100ms))
|
||||||
|
qint64 streaming_interval = qMax(message["interval"].toInt(100), 50);
|
||||||
|
|
||||||
if (subcommand == "ledstream-start")
|
if (subcommand == "ledstream-start")
|
||||||
{
|
{
|
||||||
_streaming_leds_reply["success"] = true;
|
_streaming_leds_reply["success"] = true;
|
||||||
_streaming_leds_reply["command"] = command+"-ledstream-update";
|
_streaming_leds_reply["command"] = command+"-ledstream-update";
|
||||||
_streaming_leds_reply["tan"] = tan;
|
_streaming_leds_reply["tan"] = tan;
|
||||||
connect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate, Qt::UniqueConnection);
|
|
||||||
|
connect(_hyperion, &Hyperion::rawLedColors, this, [=](const std::vector<ColorRgb>& ledValues)
|
||||||
|
{
|
||||||
|
_currentLedValues = ledValues;
|
||||||
|
|
||||||
|
// necessary because Qt::UniqueConnection for lambdas does not work until 5.9
|
||||||
|
// see: https://bugreports.qt.io/browse/QTBUG-52438
|
||||||
|
if (!_ledStreamConnection)
|
||||||
|
_ledStreamConnection = connect(_ledStreamTimer, &QTimer::timeout, this, [=]()
|
||||||
|
{
|
||||||
|
emit streamLedcolorsUpdate(_currentLedValues);
|
||||||
|
}, Qt::UniqueConnection);
|
||||||
|
|
||||||
|
// start the timer
|
||||||
|
if (!_ledStreamTimer->isActive() || _ledStreamTimer->interval() != streaming_interval)
|
||||||
|
_ledStreamTimer->start(streaming_interval);
|
||||||
|
}, Qt::UniqueConnection);
|
||||||
}
|
}
|
||||||
else if (subcommand == "ledstream-stop")
|
else if (subcommand == "ledstream-stop")
|
||||||
{
|
{
|
||||||
disconnect(_hyperion, &Hyperion::rawLedColors, this, &JsonAPI::streamLedcolorsUpdate);
|
disconnect(_hyperion, &Hyperion::rawLedColors, this, 0);
|
||||||
|
_ledStreamTimer->stop();
|
||||||
|
disconnect(_ledStreamConnection);
|
||||||
}
|
}
|
||||||
else if (subcommand == "imagestream-start")
|
else if (subcommand == "imagestream-start")
|
||||||
{
|
{
|
||||||
_streaming_image_reply["success"] = true;
|
_streaming_image_reply["success"] = true;
|
||||||
_streaming_image_reply["command"] = command+"-imagestream-update";
|
_streaming_image_reply["command"] = command+"-imagestream-update";
|
||||||
_streaming_image_reply["tan"] = tan;
|
_streaming_image_reply["tan"] = tan;
|
||||||
connect(_hyperion, &Hyperion::currentImage, this, &JsonAPI::setImage, Qt::UniqueConnection);
|
|
||||||
|
connect(_hyperion, &Hyperion::currentImage, this, [=](const Image<ColorRgb>& image)
|
||||||
|
{
|
||||||
|
_currentImage = image;
|
||||||
|
|
||||||
|
// necessary because Qt::UniqueConnection for lambdas does not work until 5.9
|
||||||
|
// see: https://bugreports.qt.io/browse/QTBUG-52438
|
||||||
|
if (!_imageStreamConnection)
|
||||||
|
_imageStreamConnection = connect(_imageStreamTimer, &QTimer::timeout, this, [=]()
|
||||||
|
{
|
||||||
|
emit setImage(_currentImage);
|
||||||
|
}, Qt::UniqueConnection);
|
||||||
|
|
||||||
|
// start timer
|
||||||
|
if (!_imageStreamTimer->isActive() || _imageStreamTimer->interval() != streaming_interval)
|
||||||
|
_imageStreamTimer->start(streaming_interval);
|
||||||
|
}, Qt::UniqueConnection);
|
||||||
|
|
||||||
_hyperion->update();
|
_hyperion->update();
|
||||||
}
|
}
|
||||||
else if (subcommand == "imagestream-stop")
|
else if (subcommand == "imagestream-stop")
|
||||||
{
|
{
|
||||||
disconnect(_hyperion, &Hyperion::currentImage, this, &JsonAPI::setImage);
|
disconnect(_hyperion, &Hyperion::currentImage, this, 0);
|
||||||
|
_imageStreamTimer->stop();
|
||||||
|
disconnect(_imageStreamConnection);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1420,13 +1459,8 @@ void JsonAPI::sendErrorReply(const QString &error, const QString &command, const
|
|||||||
emit callbackMessage(reply);
|
emit callbackMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&_led_stream_mutex);
|
|
||||||
if ( (_led_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() )
|
|
||||||
{
|
|
||||||
_led_stream_timeout = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
QJsonObject result;
|
QJsonObject result;
|
||||||
QJsonArray leds;
|
QJsonArray leds;
|
||||||
|
|
||||||
@ -1445,16 +1479,10 @@ void JsonAPI::streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors)
|
|||||||
|
|
||||||
// send the result
|
// send the result
|
||||||
emit callbackMessage(_streaming_leds_reply);
|
emit callbackMessage(_streaming_leds_reply);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::setImage(const Image<ColorRgb> & image)
|
void JsonAPI::setImage(const Image<ColorRgb> & image)
|
||||||
{
|
{
|
||||||
QMutexLocker lock(&_image_stream_mutex);
|
|
||||||
if ( (_image_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() )
|
|
||||||
{
|
|
||||||
_image_stream_timeout = QDateTime::currentMSecsSinceEpoch();
|
|
||||||
|
|
||||||
QImage jpgImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
|
QImage jpgImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
|
||||||
QByteArray ba;
|
QByteArray ba;
|
||||||
QBuffer buffer(&ba);
|
QBuffer buffer(&ba);
|
||||||
@ -1465,7 +1493,6 @@ void JsonAPI::setImage(const Image<ColorRgb> & image)
|
|||||||
result["image"] = "data:image/jpg;base64,"+QString(ba.toBase64());
|
result["image"] = "data:image/jpg;base64,"+QString(ba.toBase64());
|
||||||
_streaming_image_reply["result"] = result;
|
_streaming_image_reply["result"] = result;
|
||||||
emit callbackMessage(_streaming_image_reply);
|
emit callbackMessage(_streaming_image_reply);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg)
|
void JsonAPI::incommingLogMessage(const Logger::T_LOG_MESSAGE &msg)
|
||||||
|
@ -368,6 +368,9 @@ void Hyperion::setColor(const int priority, const ColorRgb &color, const int tim
|
|||||||
// create led vector from single color
|
// create led vector from single color
|
||||||
std::vector<ColorRgb> ledColors(_ledString.leds().size(), color);
|
std::vector<ColorRgb> ledColors(_ledString.leds().size(), color);
|
||||||
|
|
||||||
|
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
|
||||||
|
clear(priority);
|
||||||
|
|
||||||
// register color
|
// register color
|
||||||
registerInput(priority, hyperion::COMP_COLOR, origin);
|
registerInput(priority, hyperion::COMP_COLOR, origin);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ int LinearColorSmoothing::write(const std::vector<ColorRgb> &ledValues)
|
|||||||
|
|
||||||
_previousTime = QDateTime::currentMSecsSinceEpoch();
|
_previousTime = QDateTime::currentMSecsSinceEpoch();
|
||||||
_previousValues = ledValues;
|
_previousValues = ledValues;
|
||||||
_timer->start();
|
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -182,7 +182,7 @@ void LinearColorSmoothing::setEnable(bool enable)
|
|||||||
{
|
{
|
||||||
if (!enable)
|
if (!enable)
|
||||||
{
|
{
|
||||||
_timer->stop();
|
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||||
_previousValues.clear();
|
_previousValues.clear();
|
||||||
}
|
}
|
||||||
// update comp register
|
// update comp register
|
||||||
@ -218,10 +218,9 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, const bool& force)
|
|||||||
|
|
||||||
if (_cfgList[cfg].updateInterval != _updateInterval)
|
if (_cfgList[cfg].updateInterval != _updateInterval)
|
||||||
{
|
{
|
||||||
_timer->stop();
|
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||||
_updateInterval = _cfgList[cfg].updateInterval;
|
_updateInterval = _cfgList[cfg].updateInterval;
|
||||||
_timer->setInterval(_updateInterval);
|
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
||||||
_timer->start();
|
|
||||||
}
|
}
|
||||||
_currentConfigId = cfg;
|
_currentConfigId = cfg;
|
||||||
//DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay );
|
//DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay );
|
||||||
|
@ -185,6 +185,7 @@ bool PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& le
|
|||||||
// update input
|
// update input
|
||||||
input.timeoutTime_ms = timeout_ms;
|
input.timeoutTime_ms = timeout_ms;
|
||||||
input.ledColors = ledColors;
|
input.ledColors = ledColors;
|
||||||
|
input.image.clear();
|
||||||
|
|
||||||
// emit active change
|
// emit active change
|
||||||
if(activeChange)
|
if(activeChange)
|
||||||
@ -224,6 +225,7 @@ bool PriorityMuxer::setInputImage(const int priority, const Image<ColorRgb>& ima
|
|||||||
// update input
|
// update input
|
||||||
input.timeoutTime_ms = timeout_ms;
|
input.timeoutTime_ms = timeout_ms;
|
||||||
input.image = image;
|
input.image = image;
|
||||||
|
input.ledColors.clear();
|
||||||
|
|
||||||
// emit active change
|
// emit active change
|
||||||
if(activeChange)
|
if(activeChange)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
@ -128,7 +129,31 @@ void SysTray::closeEvent(QCloseEvent *event)
|
|||||||
|
|
||||||
void SysTray::settings()
|
void SysTray::settings()
|
||||||
{
|
{
|
||||||
|
// Hide error messages when opening webbrowser
|
||||||
|
|
||||||
|
int out_pipe[2];
|
||||||
|
int saved_stdout;
|
||||||
|
int saved_stderr;
|
||||||
|
|
||||||
|
// saving stdout and stderr file descriptor
|
||||||
|
saved_stdout = ::dup( STDOUT_FILENO );
|
||||||
|
saved_stderr = ::dup( STDERR_FILENO );
|
||||||
|
|
||||||
|
if(::pipe(out_pipe) == 0)
|
||||||
|
{
|
||||||
|
// redirecting stdout to pipe
|
||||||
|
::dup2(out_pipe[1], STDOUT_FILENO);
|
||||||
|
::close(out_pipe[1]);
|
||||||
|
// redirecting stderr to stdout
|
||||||
|
::dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||||
|
}
|
||||||
|
|
||||||
QDesktopServices::openUrl(QUrl("http://localhost:"+QString::number(_webPort)+"/", QUrl::TolerantMode));
|
QDesktopServices::openUrl(QUrl("http://localhost:"+QString::number(_webPort)+"/", QUrl::TolerantMode));
|
||||||
|
|
||||||
|
// restoring stdout
|
||||||
|
::dup2(saved_stdout, STDOUT_FILENO);
|
||||||
|
// restoring stderr
|
||||||
|
::dup2(saved_stderr, STDERR_FILENO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysTray::setEffect()
|
void SysTray::setEffect()
|
||||||
|
Loading…
Reference in New Issue
Block a user