diff --git a/.github/workflows/debian.yml b/.github/workflows/debian.yml
index a6b6c1e19..8fc293570 100644
--- a/.github/workflows/debian.yml
+++ b/.github/workflows/debian.yml
@@ -82,6 +82,8 @@ jobs:
-v "${{ github.workspace }}:/source:rw" \
-v "/tmp/deps:/tmp/deps:rw" \
-w "/source" \
+ -e LANG="C.UTF-8" \
+ -e LC_ALL="C.UTF-8" \
ghcr.io/hyperion-project/debian:${{ env.DOCKER_TAG }} \
/bin/bash -c "cmake --preset linux-${{ env.BUILD_TYPE }} ${{ steps.dependencies.outputs.cmakeArgs }} -DPLATFORM=${{ matrix.os.platform }} ${{ env.CPACK_SYSTEM_PROCESSOR }} &&
cmake --build --preset linux-${{ env.BUILD_TYPE }} --target package &&
diff --git a/.version b/.version
index 3e3c2f1e5..e543fedfc 100644
--- a/.version
+++ b/.version
@@ -1 +1 @@
-2.1.1
+2.1.2-beta.1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2da80f3b5..78e76f2f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,10 +16,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### 🔧 Changed
+- **Fixes:**
+ - UI - Language is not selectable (#1877)
+ - CEC-Handler is not stopped properly
+ - Qt-Grabber (Windows) does not apply pixel ratio (#1882) - _Thanks to @SolberLight_
+ - LED-devices are not retrying to establish connectivity, if supported by the device
+ - LED-devices are resolving IP-addresses for API and UDP two times in sequence
+
---
### 🗑️ Removed
+- Removed the ability to revoke API requests which are not issued from the same network segment. This includes the removal of IP-address white- & blacklisting (#1880)
+Rationale: Such kind of functionality is better to be dealt with via proper network management and setup, e.g. via firewalls, VLANs.
+
## [2.1.1](https://github.com/hyperion-project/hyperion.ng/compare/2.1.1...HEAD) - 2025-06-14
### 🔧 Changed
diff --git a/assets/webconfig/css/hyperion.css b/assets/webconfig/css/hyperion.css
index 4bfb03b66..a522b6e2a 100644
--- a/assets/webconfig/css/hyperion.css
+++ b/assets/webconfig/css/hyperion.css
@@ -245,20 +245,17 @@ table.first_cell_borderless td:first-child{width: 25px !important;}
.mdi-lead-pencil, .mdi-delete-forever {font-size: 22px;}
/*led preview & led visualisation*/
-body {
- --background-var: none;
- --width-var: 0px;
- --height-var: 0px;
-}
-
#leds_canvas {
position:absolute;
margin:15px;
background-repeat:no-repeat;
background-position: center;
+ --background-var: none;
+ --width-var: 0px;
+ --height-var: 0px;
}
-#leds_canvas:before {
+#leds_canvas::before {
content: "";
position:absolute;
@@ -279,6 +276,10 @@ body {
filter: blur(10px);
background-size: cover;
+
+ /* Safari optimization for pseudo-elements */
+ transform: translateZ(0);
+ -webkit-transform: translateZ(0);
}
.led { display:inline-block; border: 1px solid black; position:absolute; opacity:0.8; text-align:center; vertical-align:middle; padding:4px; border-radius:2px;}
diff --git a/assets/webconfig/js/content_index.js b/assets/webconfig/js/content_index.js
index 66640cce7..c5ba59e1c 100644
--- a/assets/webconfig/js/content_index.js
+++ b/assets/webconfig/js/content_index.js
@@ -442,7 +442,28 @@ $(window.hyperion).on("cmd-config-setconfig", function (event) {
function bindUiHandlers() {
- // Side menu link click activation
+ // Handle language selection
+
+ // Prevent dropdown from closing when selecting language
+ $('#btn_setlang').on('click', function (e) {
+ e.stopPropagation();
+ });
+
+ $('#language-select').on('changed.bs.select', function () {
+ const newLang = $(this).val();
+ if (newLang !== storedLang) {
+ setStorage("langcode", newLang);
+ location.reload();
+ }
+ });
+
+ //Close selector, if open (and no change in language happend)
+ $(document).on("click", function () {
+ $(".bootstrap-select.open").removeClass("open");
+ });
+ //End language selection
+
+ // Side smenu link click activation
$('#side-menu li a, #side-menu li ul li a').on("click", function () {
$('#side-menu').find('.active').removeClass('active');
$(this).addClass('active');
@@ -476,13 +497,6 @@ function bindUiHandlers() {
logo.style.display = window.scrollY > 65 ? "none" : "";
}, { passive: true });
- // Language selector
- $(".langSelect").off().on("click", function () {
- const newLang = $(this).attr("id").replace("lang_", "");
- setStorage("lang", newLang);
- location.reload();
- });
-
// Toggle top menu for mobile
$(".navbar-toggle").off().on("click", function () {
const target = $(this).data("target");
diff --git a/assets/webconfig/js/content_network.js b/assets/webconfig/js/content_network.js
index 69f49494f..134ef2929 100644
--- a/assets/webconfig/js/content_network.js
+++ b/assets/webconfig/js/content_network.js
@@ -266,16 +266,11 @@ $(document).ready(function () {
$("#conf_cont_tok").insertAfter("#conf_cont_network");
// Initial state check based on server config
- checkApiTokenState(window.serverConfig.network.internetAccessAPI || window.serverConfig.network.localApiAuth || storedAccess === 'expert');
-
- // Listen for changes on the Internet access API Auth toggle
- $('#root_network_internetAccessAPI').on("change", function () {
- checkApiTokenState($(this).is(":checked") || $('#root_network_localApiAuth').is(":checked"));
- });
+ checkApiTokenState(window.serverConfig.network.localApiAuth || storedAccess === 'expert');
// Listen for changes on the local API Auth toggle
$('#root_network_localApiAuth').on("change", function () {
- checkApiTokenState($(this).is(":checked") || $('#root_network_internetAccessAPI').is(":checked"));
+ checkApiTokenState($(this).is(":checked"));
});
$('#btn_create_tok').off().on('click', function () {
@@ -317,7 +312,7 @@ $(document).ready(function () {
}
function checkApiTokenState(state) {
- if (!state) {
+ if (!state && storedAccess !== 'expert') {
$("#conf_cont_tok").hide();
} else {
$("#conf_cont_tok").show();
diff --git a/assets/webconfig/js/ledsim.js b/assets/webconfig/js/ledsim.js
index 75c8dc62e..711ae9fb9 100644
--- a/assets/webconfig/js/ledsim.js
+++ b/assets/webconfig/js/ledsim.js
@@ -6,9 +6,9 @@ $(document).ready(function () {
var leds;
var grabberConfig;
var lC = false;
- var imageCanvasNodeCtx = document.getElementById("image_preview_canv").getContext("2d");
- var ledsCanvasNodeCtx = document.getElementById("leds_preview_canv").getContext("2d");
- var sigDetectAreaCanvasNodeCtx = document.getElementById("grab_preview_canv").getContext("2d");
+ var imageCanvasNodeCtx = document.getElementById("image_preview_canv").getContext("2d", { willReadFrequently: false});
+ var ledsCanvasNodeCtx = document.getElementById("leds_preview_canv").getContext("2d", { willReadFrequently: false});
+ var sigDetectAreaCanvasNodeCtx = document.getElementById("grab_preview_canv").getContext("2d", { willReadFrequently: false});
var canvas_height;
var canvas_width;
var twoDPaths = [];
@@ -205,12 +205,12 @@ $(document).ready(function () {
canvas_width = $('#ledsim_dialog').outerWidth() - 30;
$("[id$=_preview_canv]").prop({ "width": canvas_width, "height": canvas_height });
- $("body").get(0).style.setProperty("--width-var", canvas_width + "px");
- $("body").get(0).style.setProperty("--height-var", canvas_height + "px");
+ $('#leds_canvas').css("--width-var", canvas_width + "px");
+ $('#leds_canvas').css("--height-var", canvas_height + "px");
create2dPaths();
printLedsToCanvas();
- $("body").get(0).style.setProperty("--background-var", "none");
+ $('#leds_canvas').css("--background-var", "none");
resetImage();
}
@@ -227,7 +227,7 @@ $(document).ready(function () {
if (window.ledStreamActive) {
requestLedColorsStop();
ledsCanvasNodeCtx.clear();
- $("body").get(0).style.setProperty("--background-var", "none");
+ $('#leds_canvas').css("--background-var", "none");
} else {
requestLedColorsStart();
}
@@ -263,11 +263,13 @@ $(document).ready(function () {
$(window.hyperion).on("cmd-ledcolors-ledstream-update", function (event) {
if (!modalOpened) {
requestLedColorsStop();
- $("body").get(0).style.setProperty("--background-var", "none");
+ $('#leds_canvas').css("--background-var", "none");
}
else {
printLedsToCanvas(event.response.data.leds)
- $("body").get(0).style.setProperty("--background-var", "url(" + ($('#leds_preview_canv')[0]).toDataURL("image/jpg") + ") no-repeat top left");
+ $('#leds_canvas').css("--background-var", "url(" + ($('#leds_preview_canv')[0]).toDataURL("image/jpg") + ") no-repeat top left");
+ // Safari workaround (redraw canvas)
+ $('#leds_canvas').parent().hide().show(0);
}
});
diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js
index 41dba356a..423917c0c 100644
--- a/assets/webconfig/js/ui_utils.js
+++ b/assets/webconfig/js/ui_utils.js
@@ -188,40 +188,38 @@ function updateHyperionInstanceListing() {
}
function initLanguageSelection() {
- // Initialize language selection list with supported languages
+ const $select = $('#language-select');
+ $select.empty(); // clear existing options
+
for (let i = 0; i < availLang.length; i++) {
- $("#language-select").append(
- ''
- );
+ $select.append('');
}
let langLocale = storedLang;
- let langText = '';
+ if (!langLocale) {
+ langLocale = navigator.language?.substring(0, 2) || 'en';
+ }
- // Test if the language is supported by Hyperion
let langIdx = availLang.indexOf(langLocale);
- if (langIdx > -1) {
- langText = availLangText[langIdx];
- } else {
- // If the language is not supported, try the fallback language
+ if (langIdx === -1) {
+ // Try fallback
langLocale = $.i18n().options.fallbackLocale.substring(0, 2);
langIdx = availLang.indexOf(langLocale);
- if (langIdx > -1) {
- langText = availLangText[langIdx];
- } else {
- // Default to English if fallback language is also unsupported
- langLocale = 'en';
- langIdx = availLang.indexOf(langLocale);
- if (langIdx > -1) {
- langText = availLangText[langIdx];
- }
- }
+ }
+
+ if (langIdx === -1) {
+ // Default to English
+ langLocale = 'en';
}
// Update the language select dropdown
- $('#language-select').prop('title', langText);
- $("#language-select").val(langIdx);
- $("#language-select").selectpicker("refresh");
+ $select.val(langLocale);
+ $select.selectpicker({
+ container: 'body',
+ width: 'fit',
+ style: 'btn-transparent'
+ });
+ $select.selectpicker('refresh');
}
function updateUiOnInstance(inst) {
diff --git a/bin/scripts/docker-compile.sh b/bin/scripts/docker-compile.sh
index 464adcc22..c9188d2bf 100755
--- a/bin/scripts/docker-compile.sh
+++ b/bin/scripts/docker-compile.sh
@@ -272,7 +272,9 @@ $DOCKER run --rm --platform=${PLATFORM_ARCHITECTURE} \
${ENTRYPOINT_OPTION} \
-v "${DEPLOY_PATH}:/deploy" \
-v "${CODE_PATH}/:/source:rw" \
- ${REGISTRY_URL}/${DISTRIBUTION}:${CODENAME} \
+ -e LANG="C.UTF-8" \
+ -e LC_ALL="C.UTF-8" \
+ "${REGISTRY_URL}/${DISTRIBUTION}:${CODENAME}" \
/bin/bash -c "mkdir -p /source/${BUILD_DIR} && cd /source/${BUILD_DIR} &&
cmake -G Ninja -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${PLATFORM} ${BUILD_ARGS} .. || exit 2 &&
cmake --build . ${PACKAGES} -- -j $(nproc) || exit 3 || : &&
diff --git a/cmake/windows/inno/windows.iss.in b/cmake/windows/inno/windows.iss.in
index e6e7f4165..1267243c2 100644
--- a/cmake/windows/inno/windows.iss.in
+++ b/cmake/windows/inno/windows.iss.in
@@ -251,6 +251,7 @@ begin
PageDescriptionLabel.Visible := False;
PageNameLabel.Visible := False;
Bevel1.Visible := False;
+ RunList.Left := InnerNotebook.Left;
with WizardSmallBitmapImage do
begin
@@ -261,6 +262,32 @@ begin
Center := True;
Align := alClient;
end;
+
+ with FinishedLabel do
+ begin
+ Left := InnerNotebook.Left;
+ Width := InnerNotebook.Width;
+ end;
+
+ with FinishedHeadingLabel do
+ begin
+ Left := InnerNotebook.Left;
+ Width := InnerNotebook.Width;
+ Top := 0;
+ end;
+
+ with WizardBitmapImage2 do
+ begin
+ Parent := FinishedHeadingLabel;
+ Bitmap.AlphaFormat := afDefined;
+ Width := Parent.Width;
+ Height := Parent.Height;
+ AutoSize := True;
+ Stretch := False;
+ Center := True;
+ Align := alClient;
+ Bitmap := WizardSmallBitmapImage.Bitmap;
+ end;
end;
end;
diff --git a/include/api/API.h b/include/api/API.h
index 1f778bb93..0ea331c69 100644
--- a/include/api/API.h
+++ b/include/api/API.h
@@ -383,7 +383,7 @@ class API : public QObject
// current instance index
quint8 _currInstanceIndex;
- QSharedPointer _hyperion;
+ QWeakPointer _hyperionWeak;
signals:
///
diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h
index 766aab36e..b388e93b0 100644
--- a/include/api/JsonAPI.h
+++ b/include/api/JsonAPI.h
@@ -422,5 +422,4 @@ private slots:
QSharedPointer _jsonCB;
bool _isServiceAvailable;
-
};
diff --git a/include/api/JsonApiSubscription.h b/include/api/JsonApiSubscription.h
index 3d011bbdf..7642d6e01 100644
--- a/include/api/JsonApiSubscription.h
+++ b/include/api/JsonApiSubscription.h
@@ -13,9 +13,7 @@ class Subscription {
Unknown,
AdjustmentUpdate,
ComponentsUpdate,
-#if defined(ENABLE_EFFECTENGINE)
EffectsUpdate,
-#endif
EventUpdate,
ImageToLedMappingUpdate,
ImageUpdate,
@@ -33,9 +31,7 @@ class Subscription {
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";
@@ -55,9 +51,7 @@ class Subscription {
switch (type) {
case AdjustmentUpdate:
case ComponentsUpdate:
-#if defined(ENABLE_EFFECTENGINE)
case EffectsUpdate:
-#endif
case ImageToLedMappingUpdate:
case ImageUpdate:
case LedColorsUpdate:
@@ -109,9 +103,7 @@ class ApiSubscriptionRegister {
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} },
diff --git a/include/api/JsonCallbacks.h b/include/api/JsonCallbacks.h
index a090b780e..84d10a0db 100644
--- a/include/api/JsonCallbacks.h
+++ b/include/api/JsonCallbacks.h
@@ -196,16 +196,16 @@ private slots:
Logger *_log;
quint8 _instanceID;
- QSharedPointer _hyperion;
+ QWeakPointer _hyperionWeak;
/// The peer address of the client
QString _peerAddress;
/// pointer of comp register
- QSharedPointer _componentRegister;
+ QWeakPointer _componentRegisterWeak;
/// priority muxer instance
- QSharedPointer _prioMuxer;
+ QWeakPointer _prioMuxerWeak;
/// contains active subscriptions
QSet _subscribedCommands;
diff --git a/include/api/JsonInfo.h b/include/api/JsonInfo.h
index 58f0eab9a..2a3cbca30 100644
--- a/include/api/JsonInfo.h
+++ b/include/api/JsonInfo.h
@@ -7,29 +7,31 @@
#include
#include
+#include
+
class JsonInfo
{
public:
- static QJsonObject getInfo(const Hyperion* hyperion, Logger* log);
- static QJsonArray getAdjustmentInfo(const Hyperion* hyperion, Logger* log);
- static QJsonArray getPrioritiestInfo(const Hyperion* hyperion);
+ static QJsonObject getInfo(const QSharedPointer& hyperionInstance, Logger* log);
+ static QJsonArray getAdjustmentInfo(const QSharedPointer& hyperionInstance, Logger* log);
+ static QJsonArray getPrioritiestInfo(const QSharedPointer& hyperionInstance);
static QJsonArray getPrioritiestInfo(int currentPriority, const PriorityMuxer::InputsMap& activeInputs);
static QJsonArray getEffects();
static QJsonArray getEffectSchemas();
static QJsonArray getAvailableScreenGrabbers();
static QJsonArray getAvailableVideoGrabbers();
static QJsonArray getAvailableAudioGrabbers();
- static QJsonObject getGrabbers(const Hyperion* hyperion);
+ static QJsonObject getGrabbers(const QSharedPointer& hyperionInstance);
static QJsonObject getAvailableLedDevices();
static QJsonObject getCecInfo();
static QJsonArray getServices();
- static QJsonArray getComponents(const Hyperion* hyperion);
+ static QJsonArray getComponents(const QSharedPointer& hyperionInstance);
static QJsonArray getInstanceInfo();
- static QJsonArray getActiveEffects(const Hyperion* hyperion);
- static QJsonArray getActiveColors(const Hyperion* hyperion);
- static QJsonArray getTransformationInfo(const Hyperion* hyperion);
+ static QJsonArray getActiveEffects(const QSharedPointer& hyperionInstance);
+ static QJsonArray getActiveColors(const QSharedPointer& hyperionInstance);
+ static QJsonArray getTransformationInfo(const QSharedPointer& hyperionInstance);
static QJsonObject getSystemInfo();
QJsonObject discoverSources (const QString& sourceType, const QJsonObject& params);
diff --git a/include/blackborder/BlackBorderProcessor.h b/include/blackborder/BlackBorderProcessor.h
index ce372bf17..2e1cb4ecf 100644
--- a/include/blackborder/BlackBorderProcessor.h
+++ b/include/blackborder/BlackBorderProcessor.h
@@ -26,7 +26,8 @@ namespace hyperion
{
Q_OBJECT
public:
- BlackBorderProcessor(Hyperion* hyperion, QObject* parent);
+ BlackBorderProcessor(const QSharedPointer& hyperionInstance, QObject* parent);
+ ~BlackBorderProcessor() override;
///
/// Return the current (detected) border
@@ -114,7 +115,9 @@ namespace hyperion
private:
/// Hyperion instance
- Hyperion* _hyperion;
+ QWeakPointer _hyperionWeak;
+ /// Logger instance
+ Logger* _log;
///
/// Updates the current border based on the newly detected border. Returns true if the
diff --git a/include/boblightserver/BoblightServer.h b/include/boblightserver/BoblightServer.h
index 153177e13..68c6c6442 100644
--- a/include/boblightserver/BoblightServer.h
+++ b/include/boblightserver/BoblightServer.h
@@ -6,6 +6,7 @@
// Qt includes
#include
#include
+#include
// Hyperion includes
#include
@@ -31,7 +32,7 @@ class BoblightServer : public QObject
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
///
- BoblightServer(Hyperion* hyperion, const QJsonDocument& config);
+ explicit BoblightServer(const QSharedPointer& hyperionInstance, const QJsonDocument& config);
~BoblightServer() override;
///
@@ -76,8 +77,8 @@ private slots:
void closedConnection(BoblightClientConnection * connection);
private:
- /// Hyperion instance
- Hyperion * _hyperion;
+ /// Hyperion instance pointer
+ QWeakPointer _hyperionWeak;
/// The TCP server object
QTcpServer * _server;
diff --git a/include/cec/CECHandler.h b/include/cec/CECHandler.h
index d3a19c11d..6639f347b 100644
--- a/include/cec/CECHandler.h
+++ b/include/cec/CECHandler.h
@@ -33,7 +33,6 @@ class CECHandler : public QObject
Q_OBJECT
public:
CECHandler(const QJsonDocument& config, QObject * parent = nullptr);
- ~CECHandler() override;
QString scan() const;
diff --git a/include/db/DBMigrationManager.h b/include/db/DBMigrationManager.h
index f5b342070..474dfb111 100644
--- a/include/db/DBMigrationManager.h
+++ b/include/db/DBMigrationManager.h
@@ -22,6 +22,7 @@ class DBMigrationManager : public DBManager
bool upgradeGlobalSettings_2_0_12(semver::version& currentVersion, QJsonObject& config);
bool upgradeGlobalSettings_2_0_16(semver::version& currentVersion, QJsonObject& config);
bool upgradeGlobalSettings_2_1_0(semver::version& currentVersion, QJsonObject& config);
+ bool upgradeGlobalSettings_2_1_2(semver::version& currentVersion, QJsonObject& config);
bool upgradeInstanceSettings(const semver::version& currentVersion, quint8 instance, QJsonObject& config);
bool upgradeInstanceSettings_alpha_9(semver::version& currentVersion, quint8 instance, QJsonObject& config);
diff --git a/include/effectengine/Effect.h b/include/effectengine/Effect.h
index ad4419305..3d4f8dd6f 100644
--- a/include/effectengine/Effect.h
+++ b/include/effectengine/Effect.h
@@ -24,7 +24,7 @@ class Effect : public QThread
friend class EffectModule;
- Effect(Hyperion* hyperion
+ Effect(const QSharedPointer& hyperionInstance
, int priority
, int timeout
, const QString& script
@@ -84,7 +84,8 @@ public slots:
bool setModuleParameters();
void addImage();
- Hyperion* _hyperion;
+ /// Hyperion instance pointer
+ QWeakPointer _hyperionWeak;
const int _priority;
diff --git a/include/effectengine/EffectEngine.h b/include/effectengine/EffectEngine.h
index 7d807f862..01ec83f89 100644
--- a/include/effectengine/EffectEngine.h
+++ b/include/effectengine/EffectEngine.h
@@ -27,7 +27,7 @@ class EffectEngine : public QObject
Q_OBJECT
public:
- EffectEngine(Hyperion * hyperion);
+ explicit EffectEngine(const QSharedPointer& hyperionInstance);
~EffectEngine() override;
std::list getEffects() const { return _availableEffects; }
@@ -101,7 +101,8 @@ private slots:
void waitForEffectsToStop();
private:
- Hyperion * _hyperion;
+ /// Hyperion instance pointer
+ QWeakPointer _hyperionWeak;
std::list _availableEffects;
@@ -112,7 +113,7 @@ private slots:
Logger * _log;
// The global effect file handler
- EffectFileHandler* _effectFileHandler;
+ EffectFileHandler * _effectFileHandler;
QEventLoop _eventLoop;
int _remainingEffects;
diff --git a/include/forwarder/MessageForwarder.h b/include/forwarder/MessageForwarder.h
index 8fd1d927a..d4458a403 100644
--- a/include/forwarder/MessageForwarder.h
+++ b/include/forwarder/MessageForwarder.h
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
// Utils includes
#include
@@ -133,10 +134,11 @@ private slots:
SettingsTable _settings;
/// Hyperion instance forwarded
- QSharedPointer _hyperion;
+ /// Hyperion instance
+ QWeakPointer _hyperionWeak;
/// Muxer instance
- QSharedPointer _muxer;
+ QWeakPointer _muxerWeak;
// JSON connections for forwarding
QList _jsonTargets;
diff --git a/include/grabber/qt/QtGrabber.h b/include/grabber/qt/QtGrabber.h
index abf666bd0..e95084b01 100644
--- a/include/grabber/qt/QtGrabber.h
+++ b/include/grabber/qt/QtGrabber.h
@@ -98,11 +98,17 @@ class QtGrabber : public Grabber
private slots:
///
- /// @brief is called whenever the current _screen changes it's geometry
+ /// @brief is called whenever the current screen changes it's geometry
/// @param geo The new geometry
///
void geometryChanged(const QRect &geo);
+ ///
+ /// @brief is called whenever the current pixel ratio changed
+ /// @param dpi The new dots per inch
+ ///
+ void pixelRatioChanged(qreal dpi);
+
private:
///
diff --git a/include/hyperion/BGEffectHandler.h b/include/hyperion/BGEffectHandler.h
index a92b1dbce..de755930c 100644
--- a/include/hyperion/BGEffectHandler.h
+++ b/include/hyperion/BGEffectHandler.h
@@ -17,7 +17,8 @@ class BGEffectHandler : public QObject
Q_OBJECT
public:
- BGEffectHandler(Hyperion* hyperion = nullptr);
+ BGEffectHandler(const QSharedPointer& hyperionInstance);
+ ~BGEffectHandler() override;
///
/// @brief Disconnect from connected signals
@@ -48,7 +49,7 @@ private slots:
private:
/// Hyperion instance pointer
- Hyperion* _hyperion;
+ QWeakPointer _hyperionWeak;
Logger * _log;
QJsonDocument _bgEffectConfig;
diff --git a/include/hyperion/CaptureCont.h b/include/hyperion/CaptureCont.h
index 689e92c79..4b86e5df7 100644
--- a/include/hyperion/CaptureCont.h
+++ b/include/hyperion/CaptureCont.h
@@ -16,12 +16,23 @@ class CaptureCont : public QObject
{
Q_OBJECT
public:
- CaptureCont(Hyperion* hyperion);
+ explicit CaptureCont(const QSharedPointer& hyperionInstance);
+ ~CaptureCont() override;
void setScreenCaptureEnable(bool enable);
void setVideoCaptureEnable(bool enable);
void setAudioCaptureEnable(bool enable);
+ ///
+ /// @brief Start Capture Control and its timers
+ ///
+ void start();
+
+ ///
+ /// @brief Stop Capture Control and its timers
+ ///
+ void stop();
+
private slots:
///
/// @brief Handle component state change of Video- (V4L/MF) and Screen capture
@@ -72,24 +83,24 @@ private slots:
private:
- /// Hyperion instance
- Hyperion* _hyperion;
+ /// Hyperion instance pointer
+ QWeakPointer _hyperionWeak;
/// Reflect state of screen capture and prio
bool _screenCaptureEnabled;
int _screenCapturePriority;
QString _screenCaptureName;
- QTimer* _screenCaptureInactiveTimer;
+ QScopedPointer _screenCaptureInactiveTimer;
/// Reflect state of video capture and prio
bool _videoCaptureEnabled;
int _videoCapturePriority;
QString _videoCaptureName;
- QTimer* _videoInactiveTimer;
+ QScopedPointer _videoInactiveTimer;
/// Reflect state of audio capture and prio
bool _audioCaptureEnabled;
int _audioCapturePriority;
QString _audioCaptureName;
- QTimer* _audioCaptureInactiveTimer;
+ QScopedPointer _audioCaptureInactiveTimer;
};
diff --git a/include/hyperion/ComponentRegister.h b/include/hyperion/ComponentRegister.h
index aa2023404..ef3ab825b 100644
--- a/include/hyperion/ComponentRegister.h
+++ b/include/hyperion/ComponentRegister.h
@@ -8,6 +8,8 @@
#include
#include
+#include
+#include
class Hyperion;
@@ -22,7 +24,7 @@ class ComponentRegister : public QObject
Q_OBJECT
public:
- ComponentRegister(Hyperion* hyperion);
+ explicit ComponentRegister(const QSharedPointer& hyperionInstance);
~ComponentRegister() override;
///
@@ -30,9 +32,10 @@ class ComponentRegister : public QObject
/// @param comp The component from enum
/// @return True if component is running else false. Not found is -1
///
- int isComponentEnabled(hyperion::Components comp) const;
-
- /// contains all components and their state
+ int extracted(hyperion::Components &comp) const;
+ int isComponentEnabled(hyperion::Components comp) const;
+
+ /// contains all components and their state
std::map getRegister() const { return _componentStates; }
signals:
@@ -68,7 +71,7 @@ private slots:
private:
/// Hyperion instance
- Hyperion * _hyperion;
+ QWeakPointer _hyperionWeak;
/// Logger instance
Logger * _log;
/// current state of all components
diff --git a/include/hyperion/Grabber.h b/include/hyperion/Grabber.h
index 5ad7c45b2..aba5899b5 100644
--- a/include/hyperion/Grabber.h
+++ b/include/hyperion/Grabber.h
@@ -175,6 +175,8 @@ protected slots:
// Device states
+ bool _isCropping;
+
/// Is the device available?
bool _isAvailable;
diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h
index aef0598a1..83ca3cd85 100644
--- a/include/hyperion/Hyperion.h
+++ b/include/hyperion/Hyperion.h
@@ -47,6 +47,8 @@
// settings utils
#include
+#include
+
// Forward class declaration
class ImageProcessor;
class LinearColorSmoothing;
@@ -56,7 +58,7 @@ class Logger;
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
/// the priority muxer.
///
-class Hyperion : public QObject
+class Hyperion : public QObject, public QEnableSharedFromThis
{
Q_OBJECT
public:
@@ -70,7 +72,9 @@ class Hyperion : public QObject
///
explicit Hyperion(quint8 instance, QObject* parent = nullptr);
- ImageProcessor* getImageProcessor() const { return _imageProcessor.get(); }
+ ~Hyperion() override;
+
+ QSharedPointer getImageProcessor() const { return _imageProcessor; }
///
/// @brief Get instance index of this instance
@@ -508,8 +512,10 @@ private slots:
///
void handleSourceAvailability(int priority);
-private:
+signals:
+ void isSetNewComponentState(hyperion::Components component, bool state);
+private:
void updateLedColorAdjustment(int ledCount, const QJsonObject& colors);
void updateLedLayout(const QJsonArray& ledLayout);
@@ -519,34 +525,45 @@ private slots:
/// Settings manager of this instance
QScopedPointer _settingsManager;
- /// Register that holds component states
- QSharedPointer _componentRegister;
-
/// The specifiation of the led frame construction and picture integration
LedString _ledString;
+ std::vector _ledStringColorOrder;
+
+ /// Register that holds component states
+ QSharedPointer _componentRegister;
+
/// Image Processor
QSharedPointer _imageProcessor;
- std::vector _ledStringColorOrder;
+ /// The adjustment from raw colors to led colors
+ QScopedPointer _raw2ledAdjustment;
/// The priority muxer
QSharedPointer _muxer;
- /// The adjustment from raw colors to led colors
- QScopedPointer _raw2ledAdjustment;
-
/// The actual LedDeviceWrapper
- QScopedPointer _ledDeviceWrapper;
+ QSharedPointer _ledDeviceWrapper;
/// The smoothing LedDevice
- QScopedPointer _deviceSmooth;
+ QSharedPointer _deviceSmooth;
+
+ /// Capture control for Daemon native capture
+ QSharedPointer _captureCont;
+
+ /// Background effect instance, kept active to react on setting changes
+ QSharedPointer _BGEffectHandler;
#if defined(ENABLE_EFFECTENGINE)
/// Effect engine
QSharedPointer _effectEngine;
#endif
+#if defined(ENABLE_BOBLIGHT_SERVER)
+ /// Boblight instance
+ QSharedPointer _boblightServer;
+#endif
+
/// Logger instance
Logger * _log;
@@ -556,21 +573,11 @@ private slots:
QString _colorOrder;
QSize _layoutGridSize;
- /// Background effect instance, kept active to react on setting changes
- QScopedPointer _BGEffectHandler;
- /// Capture control for Daemon native capture
- QScopedPointer _captureCont;
-
/// buffer for leds (with adjustment)
std::vector _ledBuffer;
VideoMode _currVideoMode = VideoMode::VIDEO_2D;
-#if defined(ENABLE_BOBLIGHT_SERVER)
- /// Boblight instance
- QScopedPointer _boblightServer;
-#endif
-
QElapsedTimer _imageTimer; // Timer for controlling image emission frequency
QElapsedTimer _rawLedDataTimer; // Timer for controlling rawLedColors emission frequency
QElapsedTimer _ledDeviceDataTimer; // Timer for controlling LedDevice data emission frequency
diff --git a/include/hyperion/ImageProcessor.h b/include/hyperion/ImageProcessor.h
index f588b221d..f8e2cc8dd 100644
--- a/include/hyperion/ImageProcessor.h
+++ b/include/hyperion/ImageProcessor.h
@@ -35,8 +35,7 @@ class ImageProcessor : public QObject
/// @param[in] ledString LedString data
/// @param[in] hyperion Hyperion instance pointer
///
- ImageProcessor(const LedString& ledString, Hyperion* hyperion);
-
+ explicit ImageProcessor(const LedString& ledString, const QSharedPointer& hyperionInstance);
~ImageProcessor() override;
///
@@ -270,13 +269,14 @@ private slots:
void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
private:
+ /// Logger instance
+ Logger* _log;
- Logger * _log;
/// The Led-string specification
LedString _ledString;
/// The processor for black border detection
- hyperion::BlackBorderProcessor * _borderProcessor;
+ QScopedPointer _borderProcessor;
/// The mapping of image-pixels to LEDs
QSharedPointer _imageToLedColors;
@@ -292,5 +292,5 @@ private slots:
int _reducedPixelSetFactorFactor;
/// Hyperion instance pointer
- Hyperion* _hyperion;
+ QWeakPointer _hyperionWeak;
};
diff --git a/include/hyperion/ImageToLedsMap.h b/include/hyperion/ImageToLedsMap.h
index 2b33cf14e..5b12067ab 100644
--- a/include/hyperion/ImageToLedsMap.h
+++ b/include/hyperion/ImageToLedsMap.h
@@ -53,6 +53,7 @@ namespace hyperion
const std::vector & leds,
int reducedProcessingFactor = 0,
int accuraryLevel = 0);
+ ~ImageToLedsMap() override;
///
/// Returns the width of the indexed image
diff --git a/include/hyperion/LinearColorSmoothing.h b/include/hyperion/LinearColorSmoothing.h
index 127f0072b..96d8cd758 100644
--- a/include/hyperion/LinearColorSmoothing.h
+++ b/include/hyperion/LinearColorSmoothing.h
@@ -82,7 +82,7 @@ class LinearColorSmoothing : public QObject
/// @param config The smoothing configuration
/// @param hyperion The hyperion parent instance
///
- LinearColorSmoothing(const QJsonObject &config, Hyperion *hyperion);
+ explicit LinearColorSmoothing(const QJsonObject &config, const QSharedPointer& hyperionInstance);
~LinearColorSmoothing() override;
/// LED values as input for the smoothing filter
@@ -188,10 +188,10 @@ private slots:
Logger *_log;
/// Hyperion instance
- Hyperion *_hyperion;
+ QWeakPointer _hyperionWeak;
/// priority muxer instance
- QSharedPointer _prioMuxer;
+ QWeakPointer _prioMuxerWeak;
/// The interval at which to update the leds (msec)
int _updateInterval;
diff --git a/include/hyperion/PriorityMuxer.h b/include/hyperion/PriorityMuxer.h
index d26b670aa..caaf6cd7c 100644
--- a/include/hyperion/PriorityMuxer.h
+++ b/include/hyperion/PriorityMuxer.h
@@ -289,8 +289,8 @@ private slots:
bool _sourceAutoSelectEnabled;
// Timer to update Muxer times independent
- QScopedPointer _updateTimer;
+ QScopedPointer _updateTimer;
- QScopedPointer _timer;
- QScopedPointer _blockTimer;
+ QScopedPointer _timer;
+ QScopedPointer _blockTimer;
};
diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index bd4ed880f..8d60d4a3c 100644
--- a/include/leddevice/LedDevice.h
+++ b/include/leddevice/LedDevice.h
@@ -108,6 +108,12 @@ class LedDevice : public QObject
///
void setAutoStart(bool isAutoStart);
+ /// @brief Define, if a device can be recovered by retrying open attempts in an error scenrario
+ ///
+ /// @param[in] isRecoverable
+ ///
+ void setIsRecoverable(bool isRecoverable = true) { _isDeviceRecoverable = isRecoverable; }
+
///
/// @brief Discover devices of this type available (for configuration).
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
@@ -436,7 +442,7 @@ public slots:
/// Timer object which makes sure that LED data is written at a minimum rate
/// e.g. some devices will switch off when they do not receive data at least every 15 seconds
- QScopedPointer _refreshTimer;
+ QScopedPointer _refreshTimer;
// Device configuration parameters
@@ -516,7 +522,7 @@ private slots:
void stopRefreshTimer();
/// Timer that enables a device (used to retry enablement, if enabled failed before)
- QScopedPointer _enableAttemptsTimer;
+ QScopedPointer _enableAttemptsTimer;
// Device configuration parameters
diff --git a/include/leddevice/LedDeviceWrapper.h b/include/leddevice/LedDeviceWrapper.h
index 1b495a41f..52a2a9896 100644
--- a/include/leddevice/LedDeviceWrapper.h
+++ b/include/leddevice/LedDeviceWrapper.h
@@ -7,6 +7,7 @@
#include
#include
+#include
class LedDevice;
class Hyperion;
@@ -21,7 +22,7 @@ class LedDeviceWrapper : public QObject
{
Q_OBJECT
public:
- explicit LedDeviceWrapper(Hyperion* hyperion);
+ explicit LedDeviceWrapper(const QSharedPointer& hyperionInstance);
~LedDeviceWrapper() override;
///
/// @brief Constructs a new LedDevice, moves to thread and starts
@@ -158,11 +159,11 @@ private slots:
/// The common Logger instance for all LED-devices
Logger * _log;
- // parent Hyperion
- Hyperion* _hyperion;
+ /// Hyperion instance pointer
+ QWeakPointer _hyperionWeak;
// Pointer to the current LED-device & its thread
- QScopedPointer _ledDevice;
+ QScopedPointer _ledDevice;
QScopedPointer _ledDeviceThread;
// LED-Device's states
diff --git a/include/utils/Components.h b/include/utils/Components.h
index 841604a9a..73b5d9483 100644
--- a/include/utils/Components.h
+++ b/include/utils/Components.h
@@ -44,7 +44,7 @@ inline const char* componentToString(Components c)
case COMP_SMOOTHING: return "Smoothing";
case COMP_BLACKBORDER: return "Blackborder detector";
#if defined(ENABLE_FORWARDER)
- case COMP_FORWARDER: return "Json/Proto forwarder";
+ case COMP_FORWARDER: return "JSON-/Flatbuffer forwarder";
#endif
#if defined(ENABLE_BOBLIGHT_SERVER)
case COMP_BOBLIGHTSERVER:return "Boblight server";
diff --git a/include/utils/Logger.h b/include/utils/Logger.h
index 016b63525..49a3fe107 100644
--- a/include/utils/Logger.h
+++ b/include/utils/Logger.h
@@ -17,18 +17,21 @@
// stl includes
#ifdef _WIN32
+
#include
#endif
#include
+// ================================================================
+
#define LOG_MESSAGE(severity, logger, ...) (logger)->Message(severity, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
// standard log messages
-#define Debug(logger, ...) LOG_MESSAGE(Logger::DEBUG , logger, __VA_ARGS__)
-#define Info(logger, ...) LOG_MESSAGE(Logger::INFO , logger, __VA_ARGS__)
-#define Warning(logger, ...) LOG_MESSAGE(Logger::WARNING, logger, __VA_ARGS__)
-#define Error(logger, ...) LOG_MESSAGE(Logger::ERRORR , logger, __VA_ARGS__)
+#define Debug(logger, ...) LOG_MESSAGE(Logger::LOG_DEBUG , logger, __VA_ARGS__)
+#define Info(logger, ...) LOG_MESSAGE(Logger::LOG_INFO , logger, __VA_ARGS__)
+#define Warning(logger, ...) LOG_MESSAGE(Logger::LOG_WARNING, logger, __VA_ARGS__)
+#define Error(logger, ...) LOG_MESSAGE(Logger::LOG_ERROR , logger, __VA_ARGS__)
// conditional log messages
#define DebugIf(condition, logger, ...) if (condition) Debug(logger, __VA_ARGS__)
@@ -43,13 +46,14 @@ class Logger : public QObject
Q_OBJECT
public:
+
enum LogLevel {
- UNSET = 0,
- DEBUG = 1,
- INFO = 2,
- WARNING = 3,
- ERRORR = 4,
- OFF = 5
+ LOG_UNSET = 0,
+ LOG_DEBUG = 1,
+ LOG_INFO = 2,
+ LOG_WARNING = 3,
+ LOG_ERROR = 4,
+ LOG_OFF = 5
};
struct T_LOG_MESSAGE
@@ -65,7 +69,7 @@ class Logger : public QObject
QString levelString;
};
- static Logger* getInstance(const QString & name = "", const QString & subName = "__", LogLevel minLevel=Logger::INFO);
+ static Logger* getInstance(const QString & name = "", const QString & subName = "__", LogLevel minLevel= Logger::LogLevel::LOG_INFO);
static void deleteInstance(const QString & name = "", const QString & subName = "__");
static void setLogLevel(LogLevel level, const QString & name = "", const QString & subName = "__");
static LogLevel getLogLevel(const QString & name = "", const QString & subName = "__");
@@ -80,7 +84,7 @@ class Logger : public QObject
void newLogMessage(Logger::T_LOG_MESSAGE);
protected:
- Logger(const QString & name="", const QString & subName = "__", LogLevel minLevel = INFO);
+ Logger(const QString & name="", const QString & subName = "__", LogLevel minLevel = Logger::LogLevel::LOG_INFO);
~Logger() override;
private:
@@ -123,7 +127,7 @@ class LoggerManager : public QObject
public slots:
void handleNewLogMessage(const Logger::T_LOG_MESSAGE&);
- QJsonArray getLogMessageBuffer(Logger::LogLevel filter=Logger::UNSET) const;
+ QJsonArray getLogMessageBuffer(Logger::LogLevel filter= Logger::LogLevel::LOG_UNSET) const;
signals:
void newLogMessage(const Logger::T_LOG_MESSAGE&);
diff --git a/include/utils/NetOrigin.h b/include/utils/NetOrigin.h
index 648d3de3c..9d88a724f 100644
--- a/include/utils/NetOrigin.h
+++ b/include/utils/NetOrigin.h
@@ -19,14 +19,6 @@ class NetOrigin : public QObject
NetOrigin(QObject* parent = nullptr, Logger* log = Logger::getInstance("NETWORK"));
public:
- ///
- /// @brief Check if address is allowed to connect. The local address is the network adapter ip this connection comes from
- /// @param address The peer address
- /// @param local The local address of the socket (Differs based on NetworkAdapter IP or localhost)
- /// @return True when allowed, else false
- ///
- bool accessAllowed(const QHostAddress& address, const QHostAddress& local) const;
-
///
/// @brief Check if address is in subnet of local
/// @return True or false
@@ -36,21 +28,6 @@ class NetOrigin : public QObject
static NetOrigin *getInstance() { return instance; }
static NetOrigin *instance;
-private slots:
- ///
- /// @brief Handle settings update from SettingsManager
- /// @param type settingyType from enum
- /// @param config configuration object
- ///
- void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
-
private:
Logger* _log;
- /// True when internet access is allowed
- bool _isInternetAccessAllowed;
- /// True when internet access is restricted by a white list
- bool _isInternetAccessRestricted;
- /// Whitelisted ip addresses
- QList _ipWhitelist;
-
};
diff --git a/include/utils/NetUtils.h b/include/utils/NetUtils.h
index 9fe0e0139..df35cdcf7 100644
--- a/include/utils/NetUtils.h
+++ b/include/utils/NetUtils.h
@@ -227,14 +227,22 @@ inline bool resolveHostToAddress(Logger* log, const QString& hostname, QHostAddr
QMdnsEngine::Record const service = resolveMdDnsServiceRecord(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());
- target = service.target();
- port = service.port();
+ if (!service.target().isEmpty())
+ {
+ Info(log, "Resolved service [%s] to mDNS hostname [%s], service port [%d]", QSTRING_CSTR(hostname), service.target().constData(), service.port());
+ target = service.target();
+ port = service.port();
+ }
+ else
+ {
+ Error(log, "Failed to resolved service [%s] to an mDNS hostname", QSTRING_CSTR(hostname));
+ return false;
+ }
}
else
{
Error(log, "Cannot resolve mDNS hostname for given service [%s]!", QSTRING_CSTR(hostname));
- return areHostAddressPartOK;
+ return false;
}
}
#endif
diff --git a/include/utils/TrackedMemory.h b/include/utils/TrackedMemory.h
index ecb7e2aff..e0fa804dd 100644
--- a/include/utils/TrackedMemory.h
+++ b/include/utils/TrackedMemory.h
@@ -9,30 +9,27 @@
#include
#include
-#define ENABLE_MEMORY_TRACKING 0
+#define ENABLE_MEMORY_TRACKING 1
#define USE_TRACKED_SHARED_PTR ENABLE_MEMORY_TRACKING
-#define USE_TRACKED_DELETE_LATER ENABLE_MEMORY_TRACKING
+#define USE_TRACKED_CUSTOM_DELETE ENABLE_MEMORY_TRACKING
#if USE_TRACKED_SHARED_PTR
#define MAKE_TRACKED_SHARED(T, ...) makeTrackedShared(__VA_ARGS__)
#else
- #define MAKE_TRACKED_SHARED(T, ...) QSharedPointer(new T(__VA_ARGS__), &QObject::deleteLater)
+ #define MAKE_TRACKED_SHARED(T, ...) QSharedPointer(new T(__VA_ARGS__), &customDelete)
#endif
-#if USE_TRACKED_DELETE_LATER
- #define DELETE_LATER_FN(T) trackedDeleteLater
-#else
- #define DELETE_LATER_FN(T) &QObject::deleteLater
-#endif
+// Custom Delete function templates
-// Deleter function template
template
-void trackedDeleteLater(T* ptr)
+void customDelete(T* ptr)
{
if (!ptr)
return;
+#if USE_TRACKED_CUSTOM_DELETE
+
QString subComponent = "__";
QString typeName;
@@ -51,27 +48,45 @@ void trackedDeleteLater(T* ptr)
}
Logger* log = Logger::getInstance("MEMORY", subComponent);
-
- Debug(log, "Deleting object of type '%s' at %p", QSTRING_CSTR(typeName), static_cast(ptr));
+ Debug(log, "Deleting object of type '%s' at %p - current thread: '%s'", QSTRING_CSTR(typeName), static_cast(ptr), QSTRING_CSTR(QThread::currentThread()->objectName()));
+#endif
if constexpr (std::is_base_of::value)
{
QThread* thread = ptr->thread();
- if (thread && thread->isRunning())
- {
+ if (thread && thread == QThread::currentThread()) {
+#if USE_TRACKED_CUSTOM_DELETE
+ Debug(log, "QObject<%s> deleted immediately (current thread: '%s').", QSTRING_CSTR(typeName), QSTRING_CSTR(thread->objectName()));
+#endif
ptr->deleteLater();
- Debug(log, "QObject<%s>::deleteLater() scheduled on thread '%s'", QSTRING_CSTR(typeName), QSTRING_CSTR(thread->objectName()));
}
else
{
- delete ptr;
- Debug(log, "QObject<%s> deleted immediately (thread not running).", QSTRING_CSTR(typeName));
+ if (thread && thread->isRunning())
+ {
+ // Schedule deleteLater from the object's thread
+#if USE_TRACKED_CUSTOM_DELETE
+ Debug(log, "QObject<%s>::deleteLater() scheduled via invokeMethod on thread '%s'", QSTRING_CSTR(typeName), QSTRING_CSTR(thread->objectName()));
+#endif
+ QMetaObject::invokeMethod(ptr, "deleteLater", Qt::QueuedConnection);
+ }
+ else
+ {
+ // This should be an *extremely rare* fallback and indicates a bug in the thread shutdown sequence.
+#if USE_TRACKED_CUSTOM_DELETE
+ Debug(log, "<%s> object's owning thread is not running. Deleted immediately (thread not running) - current thread: '%s'", QSTRING_CSTR(typeName), QSTRING_CSTR(QThread::currentThread()->objectName()));
+#endif
+ delete ptr;
+ }
}
}
else
{
+#if USE_TRACKED_CUSTOM_DELETE
+ Debug(log, "Non-QObject<%s> deleted immediately - current thread: '%s'.", QSTRING_CSTR(typeName), QSTRING_CSTR(QThread::currentThread()->objectName()));
+#endif
delete ptr;
- Debug(log, "Non-QObject<%s> deleted immediately.", QSTRING_CSTR(typeName));
+
}
}
@@ -80,6 +95,8 @@ template
QSharedPointer makeTrackedShared(Args&&... args)
{
T* rawPtr = new T(std::forward(args)...);
+ if (!rawPtr)
+ return QSharedPointer();
QString subComponent = "__";
QString typeName;
@@ -99,9 +116,9 @@ QSharedPointer makeTrackedShared(Args&&... args)
}
Logger* log = Logger::getInstance("MEMORY", subComponent);
- Debug(log, "Creating object of type '%s' at %p", QSTRING_CSTR(typeName), static_cast(rawPtr));
+ Debug(log, "Creating object of type '%s' at %p (current thread '%s')", QSTRING_CSTR(typeName), static_cast(rawPtr), QSTRING_CSTR(QThread::currentThread()->objectName()));
- return QSharedPointer(rawPtr, DELETE_LATER_FN(T));
+ return QSharedPointer(rawPtr, &customDelete);
}
#endif // TRACKEDMEMORY_H
diff --git a/include/utils/WaitTime.h b/include/utils/WaitTime.h
index e6140f01f..49b8f81df 100644
--- a/include/utils/WaitTime.h
+++ b/include/utils/WaitTime.h
@@ -8,22 +8,28 @@
inline void wait(std::chrono::milliseconds millisecondsWait)
{
- QEventLoop loop;
- QTimer timer;
- timer.setTimerType(Qt::PreciseTimer);
- QTimer::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
- timer.start(millisecondsWait.count());
- loop.exec();
+ if (millisecondsWait.count() > 0)
+ {
+ QEventLoop loop;
+ QTimer timer;
+ timer.setTimerType(Qt::PreciseTimer);
+ QTimer::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+ timer.start(millisecondsWait.count());
+ loop.exec();
+ }
}
inline void wait(int millisecondsWait)
{
- QEventLoop loop;
- QTimer timer;
- timer.setTimerType(Qt::PreciseTimer);
- QTimer::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
- timer.start(millisecondsWait);
- loop.exec();
+ if (millisecondsWait > 0)
+ {
+ QEventLoop loop;
+ QTimer timer;
+ timer.setTimerType(Qt::PreciseTimer);
+ QTimer::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
+ timer.start(millisecondsWait);
+ loop.exec();
+ }
}
#endif // WAITTIME_H
diff --git a/libsrc/api/API.cpp b/libsrc/api/API.cpp
index d2ea5b2ad..38e3aef5f 100644
--- a/libsrc/api/API.cpp
+++ b/libsrc/api/API.cpp
@@ -41,7 +41,7 @@ const int IMAGE_SCALE = 2000;
API::API(Logger *log, bool localConnection, QObject *parent)
: QObject(parent),
_currInstanceIndex (NO_INSTANCE_ID)
- , _hyperion (nullptr)
+ , _hyperionWeak(nullptr)
, _authorized (false)
, _adminAuthorized (false)
, _localConnection(localConnection)
@@ -104,7 +104,11 @@ void API::setColor(int priority, const std::vector &ledColors, int time
fledColors.emplace_back(ColorRgb{ledColors[i], ledColors[i + 1], ledColors[i + 2]});
}
- QMetaObject::invokeMethod(_hyperion.get(), "setColor", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(std::vector, fledColors), Q_ARG(int, timeout_ms), Q_ARG(QString, origin));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setColor", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(std::vector, fledColors), Q_ARG(int, timeout_ms), Q_ARG(QString, origin));
+ }
}
}
@@ -194,8 +198,12 @@ bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &reply
Image image(data.width, data.height);
memcpy(image.memptr(), data.data.data(), static_cast(data.data.size()));
- QMetaObject::invokeMethod(_hyperion.get(), "registerInput", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(hyperion::Components, comp), Q_ARG(QString, data.origin), Q_ARG(QString, data.imgName));
- QMetaObject::invokeMethod(_hyperion.get(), "setInputImage", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(Image, image), Q_ARG(int64_t, data.duration));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "registerInput", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(hyperion::Components, comp), Q_ARG(QString, data.origin), Q_ARG(QString, data.imgName));
+ QMetaObject::invokeMethod(hyperion.get(), "setInputImage", Qt::QueuedConnection, Q_ARG(int, data.priority), Q_ARG(Image, image), Q_ARG(int64_t, data.duration));
+ }
return true;
}
@@ -204,7 +212,11 @@ bool API::clearPriority(int priority, QString &replyMsg, hyperion::Components /*
{
if (priority < 0 || (priority > 0 && priority < PriorityMuxer::BG_PRIORITY))
{
- QMetaObject::invokeMethod(_hyperion.get(), "clear", Qt::QueuedConnection, Q_ARG(int, priority));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "clear", Qt::QueuedConnection, Q_ARG(int, priority));
+ }
}
else
{
@@ -220,7 +232,11 @@ bool API::setComponentState(const QString &comp, bool &compState, QString &reply
if (component != COMP_INVALID)
{
- QMetaObject::invokeMethod(_hyperion.get(), "compStateChangeRequest", Qt::QueuedConnection, Q_ARG(hyperion::Components, component), Q_ARG(bool, compState));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "compStateChangeRequest", Qt::QueuedConnection, Q_ARG(hyperion::Components, component), Q_ARG(bool, compState));
+ }
return true;
}
replyMsg = QString("Unknown component name: %1").arg(comp);
@@ -229,25 +245,37 @@ bool API::setComponentState(const QString &comp, bool &compState, QString &reply
void API::setLedMappingType(int type, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion.get(), "setLedMappingType", Qt::QueuedConnection, Q_ARG(int, type));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setLedMappingType", Qt::QueuedConnection, Q_ARG(int, type));
+ }
}
void API::setVideoMode(VideoMode mode, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion.get(), "setVideoMode", Qt::QueuedConnection, Q_ARG(VideoMode, mode));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setVideoMode", Qt::QueuedConnection, Q_ARG(VideoMode, mode));
+ }
}
#if defined(ENABLE_EFFECTENGINE)
bool API::setEffect(const EffectCmdData &dat, hyperion::Components /*callerComp*/)
{
int isStarted;
- if (!dat.args.isEmpty())
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
{
- QMetaObject::invokeMethod(_hyperion.get(), "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
- }
- else
- {
- QMetaObject::invokeMethod(_hyperion.get(), "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
+ if (!dat.args.isEmpty())
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
+ }
+ else
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isStarted), Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
+ }
}
return isStarted >= 0;
@@ -256,12 +284,20 @@ bool API::setEffect(const EffectCmdData &dat, hyperion::Components /*callerComp*
void API::setSourceAutoSelect(bool state, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion.get(), "setSourceAutoSelect", Qt::QueuedConnection, Q_ARG(bool, state));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setSourceAutoSelect", Qt::QueuedConnection, Q_ARG(bool, state));
+ }
}
void API::setVisiblePriority(int priority, hyperion::Components /*callerComp*/)
{
- QMetaObject::invokeMethod(_hyperion.get(), "setVisiblePriority", Qt::QueuedConnection, Q_ARG(int, priority));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "setVisiblePriority", Qt::QueuedConnection, Q_ARG(int, priority));
+ }
}
void API::registerInput(int priority, hyperion::Components component, const QString &origin, const QString &owner, hyperion::Components callerComp)
@@ -273,7 +309,11 @@ void API::registerInput(int priority, hyperion::Components component, const QStr
_activeRegisters.insert({priority, registerData{component, origin, owner, callerComp}});
- QMetaObject::invokeMethod(_hyperion.get(), "registerInput", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(hyperion::Components, component), Q_ARG(QString, origin), Q_ARG(QString, owner));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "registerInput", Qt::QueuedConnection, Q_ARG(int, priority), Q_ARG(hyperion::Components, component), Q_ARG(QString, origin), Q_ARG(QString, owner));
+ }
}
void API::unregisterInput(int priority)
@@ -291,12 +331,14 @@ bool API::setHyperionInstance(quint8 inst)
return true;
}
- if (_hyperion.get() != nullptr)
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
{
- disconnect(_hyperion.get(), nullptr, this, nullptr);
+ disconnect(hyperion.get(), nullptr, this, nullptr);
}
- QMetaObject::invokeMethod(_instanceManager, "getHyperionInstance", Qt::DirectConnection, Q_RETURN_ARG(QSharedPointer, _hyperion), Q_ARG(quint8, inst));
+ QMetaObject::invokeMethod(_instanceManager, "getHyperionInstance", Qt::DirectConnection, Q_RETURN_ARG(QSharedPointer, hyperion), Q_ARG(quint8, inst));
+ _hyperionWeak = hyperion;
_currInstanceIndex = inst;
return true;
@@ -305,7 +347,11 @@ bool API::setHyperionInstance(quint8 inst)
bool API::isHyperionEnabled()
{
int isEnabled;
- QMetaObject::invokeMethod(_hyperion.get(), "isComponentEnabled", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isEnabled), Q_ARG(hyperion::Components, hyperion::COMP_ALL));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "isComponentEnabled", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, isEnabled), Q_ARG(hyperion::Components, hyperion::COMP_ALL));
+ }
return isEnabled > 0;
}
@@ -373,7 +419,11 @@ QString API::deleteEffect(const QString &name)
if (_adminAuthorized)
{
QString res;
- QMetaObject::invokeMethod(_hyperion.get(), "deleteEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QString, name));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "deleteEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QString, name));
+ }
return res;
}
return NO_AUTHORIZATION;
@@ -384,7 +434,11 @@ QString API::saveEffect(const QJsonObject &data)
if (_adminAuthorized)
{
QString res;
- QMetaObject::invokeMethod(_hyperion.get(), "saveEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QJsonObject, data));
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QMetaObject::invokeMethod(hyperion.get(), "saveEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, res), Q_ARG(QJsonObject, data));
+ }
return res;
}
return NO_AUTHORIZATION;
diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp
index 9acba4001..3fc3e3e4b 100644
--- a/libsrc/api/JsonAPI.cpp
+++ b/libsrc/api/JsonAPI.cpp
@@ -90,7 +90,7 @@ JsonAPI::JsonAPI(QString peerAddress, Logger *log, bool localConnection, QObject
qRegisterMetaType("Event");
- connect(EventHandler::getInstance().data(), &EventHandler::signalEvent, [log, this](const Event &event) {
+ connect(EventHandler::getInstance().data(), &EventHandler::signalEvent, this, [log, this](const Event &event) {
if (event == Event::Quit)
{
_isServiceAvailable = false;
@@ -499,15 +499,16 @@ void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &messag
void JsonAPI::handleGetImageSnapshotCommand(const QJsonObject &message, const JsonApiCommand &cmd)
{
- if (_hyperion.isNull())
+ if (_hyperionWeak.isNull())
{
sendErrorReply("Failed to create snapshot. No instance provided.", cmd);
return;
}
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
QString replyMsg;
QString const imageFormat = message["format"].toString("PNG");
- const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority());
+ const PriorityMuxer::InputInfo priorityInfo = hyperion->getPriorityInfo(hyperion->getCurrentPriority());
Image image = priorityInfo.image;
QImage snapshot(reinterpret_cast(image.memptr()), image.width(), image.height(), qsizetype(3) * image.width(), QImage::Format_RGB888);
QByteArray byteArray;
@@ -532,12 +533,14 @@ void JsonAPI::handleGetImageSnapshotCommand(const QJsonObject &message, const Js
void JsonAPI::handleGetLedSnapshotCommand(const QJsonObject& /*message*/, const JsonApiCommand &cmd)
{
- if (_hyperion.isNull())
+ if (_hyperionWeak.isNull())
{
sendErrorReply("Failed to create snapshot. No instance not.", cmd);
return;
}
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+
std::vector ledColors;
QEventLoop loop;
QTimer timer;
@@ -551,7 +554,7 @@ void JsonAPI::handleGetLedSnapshotCommand(const QJsonObject& /*message*/, const
// Capture LED colors when the LED data signal is emitted (execute only once)
std::unique_ptr context{new QObject};
QObject* pcontext = context.get();
- QObject::connect(_hyperion.get(), &Hyperion::ledDeviceData, pcontext,
+ QObject::connect(hyperion.get(), &Hyperion::ledDeviceData, pcontext,
[this, &loop, context = std::move(context), &ledColors, cmd](std::vector ledColorsUpdate) mutable {
ledColors = ledColorsUpdate;
loop.quit(); // Ensure the event loop quits immediately when data is received
@@ -700,20 +703,21 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC
switch (cmd.getSubCommand()) {
case SubCommand::Empty:
case SubCommand::GetInfo:
+ {
// Global information
- info = JsonInfo::getInfo(_hyperion.get(),_log);
-
+ info = JsonInfo::getInfo(_hyperionWeak.toStrongRef(), _log);
+
if (!_noListener && message.contains("subscribe"))
{
- const QJsonArray &subscriptions = message["subscribe"].toArray();
+ const QJsonArray& subscriptions = message["subscribe"].toArray();
QStringList const invaliCommands = _jsonCB->subscribe(subscriptions);
if (!invaliCommands.isEmpty())
{
- errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(','));
+ errorDetails.append("subscribe - Invalid commands provided: " + invaliCommands.join(','));
}
}
// END
-
+ }
break;
case SubCommand::Subscribe:
@@ -782,24 +786,28 @@ void JsonAPI::handleClearallCommand(const QJsonObject &message, const JsonApiCom
void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiCommand& cmd)
{
- const QJsonObject &adjustment = message["adjustment"].toObject();
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ const QJsonObject& adjustment = message["adjustment"].toObject();
- const QList adjustmentIds = _hyperion->getAdjustmentIds();
- if (adjustmentIds.isEmpty()) {
- sendErrorReply("No adjustment data available", cmd);
- return;
- }
+ const QList adjustmentIds = hyperion->getAdjustmentIds();
+ if (adjustmentIds.isEmpty()) {
+ sendErrorReply("No adjustment data available", cmd);
+ return;
+ }
- const QString adjustmentId = adjustment["id"].toString(adjustmentIds.first());
- ColorAdjustment *colorAdjustment = _hyperion->getAdjustment(adjustmentId);
- if (colorAdjustment == nullptr) {
- Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str());
- return;
- }
+ const QString adjustmentId = adjustment["id"].toString(adjustmentIds.first());
+ ColorAdjustment* colorAdjustment = hyperion->getAdjustment(adjustmentId);
+ if (colorAdjustment == nullptr) {
+ Warning(_log, "Incorrect adjustment identifier: %s", adjustmentId.toStdString().c_str());
+ return;
+ }
- applyColorAdjustments(adjustment, colorAdjustment);
- applyTransforms(adjustment, colorAdjustment);
- _hyperion->adjustmentsUpdated();
+ applyColorAdjustments(adjustment, colorAdjustment);
+ applyTransforms(adjustment, colorAdjustment);
+ hyperion->adjustmentsUpdated();
+ }
sendSuccessReply(cmd);
}
@@ -1202,13 +1210,16 @@ void JsonAPI::handleLedColorsCommand(const QJsonObject& /*message*/, const JsonA
{
switch (cmd.subCommand) {
case SubCommand::LedStreamStart:
- _jsonCB->subscribe( Subscription::LedColorsUpdate);
- if (!_hyperion.isNull())
+ {
+ _jsonCB->subscribe(Subscription::LedColorsUpdate);
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
{
// push once
- _hyperion->update();
+ hyperion->update();
}
sendSuccessReply(cmd);
+ }
break;
case SubCommand::LedStreamStop:
@@ -1879,7 +1890,11 @@ void JsonAPI::sendNewRequest(const QJsonValue &infoData, const QString &command,
if (instanceCmdType != InstanceCmd::No)
{
- request["instance"] = _hyperion->getInstanceIndex();
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ request["instance"] = hyperion->getInstanceIndex();
+ }
}
request["info"] = infoData;
@@ -1901,7 +1916,7 @@ void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instanceID,
quint8 const currentInstance = _currInstanceIndex;
if (instanceID == currentInstance)
{
- _hyperion = _instanceManager->getHyperionInstance(instanceID);
+ _hyperionWeak = _instanceManager->getHyperionInstance(instanceID);
_jsonCB->setSubscriptionsTo(instanceID);
}
}
@@ -1909,8 +1924,6 @@ void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instanceID,
case InstanceState::H_STOPPED:
{
- //Release reference to stopped Hyperion instance
- _hyperion.clear();
}
break;
diff --git a/libsrc/api/JsonCallbacks.cpp b/libsrc/api/JsonCallbacks.cpp
index 9d1f5ca33..a6c7ce06a 100644
--- a/libsrc/api/JsonCallbacks.cpp
+++ b/libsrc/api/JsonCallbacks.cpp
@@ -22,10 +22,10 @@ using namespace hyperion;
JsonCallbacks::JsonCallbacks(Logger *log, const QString& peerAddress, QObject* parent)
: QObject(parent)
, _log (log)
- , _hyperion(nullptr)
+ , _hyperionWeak(nullptr)
, _peerAddress (peerAddress)
- , _componentRegister(nullptr)
- , _prioMuxer(nullptr)
+ , _componentRegisterWeak(nullptr)
+ , _prioMuxerWeak(nullptr)
, _islogMsgStreamingActive(false)
{
qRegisterMetaType("InputsMap");
@@ -42,11 +42,6 @@ void JsonCallbacks::handleInstanceStateChange(InstanceState state, quint8 instan
if (instanceID == _instanceID)
{
setSubscriptionsTo(NO_INSTANCE_ID);
-
- //Release reference to stopped Hyperion instance
- _prioMuxer.clear();
- _componentRegister.clear();
- _hyperion.clear();
}
}
@@ -55,7 +50,7 @@ void JsonCallbacks::handleInstanceStateChange(InstanceState state, quint8 instan
case InstanceState::H_STARTED:
case InstanceState::H_CREATED:
case InstanceState::H_DELETED:
- break;
+ break;
}
}
@@ -66,14 +61,17 @@ bool JsonCallbacks::subscribe(const Subscription::Type cmd)
return true;
}
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+
switch (cmd) {
// Global subscriptions
-#if defined(ENABLE_EFFECTENGINE)
case Subscription::EffectsUpdate:
+#if defined(ENABLE_EFFECTENGINE)
connect(EffectFileHandler::getInstance(), &EffectFileHandler::effectListChanged, this, &JsonCallbacks::handleEffectListChange);
- break;
#endif
+ break;
+
case Subscription::EventUpdate:
connect(EventHandler::getInstance().data(), &EventHandler::signalEvent, this, &JsonCallbacks::handleEventUpdate);
break;
@@ -98,43 +96,49 @@ bool JsonCallbacks::subscribe(const Subscription::Type cmd)
// Instance specific subscriptions
case Subscription::AdjustmentUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
}
break;
case Subscription::ComponentsUpdate:
- if (!_componentRegister.isNull()) {
- connect(_componentRegister.get(), &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
+ {
+ QSharedPointer componentRegisterStrong = _componentRegisterWeak.toStrongRef();
+ if (!componentRegisterStrong.isNull()) {
+ connect(componentRegisterStrong.get(), &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
}
+ }
break;
case Subscription::ImageToLedMappingUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
}
break;
case Subscription::ImageUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
}
break;
case Subscription::LedColorsUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
}
break;
case Subscription::LedsUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
}
break;
case Subscription::PrioritiesUpdate:
- if (!_prioMuxer.isNull()) {
- connect(_prioMuxer.get(), &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
+ {
+ QSharedPointer prioMuxerStrong = _prioMuxerWeak.toStrongRef();
+ if (!prioMuxerStrong.isNull()) {
+ connect(prioMuxerStrong.get(), &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
}
+ }
break;
case Subscription::VideomodeUpdate:
- if (!_hyperion.isNull()) {
- connect(_hyperion.get(), &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
+ if (!hyperion.isNull()) {
+ connect(hyperion.get(), &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
}
break;
@@ -194,14 +198,16 @@ bool JsonCallbacks::unsubscribe(const Subscription::Type cmd)
_subscribedCommands.remove(cmd);
- switch (cmd) {
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ switch (cmd) {
// Global subscriptions
-#if defined(ENABLE_EFFECTENGINE)
case Subscription::EffectsUpdate:
+#if defined(ENABLE_EFFECTENGINE)
disconnect(EffectFileHandler::getInstance(), &EffectFileHandler::effectListChanged, this, &JsonCallbacks::handleEffectListChange);
- break;
#endif
+ break;
+
case Subscription::EventUpdate:
disconnect(EventHandler::getInstance().data(), &EventHandler::signalEvent, this, &JsonCallbacks::handleEventUpdate);
break;
@@ -225,44 +231,50 @@ bool JsonCallbacks::unsubscribe(const Subscription::Type cmd)
// Instance specific subscriptions
case Subscription::AdjustmentUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::adjustmentChanged, this, &JsonCallbacks::handleAdjustmentChange);
}
break;
case Subscription::ComponentsUpdate:
- if (!_componentRegister.isNull()) {
- disconnect(_componentRegister.get(), &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
+ {
+ QSharedPointer componentRegisterStrong = _componentRegisterWeak.toStrongRef();
+ if (!componentRegisterStrong.isNull()) {
+ disconnect(componentRegisterStrong.get(), &ComponentRegister::updatedComponentState, this, &JsonCallbacks::handleComponentState);
}
+ }
break;
case Subscription::ImageToLedMappingUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::imageToLedsMappingChanged, this, &JsonCallbacks::handleImageToLedsMappingChange);
}
break;
case Subscription::ImageUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::currentImage, this, &JsonCallbacks::handleImageUpdate);
}
break;
case Subscription::LedColorsUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::rawLedColors, this, &JsonCallbacks::handleLedColorUpdate);
}
break;
case Subscription::LedsUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::settingsChanged, this, &JsonCallbacks::handleLedsConfigChange);
}
break;
case Subscription::PrioritiesUpdate:
- if (!_prioMuxer.isNull()) {
- disconnect(_prioMuxer.get(), &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
+ {
+ QSharedPointer prioMuxerStrong = _prioMuxerWeak.toStrongRef();
+ if (!prioMuxerStrong.isNull()) {
+ disconnect(prioMuxerStrong.get(), &PriorityMuxer::prioritiesChanged, this, &JsonCallbacks::handlePriorityUpdate);
}
+ }
break;
case Subscription::VideomodeUpdate:
- if (!_hyperion.isNull()) {
- disconnect(_hyperion.get(), &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
+ if (!hyperion.isNull()) {
+ disconnect(hyperion.get(), &Hyperion::newVideoMode, this, &JsonCallbacks::handleVideoModeChange);
}
break;
@@ -323,13 +335,14 @@ void JsonCallbacks::setSubscriptionsTo(quint8 instanceID)
resetSubscriptions();
_instanceID = instanceID;
+
// update pointer
QSharedPointer const hyperion = HyperionIManager::getInstance()->getHyperionInstance(instanceID);
- if (!hyperion.isNull() && hyperion != _hyperion)
+ if (!hyperion.isNull() && hyperion != _hyperionWeak)
{
- _hyperion = hyperion;
- _componentRegister = _hyperion->getComponentRegister();
- _prioMuxer = _hyperion->getMuxerInstance();
+ _hyperionWeak = hyperion;
+ _componentRegisterWeak = hyperion->getComponentRegister();
+ _prioMuxerWeak = hyperion->getMuxerInstance();
}
// re-apply subscriptions
@@ -421,7 +434,7 @@ void JsonCallbacks::handlePriorityUpdate(int currentPriority, const PriorityMuxe
{
QJsonObject data;
data["priorities"] = JsonInfo::getPrioritiestInfo(currentPriority, activeInputs);
- data["priorities_autoselect"] = _hyperion->sourceAutoSelectEnabled();
+ data["priorities_autoselect"] = _hyperionWeak.toStrongRef()->sourceAutoSelectEnabled();
doCallback(Subscription::PrioritiesUpdate, data);
}
@@ -436,7 +449,7 @@ void JsonCallbacks::handleImageToLedsMappingChange(int mappingType)
void JsonCallbacks::handleAdjustmentChange()
{
- doCallback(Subscription::AdjustmentUpdate, JsonInfo::getAdjustmentInfo(_hyperion.get(),_log));
+ doCallback(Subscription::AdjustmentUpdate, JsonInfo::getAdjustmentInfo(_hyperionWeak.toStrongRef(), _log));
}
void JsonCallbacks::handleVideoModeChange(VideoMode mode)
diff --git a/libsrc/api/JsonInfo.cpp b/libsrc/api/JsonInfo.cpp
index c62a9a430..190d50690 100644
--- a/libsrc/api/JsonInfo.cpp
+++ b/libsrc/api/JsonInfo.cpp
@@ -20,7 +20,7 @@
#include
#endif
-QJsonObject JsonInfo::getInfo(const Hyperion* hyperion, Logger* log)
+QJsonObject JsonInfo::getInfo(const QSharedPointer& hyperionInstance, Logger* log)
{
QJsonObject info {};
@@ -32,22 +32,22 @@ QJsonObject JsonInfo::getInfo(const Hyperion* hyperion, Logger* log)
info["effects"] = JsonInfo::getEffects();
// Global/Instance specific information
- info["grabbers"] = JsonInfo::getGrabbers(hyperion);
- info["components"] = JsonInfo::getComponents(hyperion);
+ info["grabbers"] = JsonInfo::getGrabbers(hyperionInstance);
+ info["components"] = JsonInfo::getComponents(hyperionInstance);
// Instance specific information
- info["priorities"] = JsonInfo::getPrioritiestInfo(hyperion);
- info["adjustment"] = JsonInfo::getAdjustmentInfo(hyperion, log);
- info["activeLedColor"] = JsonInfo::getActiveColors(hyperion);
+ info["priorities"] = JsonInfo::getPrioritiestInfo(hyperionInstance);
+ info["adjustment"] = JsonInfo::getAdjustmentInfo(hyperionInstance, log);
+ info["activeLedColor"] = JsonInfo::getActiveColors(hyperionInstance);
#if defined(ENABLE_EFFECTENGINE)
- info["activeEffects"] = JsonInfo::getActiveEffects(hyperion);
+ info["activeEffects"] = JsonInfo::getActiveEffects(hyperionInstance);
#endif
- if (hyperion != nullptr)
+ if (!hyperionInstance.isNull())
{
- info["priorities_autoselect"] = hyperion->sourceAutoSelectEnabled();
- info["videomode"] = QString(videoMode2String(hyperion->getCurrentVideoMode()));
- info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(hyperion->getLedMappingType());
- info["leds"] = hyperion->getSetting(settings::LEDS).array();
+ info["priorities_autoselect"] = hyperionInstance->sourceAutoSelectEnabled();
+ info["videomode"] = QString(videoMode2String(hyperionInstance->getCurrentVideoMode()));
+ info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(hyperionInstance->getLedMappingType());
+ info["leds"] = hyperionInstance->getSetting(settings::LEDS).array();
}
else
{
@@ -57,23 +57,23 @@ QJsonObject JsonInfo::getInfo(const Hyperion* hyperion, Logger* log)
info["leds"] = QJsonArray();
}
- // BEGIN | The following entries are deprecated but used to ensure backward compatibility with hyperion Classic or up to Hyperion 2.0.16
+ // BEGIN | The following entries are deprecated but used to ensure backward compatibility with hyperionInstance Classic or up to hyperionInstance 2.0.16
info["hostname"] = QHostInfo::localHostName();
- info["transform"] = JsonInfo::getTransformationInfo(hyperion);
+ info["transform"] = JsonInfo::getTransformationInfo(hyperionInstance);
return info;
}
-QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log)
+QJsonArray JsonInfo::getAdjustmentInfo(const QSharedPointer& hyperionInstance, Logger* log)
{
- if (hyperion == nullptr)
+ if (hyperionInstance.isNull())
{
return QJsonArray();
}
QJsonArray adjustmentArray;
- for (const QString &adjustmentId : hyperion->getAdjustmentIds())
+ for (const QString &adjustmentId : hyperionInstance->getAdjustmentIds())
{
- const ColorAdjustment *colorAdjustment = hyperion->getAdjustment(adjustmentId);
+ const ColorAdjustment *colorAdjustment = hyperionInstance->getAdjustment(adjustmentId);
if (colorAdjustment == nullptr)
{
Error(log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId));
@@ -143,14 +143,14 @@ QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log)
return adjustmentArray;
}
-QJsonArray JsonInfo::getPrioritiestInfo(const Hyperion* hyperion)
+QJsonArray JsonInfo::getPrioritiestInfo(const QSharedPointer& hyperionInstance)
{
- if (hyperion == nullptr)
+ if (hyperionInstance.isNull())
{
return QJsonArray();
}
- return getPrioritiestInfo(hyperion->getCurrentPriority(), hyperion->getPriorityInfo());
+ return getPrioritiestInfo(hyperionInstance->getCurrentPriority(), hyperionInstance->getPriorityInfo());
}
QJsonArray JsonInfo::getPrioritiestInfo(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
@@ -310,14 +310,14 @@ QJsonArray JsonInfo::getAvailableAudioGrabbers()
return availableAudioGrabbers;
}
-QJsonObject JsonInfo::getGrabbers(const Hyperion* hyperion)
+QJsonObject JsonInfo::getGrabbers(const QSharedPointer& hyperionInstance)
{
QJsonObject grabbers;
quint8 idx { NO_INSTANCE_ID };
- if (hyperion != nullptr)
+ if (!hyperionInstance.isNull())
{
- idx = hyperion->getInstanceIndex();
+ idx = hyperionInstance->getInstanceIndex();
}
// SCREEN
@@ -425,15 +425,15 @@ QJsonArray JsonInfo::getServices()
return services;
}
-QJsonArray JsonInfo::getComponents(const Hyperion* hyperion)
+QJsonArray JsonInfo::getComponents(const QSharedPointer& hyperionInstance)
{
// get available components
QJsonArray component;
std::map components;
- if (hyperion!= nullptr)
+ if (!hyperionInstance.isNull())
{
- components = hyperion->getComponentRegister()->getRegister();
+ components = hyperionInstance->getComponentRegister()->getRegister();
}
else
{
@@ -466,17 +466,17 @@ QJsonArray JsonInfo::getInstanceInfo()
return instanceInfo;
}
-QJsonArray JsonInfo::getTransformationInfo(const Hyperion* hyperion)
+QJsonArray JsonInfo::getTransformationInfo(const QSharedPointer& hyperionInstance)
{
// TRANSFORM INFORMATION (DEFAULT VALUES)
QJsonArray transformArray;
- if (hyperion == nullptr)
+ if (hyperionInstance.isNull())
{
return transformArray;
}
- for (const QString &transformId : hyperion->getAdjustmentIds())
+ for (const QString &transformId : hyperionInstance->getAdjustmentIds())
{
QJsonObject transform;
QJsonArray blacklevel;
@@ -509,18 +509,18 @@ QJsonArray JsonInfo::getTransformationInfo(const Hyperion* hyperion)
return transformArray;
}
-QJsonArray JsonInfo::getActiveEffects(const Hyperion* hyperion)
+QJsonArray JsonInfo::getActiveEffects(const QSharedPointer& hyperionInstance)
{
// ACTIVE EFFECT INFO
QJsonArray activeEffects;
- if (hyperion == nullptr)
+ if (hyperionInstance.isNull())
{
return activeEffects;
}
#if defined(ENABLE_EFFECTENGINE)
- for (const ActiveEffectDefinition &activeEffectDefinition : hyperion->getActiveEffects())
+ for (const ActiveEffectDefinition &activeEffectDefinition : hyperionInstance->getActiveEffects())
{
if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1)
{
@@ -537,12 +537,13 @@ QJsonArray JsonInfo::getActiveEffects(const Hyperion* hyperion)
return activeEffects;
}
-QJsonArray JsonInfo::getActiveColors(const Hyperion* hyperion)
+QJsonArray JsonInfo::getActiveColors(const QSharedPointer& hyperionInstance)
{
// ACTIVE STATIC LED COLOR
QJsonArray activeLedColors;
- if (hyperion == nullptr)
+ QSharedPointer hyperion = hyperionInstance;
+ if (hyperion.isNull())
{
return activeLedColors;
}
diff --git a/libsrc/blackborder/BlackBorderProcessor.cpp b/libsrc/blackborder/BlackBorderProcessor.cpp
index ab13a49c6..e34b73413 100644
--- a/libsrc/blackborder/BlackBorderProcessor.cpp
+++ b/libsrc/blackborder/BlackBorderProcessor.cpp
@@ -8,9 +8,9 @@
using namespace hyperion;
-BlackBorderProcessor::BlackBorderProcessor(Hyperion* hyperion, QObject* parent)
+BlackBorderProcessor::BlackBorderProcessor(const QSharedPointer& hyperionInstance, QObject* parent)
: QObject(parent)
- , _hyperion(hyperion)
+ , _hyperionWeak(hyperionInstance)
, _enabled(false)
, _unknownSwitchCnt(600)
, _borderSwitchCnt(50)
@@ -18,31 +18,45 @@ BlackBorderProcessor::BlackBorderProcessor(Hyperion* hyperion, QObject* parent)
, _blurRemoveCnt(1)
, _detectionMode("default")
, _detector(nullptr)
- , _currentBorder({true, -1, -1})
- , _previousDetectedBorder({true, -1, -1})
+ , _currentBorder({ true, -1, -1 })
+ , _previousDetectedBorder({ true, -1, -1 })
, _consistentCnt(0)
, _inconsistentCnt(10)
, _oldThreshold(-0.1)
, _hardDisabled(false)
, _userEnabled(false)
{
- // init
- handleSettingsUpdate(settings::BLACKBORDER, _hyperion->getSetting(settings::BLACKBORDER));
+ QString subComponent{ "__" };
- // listen for settings updates
- connect(_hyperion, &Hyperion::settingsChanged, this, &BlackBorderProcessor::handleSettingsUpdate);
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instance").toString();
+ _log = Logger::getInstance("BLACKBORDER", subComponent);
+
+ // init
+ handleSettingsUpdate(settings::BLACKBORDER, _hyperionWeak.toStrongRef()->getSetting(settings::BLACKBORDER));
- // listen for component state changes
- connect(_hyperion, &Hyperion::compStateChangeRequest, this, &BlackBorderProcessor::handleCompStateChangeRequest);
+ // listen for settings updates
+ connect(hyperion.get(), &Hyperion::settingsChanged, this, &BlackBorderProcessor::handleSettingsUpdate);
+ // listen for component state changes
+ connect(hyperion.get(), &Hyperion::compStateChangeRequest, this, &BlackBorderProcessor::handleCompStateChangeRequest);
+ }
_detector = std::make_unique(_oldThreshold);
}
+BlackBorderProcessor::~BlackBorderProcessor()
+{
+ qDebug() << "BlackBorderProcessor::~BlackBorderProcessor()...";
+}
+
void BlackBorderProcessor::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::BLACKBORDER)
{
- if (_hyperion->isComponentEnabled(COMP_BLACKBORDER) == -1)
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (!hyperion.isNull() && hyperion->isComponentEnabled(COMP_BLACKBORDER) == -1)
{
//Disable, if service is not available
_enabled = false;
@@ -64,7 +78,7 @@ void BlackBorderProcessor::handleSettingsUpdate(settings::type type, const QJson
_detector = std::make_unique(_oldThreshold);
}
- Debug(Logger::getInstance("BLACKBORDER", "I"+QString::number(_hyperion->getInstanceIndex())), "Set mode to: %s", QSTRING_CSTR(_detectionMode));
+ Debug(_log, "Set mode to: %s", QSTRING_CSTR(_detectionMode));
// eval the comp state
handleCompStateChangeRequest(hyperion::COMP_BLACKBORDER, obj["enable"].toBool(true));
@@ -88,7 +102,11 @@ void BlackBorderProcessor::handleCompStateChangeRequest(hyperion::Components com
_enabled = enable;
}
- _hyperion->setNewComponentState(hyperion::COMP_BLACKBORDER, enable);
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ hyperion->setNewComponentState(hyperion::COMP_BLACKBORDER, enable);
+ }
}
}
diff --git a/libsrc/boblightserver/BoblightClientConnection.cpp b/libsrc/boblightserver/BoblightClientConnection.cpp
index 242a2bb83..53acec275 100644
--- a/libsrc/boblightserver/BoblightClientConnection.cpp
+++ b/libsrc/boblightserver/BoblightClientConnection.cpp
@@ -33,21 +33,33 @@ namespace {
const int BOBLIGHT_MAX_PRIORITY = PriorityMuxer::BG_PRIORITY-1;
} //End of constants
-BoblightClientConnection::BoblightClientConnection(Hyperion* hyperion, QTcpSocket* socket, int priority)
+BoblightClientConnection::BoblightClientConnection(const QSharedPointer& hyperionInstance, QTcpSocket* socket, int priority)
: QObject()
, _locale(QLocale::C)
, _socket(socket)
- , _imageProcessor(hyperion->getImageProcessor())
- , _hyperion(hyperion)
+ , _hyperionWeak(hyperionInstance)
+ , _imageProcessorWeak()
, _receiveBuffer()
, _priority(priority)
- , _ledColors(hyperion->getLedCount(), ColorRgb::BLACK)
- , _log(Logger::getInstance("BOBLIGHT"))
+ , _ledColors()
+ , _log()
, _clientAddress(QHostInfo::fromName(socket->peerAddress().toString()).hostName())
{
// initalize the locale. Start with the default C-locale
_locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
+ QString subComponent{ "__" };
+
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instance").toString();
+
+ _imageProcessorWeak = hyperion->getImageProcessor();
+ _ledColors.resize(hyperion->getLedCount(), ColorRgb::BLACK);
+ }
+ _log = Logger::getInstance("BOBLIGHT", subComponent);
+
// connect internal signals and slots
connect(_socket, &QTcpSocket::disconnected, this, &BoblightClientConnection::socketClosed);
connect(_socket, &QTcpSocket::readyRead, this, &BoblightClientConnection::readData);
@@ -113,7 +125,11 @@ void BoblightClientConnection::socketClosed()
{
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
{
- _hyperion->clear(_priority);
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ hyperion->clear(_priority);
+ }
}
emit connectionClosed(this);
@@ -125,6 +141,7 @@ void BoblightClientConnection::handleMessage(const QString& message)
QStringList messageParts = QStringUtils::split(message, ' ', QStringUtils::SplitBehavior::SkipEmptyParts);
if (!messageParts.isEmpty())
{
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
if (messageParts[0] == "hello")
{
sendMessage("hello\n");
@@ -179,7 +196,7 @@ void BoblightClientConnection::handleMessage(const QString& message)
// send current color values to hyperion if this is the last led assuming leds values are send in order of id
if (ledIndex == _ledColors.size() - 1)
{
- _hyperion->setInput(_priority, _ledColors);
+ hyperion->setInput(_priority, _ledColors);
}
return;
@@ -201,11 +218,11 @@ void BoblightClientConnection::handleMessage(const QString& message)
const int prio = static_cast(parseUInt(messageParts[2], &rc));
if (rc)
{
- int currentPriority = _hyperion->getCurrentPriority();
+ int currentPriority = hyperion->getCurrentPriority();
if (prio == currentPriority)
{
- Error(_log, "The priority %i is already in use onther component of type [%s]", prio, componentToString(_hyperion->getPriorityInfo(currentPriority).componentId));
+ Error(_log, "The priority %i is already in use onther component of type [%s]", prio, componentToString(hyperion->getPriorityInfo(currentPriority).componentId));
_socket->close();
}
else
@@ -213,7 +230,7 @@ void BoblightClientConnection::handleMessage(const QString& message)
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
{
_priority = BOBLIGHT_DEFAULT_PRIORITY;
- while (_hyperion->getActivePriorities().contains(_priority))
+ while (hyperion->getActivePriorities().contains(_priority))
{
_priority += 1;
}
@@ -222,12 +239,12 @@ void BoblightClientConnection::handleMessage(const QString& message)
Warning(_log, "The priority %i is not in the priority range of [%d-%d]. Priority %i is used instead.",
prio, BOBLIGHT_MIN_PRIORITY, BOBLIGHT_MAX_PRIORITY, _priority);
// register new priority (previously modified)
- _hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
+ hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
}
else
{
// register new priority
- _hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
+ hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
_priority = prio;
}
}
@@ -239,16 +256,16 @@ void BoblightClientConnection::handleMessage(const QString& message)
{
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
{
- int currentPriority = _hyperion->getCurrentPriority();
+ int currentPriority = hyperion->getCurrentPriority();
if ( _priority != currentPriority)
{
// register this connection's priority
- _hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
+ hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
}
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
{
- _hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
+ hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
}
}
@@ -409,14 +426,23 @@ void BoblightClientConnection::sendLightMessage()
{
char buffer[256];
- int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount());
- sendMessage(QByteArray(buffer, n));
-
- double h0, h1, v0, v1;
- for (int i = 0; i < _hyperion->getLedCount(); ++i)
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
{
- _imageProcessor->getScanParameters(i, h0, h1, v0, v1);
- n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100 * v0, 100 * v1, 100 * h0, 100 * h1);
+ int n = snprintf(buffer, sizeof(buffer), "lights %d\n", hyperion->getLedCount());
sendMessage(QByteArray(buffer, n));
+
+ QSharedPointer const imageProcessor = _imageProcessorWeak.toStrongRef();
+ if (imageProcessor)
+ {
+ double h0, h1, v0, v1;
+
+ for (int i = 0; i < hyperion->getLedCount(); ++i)
+ {
+ imageProcessor->getScanParameters(i, h0, h1, v0, v1);
+ n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100 * v0, 100 * v1, 100 * h0, 100 * h1);
+ sendMessage(QByteArray(buffer, n));
+ }
+ }
}
}
diff --git a/libsrc/boblightserver/BoblightClientConnection.h b/libsrc/boblightserver/BoblightClientConnection.h
index b2e69d149..8a83b5cd7 100644
--- a/libsrc/boblightserver/BoblightClientConnection.h
+++ b/libsrc/boblightserver/BoblightClientConnection.h
@@ -29,7 +29,7 @@ class BoblightClientConnection : public QObject
/// @param socket The Socket object for this connection
/// @param hyperion The Hyperion server
///
- BoblightClientConnection(Hyperion* hyperion, QTcpSocket * socket, int priority);
+ explicit BoblightClientConnection(const QSharedPointer& hyperionInstance, QTcpSocket * socket, int priority);
///
/// Destructor
@@ -125,10 +125,10 @@ private slots:
QTcpSocket * _socket;
/// The processor for translating images to led-values
- ImageProcessor * _imageProcessor;
+ QWeakPointer _imageProcessorWeak;
/// Link to Hyperion for writing led-values to a priority channel
- Hyperion * _hyperion;
+ QWeakPointer _hyperionWeak;
/// The buffer used for reading data from the socket
QByteArray _receiveBuffer;
diff --git a/libsrc/boblightserver/BoblightServer.cpp b/libsrc/boblightserver/BoblightServer.cpp
index 1cd413456..9f6e05f23 100644
--- a/libsrc/boblightserver/BoblightServer.cpp
+++ b/libsrc/boblightserver/BoblightServer.cpp
@@ -16,22 +16,29 @@
using namespace hyperion;
-BoblightServer::BoblightServer(Hyperion* hyperion,const QJsonDocument& config)
- : QObject()
- , _hyperion(hyperion)
+BoblightServer::BoblightServer(const QSharedPointer& hyperionInstance,const QJsonDocument& config)
+ : _hyperionWeak(hyperionInstance)
, _server(new QTcpServer(this))
, _openConnections()
, _priority(0)
, _log(nullptr)
, _port(0)
{
- QString subComponent = _hyperion->property("instance").toString();
- _log= Logger::getInstance("BOBLIGHT", subComponent);
+ QString subComponent{ "__" };
+
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instance").toString();
+
+ // listen for component change
+ connect(hyperion.get(), &Hyperion::compStateChangeRequest, this, &BoblightServer::compStateChangeRequest);
+ }
+ _log = Logger::getInstance("BOBLIGHT", subComponent);
+
Debug(_log, "Instance created");
- // listen for component change
- connect(_hyperion, &Hyperion::compStateChangeRequest, this, &BoblightServer::compStateChangeRequest);
// listen new connection signal from server
connect(_server, &QTcpServer::newConnection, this, &BoblightServer::newConnection);
@@ -41,7 +48,7 @@ BoblightServer::BoblightServer(Hyperion* hyperion,const QJsonDocument& config)
BoblightServer::~BoblightServer()
{
- stop();
+ qDebug() << "BoblightServer::~BoblightServer()...";
}
void BoblightServer::start()
@@ -54,7 +61,11 @@ void BoblightServer::start()
Info(_log, "Boblight service started on port: %d", _port);
- _hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
+ }
}
void BoblightServer::stop()
@@ -68,7 +79,12 @@ void BoblightServer::stop()
_server->close();
Info(_log, "Boblight service stopped");
- _hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
+
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
+ }
}
bool BoblightServer::active() const
@@ -99,7 +115,7 @@ void BoblightServer::newConnection()
if (socket != nullptr)
{
Info(_log, "New connection from %s ", QSTRING_CSTR(QString("Boblight@%1").arg(socket->peerAddress().toString())));
- BoblightClientConnection * connection = new BoblightClientConnection(_hyperion, socket, _priority);
+ BoblightClientConnection * connection = new BoblightClientConnection(_hyperionWeak.toStrongRef(), socket, _priority);
_openConnections.insert(connection);
// register slot for cleaning up after the connection closed
diff --git a/libsrc/cec/CECHandler.cpp b/libsrc/cec/CECHandler.cpp
index cfbcc3959..f7fd5835a 100644
--- a/libsrc/cec/CECHandler.cpp
+++ b/libsrc/cec/CECHandler.cpp
@@ -36,11 +36,6 @@ CECHandler::CECHandler(const QJsonDocument& config, QObject * parent)
_cecConfig.callbackParam = this;
}
-CECHandler::~CECHandler()
-{
- Info(_logger, "CEC handler stopped");
-}
-
void CECHandler::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::CECEVENTS)
@@ -124,6 +119,7 @@ void CECHandler::stop()
_cecAdapter->Close();
UnloadLibCec(_cecAdapter);
}
+ Info(_logger, "CEC handler stopped");
}
bool CECHandler::enable()
diff --git a/libsrc/db/DBMigrationManager.cpp b/libsrc/db/DBMigrationManager.cpp
index 44c7ab00b..d454dbf77 100644
--- a/libsrc/db/DBMigrationManager.cpp
+++ b/libsrc/db/DBMigrationManager.cpp
@@ -99,6 +99,8 @@ bool DBMigrationManager::upgradeGlobalSettings(const semver::version& currentVer
upgradeGlobalSettings_2_0_16(migratedVersion, config);
//Migration step for versions < 2.0.17
upgradeGlobalSettings_2_1_0(migratedVersion, config);
+ //Migration step for versions < 2.1.1
+ upgradeGlobalSettings_2_1_2(migratedVersion, config);
// Set the daqtabase version to the current build version
QJsonObject generalConfig = config["general"].toObject();
@@ -436,6 +438,32 @@ bool DBMigrationManager::upgradeGlobalSettings_2_1_0(semver::version& currentVer
return migrated;
}
+bool DBMigrationManager::upgradeGlobalSettings_2_1_2(semver::version& currentVersion, QJsonObject& config)
+{
+ bool migrated = false;
+ const semver::version targetVersion{ "2.1.2" };
+
+ if (currentVersion < targetVersion)
+ {
+ Info(_log, "Global settings: Migrate from version [%s] to version [%s] or later", currentVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
+ currentVersion = targetVersion;
+
+ if (config.contains("network"))
+ {
+ QJsonObject newNetworkConfig = config["network"].toObject();
+ newNetworkConfig.remove("internetAccessAPI");
+ newNetworkConfig.remove("restirctedInternetAccessAPI");
+ newNetworkConfig.remove("ipWhitelist");
+ config.insert("network", newNetworkConfig);
+
+ Debug(_log, "Network settings migrated");
+ migrated = true;
+ }
+ }
+
+ return migrated;
+}
+
bool DBMigrationManager::upgradeInstanceSettings_alpha_9(semver::version& currentVersion, quint8 instance, QJsonObject& config)
{
bool migrated = false;
diff --git a/libsrc/effectengine/Effect.cpp b/libsrc/effectengine/Effect.cpp
index ad0745e84..8ccbb6d78 100644
--- a/libsrc/effectengine/Effect.cpp
+++ b/libsrc/effectengine/Effect.cpp
@@ -19,9 +19,9 @@ namespace {
int DEFAULT_MAX_UPDATE_RATE_HZ { 200 };
} //End of constants
-Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &script, const QString &name, const QJsonObject &args, const QString &imageData)
+Effect::Effect(const QSharedPointer& hyperionInstance, int priority, int timeout, const QString &script, const QString &name, const QJsonObject &args, const QString &imageData)
: QThread()
- , _hyperion(hyperion)
+ , _hyperionWeak(hyperionInstance)
, _priority(priority)
, _timeout(timeout)
, _isEndless(timeout <= PriorityMuxer::ENDLESS)
@@ -31,16 +31,26 @@ Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &scr
, _imageData(imageData)
, _endTime(-1)
, _interupt(false)
- , _imageSize(hyperion->getLedGridSize())
- , _image(_imageSize,QImage::Format_ARGB32_Premultiplied)
+ , _imageSize()
+ , _image()
, _lowestUpdateIntervalInSeconds(1/static_cast(DEFAULT_MAX_UPDATE_RATE_HZ))
{
- _colors.resize(_hyperion->getLedCount());
- _colors.fill(ColorRgb::BLACK);
+ QString subComponent{ "__" };
+
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instane").toString();
+ _colors.resize(hyperion->getLedCount());
+ _imageSize = hyperion->getLedGridSize();
+ }
- _log = Logger::getInstance("EFFECTENGINE");
+ _log = Logger::getInstance("EFFECTENGINE", subComponent);
+
+ _colors.fill(ColorRgb::BLACK);
// init effect image for image based effects, size is based on led layout
+ _image = QImage(_imageSize, QImage::Format_ARGB32_Premultiplied);
_image.fill(Qt::black);
_painter = new QPainter(&_image);
@@ -49,6 +59,7 @@ Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &scr
Effect::~Effect()
{
+ qDebug() << "Effect::~Effect()...";
delete _painter;
_imageStack.clear();
}
@@ -89,9 +100,11 @@ bool Effect::setModuleParameters()
return false;
}
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+
// Add ledCount variable to the interpreter
int ledCount = 0;
- QMetaObject::invokeMethod(_hyperion, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, ledCount));
+ QMetaObject::invokeMethod(hyperion.get(), "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, ledCount));
PyObject* ledCountObj = Py_BuildValue("i", ledCount);
if (PyObject_SetAttrString(module, "ledCount", ledCountObj) < 0) {
PyErr_Print(); // Print error if setting attribute fails
@@ -100,7 +113,7 @@ bool Effect::setModuleParameters()
// Add minimumWriteTime variable to the interpreter
int latchTime = 0;
- QMetaObject::invokeMethod(_hyperion, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, latchTime));
+ QMetaObject::invokeMethod(hyperion.get(), "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, latchTime));
PyObject* latchTimeObj = Py_BuildValue("i", latchTime);
if (PyObject_SetAttrString(module, "latchTime", latchTimeObj) < 0) {
PyErr_Print(); // Print error if setting attribute fails
diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp
index e66fa371c..29a7bdff2 100644
--- a/libsrc/effectengine/EffectEngine.cpp
+++ b/libsrc/effectengine/EffectEngine.cpp
@@ -18,39 +18,49 @@
#include
#include "HyperionConfig.h"
-EffectEngine::EffectEngine(Hyperion * hyperion)
- : _hyperion(hyperion)
+EffectEngine::EffectEngine(const QSharedPointer& hyperionInstance)
+ : _hyperionWeak(hyperionInstance)
, _log(nullptr)
, _effectFileHandler(EffectFileHandler::getInstance())
{
- QString subComponent = hyperion->property("instance").toString();
- _log= Logger::getInstance("EFFECTENGINE", subComponent);
+ QString subComponent{ "__" };
+
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instance").toString();
+ }
+ _log = Logger::getInstance("EFFECTENGINE", subComponent);
+
Q_INIT_RESOURCE(EffectEngine);
qRegisterMetaType("hyperion::Components");
- // connect the Hyperion channel clear feedback
- connect(_hyperion, &Hyperion::channelCleared, this, &EffectEngine::channelCleared);
- connect(_hyperion, &Hyperion::allChannelsCleared, this, &EffectEngine::allChannelsCleared);
+ if (hyperion)
+ {
+ // connect the Hyperion channel clear feedback
+ connect(hyperion.get(), &Hyperion::channelCleared, this, &EffectEngine::channelCleared);
+ connect(hyperion.get(), &Hyperion::allChannelsCleared, this, &EffectEngine::allChannelsCleared);
- // get notifications about refreshed effect list
- connect(_effectFileHandler, &EffectFileHandler::effectListChanged, this, &EffectEngine::handleUpdatedEffectList);
+ // get notifications about refreshed effect list
+ connect(_effectFileHandler, &EffectFileHandler::effectListChanged, this, &EffectEngine::handleUpdatedEffectList);
- // Stop all effects when instance is disabled, restart the same when enabled
- connect(_hyperion, &Hyperion::compStateChangeRequest, this, [=](hyperion::Components component, bool enable) {
- if (component == hyperion::COMP_ALL)
- {
- if (enable)
+ // Stop all effects when instance is disabled, restart the same when enabled
+ connect(hyperion.get(), &Hyperion::compStateChangeRequest, this, [=](hyperion::Components component, bool enable) {
+ if (component == hyperion::COMP_ALL)
{
- startCachedEffects();
+ if (enable)
+ {
+ startCachedEffects();
+ }
+ else
+ {
+ cacheRunningEffects();
+ stopAllEffects();
+ }
}
- else
- {
- cacheRunningEffects();
- stopAllEffects();
- }
- }
- });
+ });
+ }
// register smooth cfgs and fill available effects
handleUpdatedEffectList();
@@ -58,6 +68,7 @@ EffectEngine::EffectEngine(Hyperion * hyperion)
EffectEngine::~EffectEngine()
{
+ qDebug() << "EffectEngine::~EffectEngine()...";
}
std::list EffectEngine::getActiveEffects() const
@@ -109,8 +120,9 @@ void EffectEngine::handleUpdatedEffectList()
{
_availableEffects.clear();
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
//Add smoothing config entry to support dynamic effects done in configurator
- _hyperion->updateSmoothingConfig(SmoothingConfigID::EFFECT_DYNAMIC);
+ hyperion->updateSmoothingConfig(SmoothingConfigID::EFFECT_DYNAMIC);
unsigned specificId = SmoothingConfigID::EFFECT_SPECIFIC;
for (auto def : _effectFileHandler->getEffects())
@@ -124,7 +136,7 @@ void EffectEngine::handleUpdatedEffectList()
Debug(_log, "Effect \"%s\": Add custom smoothing settings [%d]. Type: Linear, Settling time: %dms, Interval: %.fHz ", QSTRING_CSTR(def.name), specificId, settlingTime_ms, ledUpdateFrequency_hz);
- def.smoothCfg = _hyperion->updateSmoothingConfig(
+ def.smoothCfg = hyperion->updateSmoothingConfig(
++specificId,
settlingTime_ms,
ledUpdateFrequency_hz,
@@ -164,7 +176,7 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
Debug(_log, "Effect \"%s\": Apply dynamic smoothing settings, if smoothing. Type: Linear, Settling time: %dms, Interval: %.fHz ", QSTRING_CSTR(effectName), settlingTime_ms, ledUpdateFrequency_hz);
- smoothCfg = _hyperion->updateSmoothingConfig(
+ smoothCfg = _hyperionWeak.toStrongRef()->updateSmoothingConfig(
SmoothingConfigID::EFFECT_DYNAMIC,
settlingTime_ms,
ledUpdateFrequency_hz,
@@ -203,15 +215,16 @@ int EffectEngine::runEffectScript(const QString &script, const QString &name, co
channelCleared(priority);
// create the effect
- Effect *effect = new Effect(_hyperion, priority, timeout, script, name, args, imageData);
- connect(effect, &Effect::setInput, _hyperion, &Hyperion::setInput, Qt::QueuedConnection);
- connect(effect, &Effect::setInputImage, _hyperion, &Hyperion::setInputImage, Qt::QueuedConnection);
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ Effect *effect = new Effect(hyperion, priority, timeout, script, name, args, imageData);
+ connect(effect, &Effect::setInput, hyperion.get(), &Hyperion::setInput, Qt::QueuedConnection);
+ connect(effect, &Effect::setInputImage, hyperion.get(), &Hyperion::setInputImage, Qt::QueuedConnection);
connect(effect, &QThread::finished, this, &EffectEngine::effectFinished);
_activeEffects.push_back(effect);
// start the effect
Debug(_log, "Start the effect: \"%s\"", QSTRING_CSTR(name));
- _hyperion->registerInput(priority, hyperion::COMP_EFFECT, origin, name ,smoothCfg);
+ hyperion->registerInput(priority, hyperion::COMP_EFFECT, origin, name ,smoothCfg);
effect->start();
return 0;
diff --git a/libsrc/effectengine/EffectModule.cpp b/libsrc/effectengine/EffectModule.cpp
index c6ba1881f..6abf2205b 100644
--- a/libsrc/effectengine/EffectModule.cpp
+++ b/libsrc/effectengine/EffectModule.cpp
@@ -85,73 +85,78 @@ PyObject* EffectModule::json2python(const QJsonValue& jsonData)
{
switch (jsonData.type())
{
- case QJsonValue::Null:
- Py_RETURN_NONE;
+ case QJsonValue::Null:
+ Py_RETURN_NONE;
- case QJsonValue::Undefined:
- Py_RETURN_NOTIMPLEMENTED;
+ case QJsonValue::Undefined:
+ Py_RETURN_NOTIMPLEMENTED;
- case QJsonValue::Double:
- {
- double value = jsonData.toDouble();
- if (value == static_cast(value)) // If no fractional part, value is equal to its integer representation
+ case QJsonValue::Double:
{
- return Py_BuildValue("i", static_cast(value));
+ double value = jsonData.toDouble();
+ if (value == static_cast(value)) // If no fractional part, value is equal to its integer representation
+ {
+ return Py_BuildValue("i", static_cast(value));
+ }
+ return Py_BuildValue("d", value);
}
- return Py_BuildValue("d", value);
- }
- case QJsonValue::Bool:
- return PyBool_FromLong(jsonData.toBool() ? 1 : 0);
+ case QJsonValue::Bool:
+ return PyBool_FromLong(jsonData.toBool() ? 1 : 0);
- case QJsonValue::String:
- return PyUnicode_FromString(jsonData.toString().toUtf8().constData());
+ case QJsonValue::String:
+ return PyUnicode_FromString(jsonData.toString().toUtf8().constData());
- case QJsonValue::Array:
- {
- QJsonArray arrayData = jsonData.toArray();
- PyObject* list = PyList_New(arrayData.size());
- int index = 0;
- for (QJsonArray::iterator i = arrayData.begin(); i != arrayData.end(); ++i, ++index)
+ case QJsonValue::Array:
{
- PyObject* obj = json2python(*i);
- Py_INCREF(obj);
- PyList_SetItem(list, index, obj);
- Py_XDECREF(obj);
+ QJsonArray arrayData = jsonData.toArray();
+ PyObject* list = PyList_New(arrayData.size());
+ int index = 0;
+ for (QJsonArray::iterator i = arrayData.begin(); i != arrayData.end(); ++i, ++index)
+ {
+ PyObject* obj = json2python(*i);
+ if (!obj)
+ {
+ Py_XDECREF(list);
+ return nullptr; // Error occurred, return null
+ }
+ PyList_SetItem(list, index, obj);
+ }
+ return list;
}
- return list;
- }
- case QJsonValue::Object: {
- // Python's dict
- QJsonObject jsonObject = jsonData.toObject();
- PyObject* pyDict = PyDict_New();
- for (auto it = jsonObject.begin(); it != jsonObject.end(); ++it) {
- // Convert key
- PyObject* pyKey = PyUnicode_FromString(it.key().toUtf8().constData());
- if (!pyKey) {
- Py_XDECREF(pyDict);
- return nullptr; // Error occurred, return null
- }
- // Convert value
- PyObject* pyValue = json2python(it.value());
- if (!pyValue) {
- Py_XDECREF(pyKey);
- Py_XDECREF(pyDict);
- return nullptr; // Error occurred, return null
+ case QJsonValue::Object:
+ {
+ // Python's dict
+ QJsonObject jsonObject = jsonData.toObject();
+ PyObject* pyDict = PyDict_New();
+ for (auto it = jsonObject.begin(); it != jsonObject.end(); ++it)
+ {
+ // Convert key
+ PyObject* pyKey = PyUnicode_FromString(it.key().toUtf8().constData());
+ if (!pyKey)
+ {
+ Py_XDECREF(pyDict);
+ return nullptr; // Error occurred, return null
+ }
+ // Convert value
+ PyObject* pyValue = json2python(it.value());
+ if (!pyValue)
+ {
+ Py_XDECREF(pyKey);
+ Py_XDECREF(pyDict);
+ return nullptr; // Error occurred, return null
+ }
+ // Add to dictionary
+ PyDict_SetItem(pyDict, pyKey, pyValue);
}
- // Add to dictionary
- PyDict_SetItem(pyDict, pyKey, pyValue);
- Py_XDECREF(pyKey);
- Py_XDECREF(pyValue);
+ return pyDict;
}
- return pyDict;
- }
- default:
- // Unsupported type
- PyErr_SetString(PyExc_TypeError, "Unsupported QJsonValue type.");
- return nullptr;
+ default:
+ // Unsupported type
+ PyErr_SetString(PyExc_TypeError, "Unsupported QJsonValue type.");
+ return nullptr;
}
assert(false);
@@ -214,7 +219,7 @@ PyObject* EffectModule::wrapSetColor(PyObject* self, PyObject* args)
if (PyByteArray_Check(bytearray))
{
size_t length = PyByteArray_Size(bytearray);
- if (length == 3 * static_cast(getEffect()->_hyperion->getLedCount()))
+ if (length == 3 * static_cast(getEffect()->_hyperionWeak.toStrongRef()->getLedCount()))
{
char* data = PyByteArray_AS_STRING(bytearray);
memcpy(getEffect()->_colors.data(), data, length);
@@ -349,6 +354,7 @@ PyObject* EffectModule::wrapGetImage(PyObject* self, PyObject* args)
if (reader.canRead())
{
PyObject* result = PyList_New(reader.imageCount());
+ if(!result) return nullptr;
for (int i = 0; i < reader.imageCount(); ++i)
{
@@ -363,6 +369,7 @@ PyObject* EffectModule::wrapGetImage(PyObject* self, PyObject* args)
{
if (cropLeft + cropRight >= width || cropTop + cropBottom >= height)
{
+ Py_DECREF(result);
QString errorStr = QString("Rejecting invalid crop values: left: %1, right: %2, top: %3, bottom: %4, higher than height/width %5/%6").arg(cropLeft).arg(cropRight).arg(cropTop).arg(cropBottom).arg(height).arg(width);
PyErr_SetString(PyExc_RuntimeError, qPrintable(errorStr));
return nullptr;
@@ -373,22 +380,42 @@ PyObject* EffectModule::wrapGetImage(PyObject* self, PyObject* args)
height = qimage.height();
}
- QByteArray binaryImage;
- for (int i = 0; i < height; i++)
+ qsizetype size = qsizetype(width) * qsizetype(height) * 3;
+ QByteArray binaryImage(size, Qt::Uninitialized);
+ char* dest = binaryImage.data();
+ for (int i = 0; i < height; ++i)
{
const QRgb* scanline = reinterpret_cast(qimage.scanLine(i));
- const QRgb* end = scanline + qimage.width();
- for (; scanline != end; scanline++)
+ for (int j = 0; j < width; ++j)
{
- binaryImage.append(!grayscale ? (char)qRed(scanline[0]) : (char)qGray(scanline[0]));
- binaryImage.append(!grayscale ? (char)qGreen(scanline[1]) : (char)qGray(scanline[1]));
- binaryImage.append(!grayscale ? (char)qBlue(scanline[2]) : (char)qGray(scanline[2]));
+ QRgb pixel = scanline[j];
+ *dest++ = static_cast(!grayscale ? qRed(pixel) : qGray(pixel));
+ *dest++ = static_cast(!grayscale ? qGreen(pixel) : qGray(pixel));
+ *dest++ = static_cast(!grayscale ? qBlue(pixel) : qGray(pixel));
}
}
- PyList_SET_ITEM(result, i, Py_BuildValue("{s:i,s:i,s:O}", "imageWidth", width, "imageHeight", height, "imageData", PyByteArray_FromStringAndSize(binaryImage.constData(), binaryImage.size())));
+
+ PyObject* pyBytes = PyByteArray_FromStringAndSize(binaryImage.constData(), binaryImage.size());
+ if (!pyBytes)
+ {
+ Py_DECREF(result);
+ return nullptr;
+ }
+
+ PyObject* dict = Py_BuildValue("{s:i,s:i,s:O}", "imageWidth", width, "imageHeight", height, "imageData", pyBytes);
+ Py_DECREF(pyBytes);
+
+ if (!dict)
+ {
+ Py_DECREF(result);
+ return nullptr;
+ }
+
+ PyList_SET_ITEM(result, i, dict);
}
else
{
+ Py_DECREF(result);
PyErr_SetString(PyExc_TypeError, reader.errorString().toUtf8().constData());
return nullptr;
}
diff --git a/libsrc/flatbufserver/FlatBufferServer.cpp b/libsrc/flatbufserver/FlatBufferServer.cpp
index c33412ed2..a0caf6222 100644
--- a/libsrc/flatbufserver/FlatBufferServer.cpp
+++ b/libsrc/flatbufserver/FlatBufferServer.cpp
@@ -75,24 +75,19 @@ void FlatBufferServer::newConnection()
{
if(QTcpSocket* socket = _server->nextPendingConnection())
{
- if(_netOrigin->accessAllowed(socket->peerAddress(), socket->localAddress()))
- {
- Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
- FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
-
- client->setPixelDecimation(_pixelDecimation);
-
- // internal
- connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
- connect(client, &FlatBufferClient::registerGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput);
- connect(client, &FlatBufferClient::clearGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::clearGlobalInput);
- connect(client, &FlatBufferClient::setGlobalInputImage, GlobalSignals::getInstance(), &GlobalSignals::setGlobalImage);
- connect(client, &FlatBufferClient::setGlobalInputColor, GlobalSignals::getInstance(), &GlobalSignals::setGlobalColor);
- connect(client, &FlatBufferClient::setBufferImage, GlobalSignals::getInstance(), &GlobalSignals::setBufferImage);
- _openConnections.append(client);
- }
- else
- socket->close();
+ Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString()));
+ FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this);
+
+ client->setPixelDecimation(_pixelDecimation);
+
+ // internal
+ connect(client, &FlatBufferClient::clientDisconnected, this, &FlatBufferServer::clientDisconnected);
+ connect(client, &FlatBufferClient::registerGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::registerGlobalInput);
+ connect(client, &FlatBufferClient::clearGlobalInput, GlobalSignals::getInstance(), &GlobalSignals::clearGlobalInput);
+ connect(client, &FlatBufferClient::setGlobalInputImage, GlobalSignals::getInstance(), &GlobalSignals::setGlobalImage);
+ connect(client, &FlatBufferClient::setGlobalInputColor, GlobalSignals::getInstance(), &GlobalSignals::setGlobalColor);
+ connect(client, &FlatBufferClient::setBufferImage, GlobalSignals::getInstance(), &GlobalSignals::setBufferImage);
+ _openConnections.append(client);
}
}
}
diff --git a/libsrc/forwarder/MessageForwarder.cpp b/libsrc/forwarder/MessageForwarder.cpp
index d5a39f870..61d8191d5 100644
--- a/libsrc/forwarder/MessageForwarder.cpp
+++ b/libsrc/forwarder/MessageForwarder.cpp
@@ -45,8 +45,8 @@ MessageForwarder::MessageForwarder(const QJsonDocument& config)
, _priority(DEFAULT_FORWARDER_FLATBUFFFER_PRIORITY)
, _isEnabled(false)
, _toBeForwardedInstanceID(NO_INSTANCE_ID)
- , _hyperion(nullptr)
- , _muxer(nullptr)
+ , _hyperionWeak(nullptr)
+ , _muxerWeak(nullptr)
, _messageForwarderFlatBufHelper(nullptr)
{
qRegisterMetaType("TargetHost");
@@ -54,6 +54,7 @@ MessageForwarder::MessageForwarder(const QJsonDocument& config)
MessageForwarder::~MessageForwarder()
{
+ qDebug() << "MessageForwarder::~MessageForwarder()...";
}
void MessageForwarder::init()
@@ -76,7 +77,8 @@ void MessageForwarder::start()
void MessageForwarder::stop()
{
- if (!_hyperion.isNull())
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (!hyperion.isNull())
{
disconnect(_toBeForwardedInstanceID);
@@ -94,19 +96,23 @@ bool MessageForwarder::connect(quint8 instanceID)
{
Info(_log, "Connect forwarder to instance [%u]", _toBeForwardedInstanceID);
- _hyperion = HyperionIManager::getInstance()->getHyperionInstance(_toBeForwardedInstanceID);
- _muxer = _hyperion->getMuxerInstance();
+ QSharedPointer const hyperion = HyperionIManager::getInstance()->getHyperionInstance(_toBeForwardedInstanceID);
+ if (hyperion)
+ {
+ _hyperionWeak = hyperion;
+ _muxerWeak = hyperion->getMuxerInstance();
- // component changes
- QObject::connect(_hyperion.get(), &Hyperion::compStateChangeRequest, this, &MessageForwarder::handleCompStateChangeRequest);
+ // component changes
+ QObject::connect(hyperion.get(), &Hyperion::compStateChangeRequest, this, &MessageForwarder::handleCompStateChangeRequest);
- // connect with Muxer visible priority changes
- QObject::connect(_muxer.get(), &PriorityMuxer::visiblePriorityChanged, this, &MessageForwarder::handlePriorityChanges);
+ // connect with Muxer visible priority changes
+ QObject::connect(_muxerWeak.toStrongRef().get(), &PriorityMuxer::visiblePriorityChanged, this, &MessageForwarder::handlePriorityChanges);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::connect(GlobalSignals::getInstance(), &GlobalSignals::setBufferImage, _hyperion.get(), &Hyperion::forwardBufferMessage);
+ QObject::connect(GlobalSignals::getInstance(), &GlobalSignals::setBufferImage, hyperion.get(), &Hyperion::forwardBufferMessage);
#endif
- isConnected = true;
+ isConnected = true;
+ }
}
else
{
@@ -118,18 +124,16 @@ bool MessageForwarder::connect(quint8 instanceID)
void MessageForwarder::disconnect(quint8 instanceID)
{
- if (instanceID == _toBeForwardedInstanceID && !_hyperion.isNull())
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (instanceID == _toBeForwardedInstanceID && !hyperion.isNull())
{
Debug(_log, "Disconnect forwarder from instance [%u]", instanceID);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(GlobalSignals::getInstance(), &GlobalSignals::setBufferImage, _hyperion.get(), &Hyperion::forwardBufferMessage);
+ QObject::disconnect(GlobalSignals::getInstance(), &GlobalSignals::setBufferImage, hyperion.get(), &Hyperion::forwardBufferMessage);
#endif
handleTargets(false, _config.object());
-
- _hyperion.clear();
- _muxer.clear();
}
}
@@ -165,7 +169,7 @@ void MessageForwarder::handleCompStateChangeRequest(hyperion::Components compone
if (enable)
{
- if (_hyperion.isNull())
+ if (_hyperionWeak.isNull())
{
connect(_toBeForwardedInstanceID);
}
@@ -180,31 +184,43 @@ void MessageForwarder::handleCompStateChangeRequest(hyperion::Components compone
bool MessageForwarder::isFlatbufferComponent(int priority)
{
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion.isNull())
+ {
+ return false;
+ }
+
bool isFlatbufferComponent{ false };
- hyperion::Components const activeCompId = _hyperion->getPriorityInfo(priority).componentId;
+ hyperion::Components const activeCompId = hyperion->getPriorityInfo(priority).componentId;
- switch (activeCompId) {
- case hyperion::COMP_GRABBER:
- case hyperion::COMP_V4L:
- case hyperion::COMP_AUDIO:
+ switch (activeCompId) {
+ case hyperion::COMP_GRABBER:
+ case hyperion::COMP_V4L:
+ case hyperion::COMP_AUDIO:
#if defined(ENABLE_FLATBUF_SERVER)
- case hyperion::COMP_FLATBUFSERVER:
+ case hyperion::COMP_FLATBUFSERVER:
#endif
#if defined(ENABLE_PROTOBUF_SERVER)
- case hyperion::COMP_PROTOSERVER:
+ case hyperion::COMP_PROTOSERVER:
#endif
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- isFlatbufferComponent = true;
- break;
+ isFlatbufferComponent = true;
+ break;
#endif
- default:
- break;
- }
+ default:
+ break;
+ }
return isFlatbufferComponent;
}
bool MessageForwarder::activateFlatbufferTargets(int priority)
{
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion.isNull())
+ {
+ return false;
+ }
+
int startedFlatbufTargets{ 0 };
if (priority != PriorityMuxer::LOWEST_PRIORITY)
@@ -214,16 +230,16 @@ bool MessageForwarder::activateFlatbufferTargets(int priority)
startedFlatbufTargets = startFlatbufferTargets(_config.object());
if (startedFlatbufTargets > 0)
{
- hyperion::Components const activeCompId = _hyperion->getPriorityInfo(priority).componentId;
+ hyperion::Components const activeCompId = hyperion->getPriorityInfo(priority).componentId;
switch (activeCompId) {
case hyperion::COMP_GRABBER:
- QObject::connect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
+ QObject::connect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
break;
case hyperion::COMP_V4L:
- QObject::connect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
+ QObject::connect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
break;
case hyperion::COMP_AUDIO:
- QObject::connect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
+ QObject::connect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
break;
#if defined(ENABLE_FLATBUF_SERVER)
case hyperion::COMP_FLATBUFSERVER:
@@ -233,7 +249,7 @@ bool MessageForwarder::activateFlatbufferTargets(int priority)
#endif
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::connect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
+ QObject::connect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage, Qt::UniqueConnection);
break;
#endif
default:
@@ -252,13 +268,14 @@ void MessageForwarder::handleTargets(bool start, const QJsonObject& config)
stopJsonTargets();
stopFlatbufferTargets();
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
if (start)
{
- int const jsonTargetNum = startJsonTargets(config);
-
- if (!_hyperion.isNull())
+ if (!hyperion.isNull())
{
- int const currentPriority = _hyperion->getCurrentPriority();
+ int const jsonTargetNum = startJsonTargets(config);
+
+ int const currentPriority = hyperion->getCurrentPriority();
bool const isActiveFlatbufferTarget = activateFlatbufferTargets(currentPriority);
if (jsonTargetNum > 0 || isActiveFlatbufferTarget)
@@ -273,41 +290,42 @@ void MessageForwarder::handleTargets(bool start, const QJsonObject& config)
}
}
- if (!_hyperion.isNull())
+ if (!hyperion.isNull())
{
- _hyperion->setNewComponentState(hyperion::COMP_FORWARDER, _isActive);
+ hyperion->setNewComponentState(hyperion::COMP_FORWARDER, _isActive);
}
}
void MessageForwarder::disconnectFlatBufferComponents(int priority)
{
- if (_hyperion.isNull())
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion.isNull())
{
return;
}
- hyperion::Components const activeCompId = _hyperion->getPriorityInfo(priority).componentId;
+ hyperion::Components const activeCompId = hyperion->getPriorityInfo(priority).componentId;
switch (activeCompId) {
case hyperion::COMP_GRABBER:
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#endif
break;
case hyperion::COMP_V4L:
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#endif
break;
case hyperion::COMP_AUDIO:
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#endif
break;
#if defined(ENABLE_FLATBUF_SERVER)
@@ -317,17 +335,17 @@ void MessageForwarder::disconnectFlatBufferComponents(int priority)
case hyperion::COMP_PROTOSERVER:
#endif
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
break;
#endif
default:
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#endif
break;
}
@@ -365,7 +383,7 @@ void MessageForwarder::addJsonTarget(const QJsonObject& targetConfig)
if (!hostName.isEmpty())
{
- if (_hyperion.isNull())
+ if (_hyperionWeak.isNull())
{
return;
}
@@ -470,7 +488,7 @@ void MessageForwarder::addFlatbufferTarget(const QJsonObject& targetConfig)
if (!hostName.isEmpty())
{
- if (_hyperion.isNull())
+ if (_hyperionWeak.isNull())
{
return;
}
@@ -557,13 +575,14 @@ void MessageForwarder::stopFlatbufferTargets()
{
if (!_flatbufferTargets.isEmpty())
{
- if (!_hyperion.isNull())
+ QSharedPointer const hyperion = _hyperionWeak.toStrongRef();
+ if (!hyperion.isNull())
{
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardSystemProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardV4lProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardAudioProtoMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#if defined(ENABLE_FLATBUF_SERVER) || defined(ENABLE_PROTOBUF_SERVER)
- QObject::disconnect(_hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
+ QObject::disconnect(hyperion.get(), &Hyperion::forwardBufferMessage, this, &MessageForwarder::forwardFlatbufferMessage);
#endif
}
diff --git a/libsrc/grabber/qt/QtGrabber.cpp b/libsrc/grabber/qt/QtGrabber.cpp
index 4d2066204..7d31be998 100644
--- a/libsrc/grabber/qt/QtGrabber.cpp
+++ b/libsrc/grabber/qt/QtGrabber.cpp
@@ -16,22 +16,22 @@
// Constants
namespace {
-const bool verbose = false;
+ const bool verbose = false;
} //End of constants
QtGrabber::QtGrabber(int display, int cropLeft, int cropRight, int cropTop, int cropBottom)
: Grabber("GRABBER-QT", cropLeft, cropRight, cropTop, cropBottom)
- , _display(display)
- , _numberOfSDisplays(0)
- , _screenWidth(0)
- , _screenHeight(0)
- , _src_x(0)
- , _src_y(0)
- , _src_x_max(0)
- , _src_y_max(0)
- , _isWayland(false)
- , _screen(nullptr)
- , _isVirtual(false)
+ , _display(display)
+ , _numberOfSDisplays(0)
+ , _screenWidth(0)
+ , _screenHeight(0)
+ , _src_x(0)
+ , _src_y(0)
+ , _src_x_max(0)
+ , _src_y_max(0)
+ , _isWayland(false)
+ , _screen(nullptr)
+ , _isVirtual(false)
{
_useImageResampler = false;
}
@@ -48,13 +48,13 @@ void QtGrabber::freeResources()
bool QtGrabber::isAvailable(bool logError)
{
- #ifndef _WIN32
+#ifndef _WIN32
if (getenv("WAYLAND_DISPLAY") != nullptr)
{
ErrorIf(logError, _log, "Grabber does not work under Wayland!");
_isWayland = true;
}
- #endif
+#endif
_isAvailable = !_isWayland;
return _isAvailable;
@@ -106,7 +106,8 @@ bool QtGrabber::setupDisplay()
for (auto* screen : std::as_const(screens))
{
const QRect geo = screen->geometry();
- Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.width(), geo.height(), geo.x(), geo.y(), geo.x() + geo.width(), geo.y() + geo.height(), screen->depth());
+ qreal devicePixelRatio = screen->devicePixelRatio();
+ Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit DPR:%.2f", index, QSTRING_CSTR(screen->name()), geo.width(), geo.height(), geo.x(), geo.y(), geo.x() + geo.width(), geo.y() + geo.height(), screen->depth(), devicePixelRatio);
++index;
}
@@ -114,7 +115,8 @@ bool QtGrabber::setupDisplay()
if (screens.at(0)->size() != screens.at(0)->virtualSize())
{
const QRect vgeo = screens.at(0)->virtualGeometry();
- Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.width(), vgeo.height(), vgeo.x(), vgeo.y(), vgeo.x() + vgeo.width(), vgeo.y() + vgeo.height(), screens.at(0)->depth());
+ qreal devicePixelRatio = screens.at(0)->devicePixelRatio();
+ Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit DPR:%.2f", _numberOfSDisplays, "All Displays", vgeo.width(), vgeo.height(), vgeo.x(), vgeo.y(), vgeo.x() + vgeo.width(), vgeo.y() + vgeo.height(), screens.at(0)->depth(), devicePixelRatio);
}
_isVirtual = false;
@@ -138,6 +140,7 @@ bool QtGrabber::setupDisplay()
// init the requested display
_screen = screens.at(_display);
connect(_screen, &QScreen::geometryChanged, this, &QtGrabber::geometryChanged);
+ connect(_screen, &QScreen::physicalDotsPerInchChanged, this, &QtGrabber::pixelRatioChanged);
updateScreenDimensions(true);
if (_isVirtual)
@@ -160,50 +163,75 @@ void QtGrabber::geometryChanged(const QRect& geo)
updateScreenDimensions(true);
}
+void QtGrabber::pixelRatioChanged(qreal /* dpi */)
+{
+ Info(_log, "The pixel ratio changed to %.2f", _screen->devicePixelRatio());
+}
+
+
#ifdef _WIN32
extern QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int format = 0);
QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int height) const
{
- QSize windowSize;
HWND hwnd = reinterpret_cast(window);
- if (hwnd)
- {
- RECT r;
- GetClientRect(hwnd, &r);
- windowSize = QSize(r.right - r.left, r.bottom - r.top);
- }
- else
+
+ QSize nativeSize(width, height);
+ if (!nativeSize.isValid())
{
- hwnd = GetDesktopWindow();
- const QRect screenGeometry = _screen->geometry();
- windowSize = screenGeometry.size();
+ QSize windowSize;
+ if (hwnd)
+ {
+ RECT r;
+ GetClientRect(hwnd, &r);
+ windowSize = QSize(r.right - r.left, r.bottom - r.top);
+ }
+ else
+ {
+ hwnd = GetDesktopWindow();
+ const QRect screenGeometry = _screen->geometry();
+ windowSize = screenGeometry.size();
+ }
+
+ if (width < 0)
+ {
+ nativeSize.setWidth(windowSize.width() - xIn);
+ }
+
+ if (height < 0)
+ {
+ nativeSize.setHeight(windowSize.height() - yIn);
+ }
}
- if (width < 0)
- width = windowSize.width() - xIn;
+ // Get device pixel ratio to handle high-DPI displays
+ qreal devicePixelRatio = _screen->devicePixelRatio();
- if (height < 0)
- height = windowSize.height() - yIn;
+ // Scale coordinates by device pixel ratio for physical pixel accuracy
+ QPoint const nativePos = QPoint(xIn, yIn) * devicePixelRatio;
+ nativeSize *= devicePixelRatio;
// Create and setup bitmap
HDC display_dc = GetDC(nullptr);
HDC bitmap_dc = CreateCompatibleDC(display_dc);
- HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height);
+ HBITMAP bitmap = CreateCompatibleBitmap(display_dc, nativeSize.width(), nativeSize.height());
HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
// copy data
HDC window_dc = GetDC(hwnd);
- BitBlt(bitmap_dc, 0, 0, width, height, window_dc, xIn, yIn, SRCCOPY);
+ BitBlt(bitmap_dc, 0, 0, nativeSize.width(), nativeSize.height(), window_dc, nativePos.x(), nativePos.y(), SRCCOPY);
// clean up all but bitmap
ReleaseDC(hwnd, window_dc);
SelectObject(bitmap_dc, null_bitmap);
DeleteDC(bitmap_dc);
- const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
+ QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
DeleteObject(bitmap);
ReleaseDC(nullptr, display_dc);
+ // Set device pixel ratio on the pixmap to ensure proper scaling
+ pixmap.setDevicePixelRatio(devicePixelRatio);
+
return pixmap;
}
#endif
@@ -269,7 +297,10 @@ int QtGrabber::updateScreenDimensions(bool force)
return 0;
}
- Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _screenWidth, _screenHeight, geo.width(), geo.height());
+ // Get device pixel ratio for high-DPI display handling
+ qreal devicePixelRatio = _screen->devicePixelRatio();
+
+ Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d] (Device Pixel Ratio: %.2f)", _screenWidth, _screenHeight, geo.width(), geo.height(), devicePixelRatio);
_screenWidth = geo.width();
_screenHeight = geo.height();
@@ -278,12 +309,12 @@ int QtGrabber::updateScreenDimensions(bool force)
// Image scaling is performed by Qt
width = (_screenWidth > (_cropLeft + _cropRight))
- ? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
- : (_screenWidth / _pixelDecimation);
+ ? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
+ : (_screenWidth / _pixelDecimation);
height = (_screenHeight > (_cropTop + _cropBottom))
- ? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
- : (_screenHeight / _pixelDecimation);
+ ? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
+ : (_screenHeight / _pixelDecimation);
// calculate final image dimensions and adjust top/left cropping in 3D modes
if (_isVirtual)
@@ -327,7 +358,13 @@ int QtGrabber::updateScreenDimensions(bool force)
}
Info(_log, "Update output image resolution to [%dx%d]", _width, _height);
- Debug(_log, "Grab screen area: %d,%d,%d,%d", _src_x, _src_y, _src_x_max, _src_y_max);
+
+ // Scale coordinates by device pixel ratio to get native resolution
+ QPoint const nativePos = QPoint(_src_x, _src_y) * devicePixelRatio;
+ QSize const nativeSize = QSize(_src_x_max, _src_y_max) * devicePixelRatio;
+
+ Debug(_log, "Grab screen area: %d,%d,%d,%d (Physical: %d,%d,%d,%d)", _src_x, _src_y, _src_x_max, _src_y_max,
+ nativePos.x(), nativePos.y(), nativeSize.width(), nativeSize.height());
return 1;
}
diff --git a/libsrc/hyperion/BGEffectHandler.cpp b/libsrc/hyperion/BGEffectHandler.cpp
index 4b28eebe8..6d57570fd 100644
--- a/libsrc/hyperion/BGEffectHandler.cpp
+++ b/libsrc/hyperion/BGEffectHandler.cpp
@@ -5,25 +5,42 @@
#include
-BGEffectHandler::BGEffectHandler(Hyperion* hyperion)
- : QObject(hyperion)
- , _hyperion(hyperion)
+BGEffectHandler::BGEffectHandler(const QSharedPointer& hyperionInstance)
+ : QObject()
+ , _hyperionWeak(hyperionInstance)
, _isBgEffectEnabled(false)
{
- QString subComponent = parent()->property("instance").toString();
+ QString subComponent{ "__" };
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ subComponent = hyperion->property("instance").toString();
+ }
_log = Logger::getInstance("HYPERION", subComponent);
- QObject::connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
- QObject::connect(_hyperion->getMuxerInstance().get(), &PriorityMuxer::prioritiesChanged, this, &BGEffectHandler::handlePriorityUpdate);
+ if (hyperion)
+ {
+ QObject::connect(hyperion.get(), &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
+ QObject::connect(hyperion->getMuxerInstance().get(), &PriorityMuxer::prioritiesChanged, this, &BGEffectHandler::handlePriorityUpdate);
+ }
// initialization
- handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
+ handleSettingsUpdate(settings::BGEFFECT, hyperion->getSetting(settings::BGEFFECT));
+}
+
+BGEffectHandler::~BGEffectHandler()
+{
+ qDebug() << "BGEffectHandler::~BGEffectHandler()...";
}
void BGEffectHandler::disconnect()
{
- QObject::disconnect(_hyperion->getMuxerInstance().get(), &PriorityMuxer::prioritiesChanged, this, &BGEffectHandler::handlePriorityUpdate);
- QObject::disconnect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ QObject::disconnect(hyperion->getMuxerInstance().get(), &PriorityMuxer::prioritiesChanged, this, &BGEffectHandler::handlePriorityUpdate);
+ QObject::disconnect(hyperion.get(), &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
+ }
}
bool BGEffectHandler::_isEnabled () const
@@ -37,12 +54,14 @@ void BGEffectHandler::handleSettingsUpdate(settings::type type, const QJsonDocum
{
_bgEffectConfig = config;
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
+
#define BGCONFIG_ARRAY bgColorConfig.toArray()
// clear background priority
- if (_hyperion->getCurrentPriority() == PriorityMuxer::BG_PRIORITY)
+ if (hyperion->getCurrentPriority() == PriorityMuxer::BG_PRIORITY)
{
- _hyperion->clear(PriorityMuxer::BG_PRIORITY);
+ hyperion->clear(PriorityMuxer::BG_PRIORITY);
}
_isBgEffectEnabled = BGEffectConfig["enable"].toBool(true);
@@ -65,13 +84,13 @@ void BGEffectHandler::handleSettingsUpdate(settings::type type, const QJsonDocum
static_cast(BGCONFIG_ARRAY.at(2).toInt(0))
}
};
- _hyperion->setColor(PriorityMuxer::BG_PRIORITY, bg_color);
+ hyperion->setColor(PriorityMuxer::BG_PRIORITY, bg_color);
Info(_log,"Initial background color set (%d %d %d)",bg_color.at(0).red, bg_color.at(0).green, bg_color.at(0).blue);
}
#if defined(ENABLE_EFFECTENGINE)
else
{
- int result = _hyperion->setEffect(bgEffectConfig, PriorityMuxer::BG_PRIORITY, PriorityMuxer::ENDLESS);
+ int result = hyperion->setEffect(bgEffectConfig, PriorityMuxer::BG_PRIORITY, PriorityMuxer::ENDLESS);
Info(_log,"Initial background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed"));
}
#endif
@@ -82,13 +101,14 @@ void BGEffectHandler::handleSettingsUpdate(settings::type type, const QJsonDocum
void BGEffectHandler::handlePriorityUpdate(int currentPriority)
{
- if (currentPriority < PriorityMuxer::BG_PRIORITY && _hyperion->getMuxerInstance()->hasPriority(PriorityMuxer::BG_PRIORITY))
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (currentPriority < PriorityMuxer::BG_PRIORITY && hyperion->getMuxerInstance()->hasPriority(PriorityMuxer::BG_PRIORITY))
{
Debug(_log,"Stop background (color-) effect as it moved out of scope");
- _hyperion->clear(PriorityMuxer::BG_PRIORITY);
+ hyperion->clear(PriorityMuxer::BG_PRIORITY);
}
// Do not start a background effect when the overall instance is disabled
- else if (_hyperion->isComponentEnabled(hyperion::COMP_ALL))
+ else if (hyperion->isComponentEnabled(hyperion::COMP_ALL))
{
if (currentPriority == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectEnabled)
{
diff --git a/libsrc/hyperion/CaptureCont.cpp b/libsrc/hyperion/CaptureCont.cpp
index 9dfb5accf..5f0b3d44d 100644
--- a/libsrc/hyperion/CaptureCont.cpp
+++ b/libsrc/hyperion/CaptureCont.cpp
@@ -21,98 +21,139 @@ constexpr std::chrono::seconds DEFAULT_SCREEN_CAPTURE_INACTIVE_TIMEOUT{5};
constexpr std::chrono::seconds DEFAULT_AUDIO_CAPTURE_INACTIVE_TIMEOUT{1};
}
-CaptureCont::CaptureCont(Hyperion* hyperion)
- : _hyperion(hyperion)
+CaptureCont::CaptureCont(const QSharedPointer& hyperionInstance)
+ : _hyperionWeak(hyperionInstance)
, _screenCaptureEnabled(false)
, _screenCapturePriority(0)
- , _screenCaptureInactiveTimer(new QTimer(this))
+ , _screenCaptureInactiveTimer(nullptr)
, _videoCaptureEnabled(false)
, _videoCapturePriority(0)
- , _videoInactiveTimer(new QTimer(this))
+ , _videoInactiveTimer(nullptr)
, _audioCaptureEnabled(false)
, _audioCapturePriority(0)
- , _audioCaptureInactiveTimer(new QTimer(this))
+ , _audioCaptureInactiveTimer(nullptr)
{
- // settings changes
- connect(_hyperion, &Hyperion::settingsChanged, this, &CaptureCont::handleSettingsUpdate);
+}
+
+CaptureCont::~CaptureCont()
+{
+ qDebug() << "CaptureCont::~CaptureCont()...";
+}
+
+void CaptureCont::start()
+{
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ // settings changes
+ connect(hyperion.get(), &Hyperion::settingsChanged, this, &CaptureCont::handleSettingsUpdate);
+
+ // comp changes
+ connect(hyperion.get(), &Hyperion::compStateChangeRequest, this, &CaptureCont::handleCompStateChangeRequest);
- // comp changes
- connect(_hyperion, &Hyperion::compStateChangeRequest, this, &CaptureCont::handleCompStateChangeRequest);
- // inactive timer screen
- connect(_screenCaptureInactiveTimer, &QTimer::timeout, this, &CaptureCont::onScreenIsInactive);
- _screenCaptureInactiveTimer->setSingleShot(true);
- _screenCaptureInactiveTimer->setInterval(DEFAULT_SCREEN_CAPTURE_INACTIVE_TIMEOUT);
+ // inactive timer screen
+ _screenCaptureInactiveTimer.reset(new QTimer(this));
+ connect(_screenCaptureInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onScreenIsInactive);
+ _screenCaptureInactiveTimer->setSingleShot(true);
+ _screenCaptureInactiveTimer->setInterval(DEFAULT_SCREEN_CAPTURE_INACTIVE_TIMEOUT);
- // inactive timer video
- connect(_videoInactiveTimer, &QTimer::timeout, this, &CaptureCont::onVideoIsInactive);
- _videoInactiveTimer->setSingleShot(true);
- _videoInactiveTimer->setInterval(DEFAULT_VIDEO_CAPTURE_INACTIVE_TIMEOUT);
+ // inactive timer video
+ _videoInactiveTimer.reset(new QTimer(this));
+ connect(_videoInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onVideoIsInactive);
+ _videoInactiveTimer->setSingleShot(true);
+ _videoInactiveTimer->setInterval(DEFAULT_VIDEO_CAPTURE_INACTIVE_TIMEOUT);
- // inactive timer audio
- connect(_audioCaptureInactiveTimer, &QTimer::timeout, this, &CaptureCont::onAudioIsInactive);
- _audioCaptureInactiveTimer->setSingleShot(true);
- _audioCaptureInactiveTimer->setInterval(DEFAULT_AUDIO_CAPTURE_INACTIVE_TIMEOUT);
+ // inactive timer audio
+ _audioCaptureInactiveTimer.reset(new QTimer(this));
+ connect(_audioCaptureInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onAudioIsInactive);
+ _audioCaptureInactiveTimer->setSingleShot(true);
+ _audioCaptureInactiveTimer->setInterval(DEFAULT_AUDIO_CAPTURE_INACTIVE_TIMEOUT);
- // init
- handleSettingsUpdate(settings::INSTCAPTURE, _hyperion->getSetting(settings::INSTCAPTURE));
+ // init
+ handleSettingsUpdate(settings::INSTCAPTURE, hyperion->getSetting(settings::INSTCAPTURE));
+ }
+}
+
+void CaptureCont::stop()
+{
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
+ if (hyperion)
+ {
+ disconnect(hyperion.get(), &Hyperion::compStateChangeRequest, this, &CaptureCont::handleCompStateChangeRequest);
+ disconnect(hyperion.get(), &Hyperion::settingsChanged, this, &CaptureCont::handleSettingsUpdate);
+ }
+
+ _videoInactiveTimer->stop();
+ _screenCaptureInactiveTimer->stop();
+ _audioCaptureInactiveTimer->stop();
+
+ disconnect(_videoInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onVideoIsInactive);
+ disconnect(_screenCaptureInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onScreenIsInactive);
+ disconnect(_audioCaptureInactiveTimer.get(), &QTimer::timeout, this, &CaptureCont::onAudioIsInactive);
}
void CaptureCont::handleVideoImage(const QString& name, const Image & image)
{
+ QSharedPointer hyperion = _hyperionWeak.toStrongRef();
if(_videoCaptureName != name)
{
- _hyperion->registerInput(_videoCapturePriority, hyperion::COMP_V4L, "System", name);
+ hyperion->registerInput(_videoCapturePriority, hyperion::COMP_V4L, "System", name);
_videoCaptureName = name;
- emit GlobalSignals::getInstance()->requestSource(hyperion::COMP_V4L, int(_hyperion->getInstanceIndex()), _videoCaptureEnabled);
+ emit GlobalSignals::getInstance()->requestSource(hyperion::COMP_V4L, int(hyperion->getInstanceIndex()), _videoCaptureEnabled);
}
_videoInactiveTimer->start();
- _hyperion->setInputImage(_videoCapturePriority, image);
+ hyperion->setInputImage(_videoCapturePriority, image);
}
void CaptureCont::handleScreenImage(const QString& name, const Image& image)
{
+ QSharedPointer