Allow running macros in parallel to other macros

This commit is contained in:
WarmUpTill 2021-11-27 23:54:12 +01:00 committed by WarmUpTill
parent 9dd47b811b
commit 845506f7e4
8 changed files with 89 additions and 19 deletions

View File

@ -67,6 +67,8 @@ AdvSceneSwitcher.macroTab.edit.action="Action type:"
AdvSceneSwitcher.macroTab.add="Add new macro"
AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Run macro"
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
AdvSceneSwitcher.macroTab.copy="Create copy"

View File

@ -722,7 +722,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0">
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0">
<item>
<widget class="QLabel" name="label_20">
<property name="text">
@ -740,6 +740,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="runMacroInParallel">
<property name="text">
<string>AdvSceneSwitcher.macroTab.runInParallel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">

View File

@ -98,6 +98,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
obs_data_release(obj);
} else {
// Stop the scene switcher at least once to
// avoid scene duplication issues with scene collection changes
bool start = !switcher->stop;
switcher->Stop();
switcher->m.lock();
obs_data_t *obj =
obs_data_get_obj(save_data, "advanced-scene-switcher");
@ -111,10 +116,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(obj);
switcher->m.unlock();
// Stop the scene switcher at least once to
// avoid scene duplication issues with scene collection changes
bool start = !switcher->stop;
switcher->Stop();
if (start) {
switcher->Start();
}
@ -410,9 +411,9 @@ void SwitcherData::Stop()
{
if (th && th->isRunning()) {
stop = true;
cv.notify_one();
cv.notify_all();
abortMacroWait = true;
macroWaitCv.notify_one();
macroWaitCv.notify_all();
th->wait();
delete th;
th = nullptr;

View File

@ -116,6 +116,7 @@ public slots:
void on_macroDown_clicked();
void on_macroName_editingFinished();
void on_runMacro_clicked();
void on_runMacroInParallel_stateChanged(int value);
void on_macros_currentRowChanged(int idx);
void on_macros_itemChanged(QListWidgetItem *);
void on_conditionAdd_clicked();

View File

@ -2,13 +2,14 @@
#include "macro-segment.hpp"
#include "duration-control.hpp"
#include <QString>
#include <string>
#include <deque>
#include <memory>
#include <map>
#include <thread>
#include <obs.hpp>
#include <obs-module.h>
#include <QString>
constexpr auto macro_func = 10;
constexpr auto default_priority_10 = macro_func;
@ -73,10 +74,12 @@ public:
virtual ~Macro();
bool CeckMatch();
bool PerformAction();
bool PerformAction(bool forceParallel = false);
bool Matched() { return _matched; }
std::string Name() { return _name; }
void SetName(const std::string &name);
void SetRunInParallel(bool parallel) { _runInParallel = parallel; }
bool RunInParallel() { return _runInParallel; }
void SetPaused(bool pause = true);
bool Paused() { return _paused; }
int GetCount() { return _count; };
@ -103,16 +106,23 @@ private:
void ClearHotkeys();
void SetHotkeysDesc();
void ResetTimers();
void RunActions(bool &ret);
void RunActions();
std::string _name = "";
std::deque<std::shared_ptr<MacroCondition>> _conditions;
std::deque<std::shared_ptr<MacroAction>> _actions;
bool _runInParallel = false;
bool _matched = false;
bool _paused = false;
int _count = 0;
obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _togglePauseHotkey = OBS_INVALID_HOTKEY_ID;
bool _stop = false;
bool _done = true;
std::thread _thread;
};
Macro *GetMacroByName(const char *name);

View File

@ -184,7 +184,7 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
std::lock_guard<std::mutex> lock(switcher->m);
macro->Actions().erase(macro->Actions().begin() + idx);
switcher->abortMacroWait = true;
switcher->macroWaitCv.notify_one();
switcher->macroWaitCv.notify_all();
macro->UpdateActionIndices();
clearLayout(ui->macroEditActionLayout, idx);

View File

@ -82,7 +82,7 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
{
std::lock_guard<std::mutex> lock(switcher->m);
switcher->abortMacroWait = true;
switcher->macroWaitCv.notify_one();
switcher->macroWaitCv.notify_all();
int idx = ui->macros->currentRow();
QString::fromStdString(switcher->macros[idx]->Name());
switcher->macros.erase(switcher->macros.begin() + idx);
@ -180,7 +180,22 @@ void AdvSceneSwitcher::on_runMacro_clicked()
return;
}
macro->PerformAction();
bool ret = macro->PerformAction(true);
if (!ret) {
QString err =
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
DisplayMessage(err.arg(QString::fromStdString(macro->Name())));
}
}
void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
{
Macro *macro = getSelectedMacro();
if (!macro) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
macro->SetRunInParallel(value);
}
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
@ -215,6 +230,7 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
void AdvSceneSwitcher::SetEditMacro(Macro &m)
{
ui->macroName->setText(m.Name().c_str());
ui->runMacroInParallel->setChecked(m.RunInParallel());
clearLayout(ui->macroEditConditionLayout);
clearLayout(ui->macroEditActionLayout);

View File

@ -29,6 +29,10 @@ Macro::Macro(const std::string &name)
Macro::~Macro()
{
_stop = true;
if (_thread.joinable()) {
_thread.join();
}
ClearHotkeys();
}
@ -104,15 +108,22 @@ bool Macro::CeckMatch()
return _matched;
}
bool Macro::PerformAction()
bool Macro::PerformAction(bool forceParallel)
{
if (!_done) {
vblog(LOG_INFO, "macro %s already running", _name.c_str());
return false;
}
bool ret = true;
for (auto &a : _actions) {
a->LogAction();
ret = ret && a->PerformAction();
if (!ret) {
return false;
_done = false;
if (_runInParallel || forceParallel) {
if (_thread.joinable()) {
_thread.join();
}
_thread = std::thread([this] { RunActions(); });
} else {
RunActions(ret);
}
return ret;
}
@ -130,6 +141,27 @@ void Macro::ResetTimers()
}
}
void Macro::RunActions(bool &retVal)
{
bool ret = true;
for (auto &a : _actions) {
a->LogAction();
ret = ret && a->PerformAction();
if (!ret || _stop) {
retVal = ret;
_done = true;
return;
}
}
_done = true;
}
void Macro::RunActions()
{
bool unused;
RunActions(unused);
}
void Macro::SetPaused(bool pause)
{
if (_paused && !pause) {
@ -160,6 +192,7 @@ bool Macro::Save(obs_data_t *obj)
{
obs_data_set_string(obj, "name", _name.c_str());
obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel);
obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey);
obs_data_set_array(obj, "pauseHotkey", pauseHotkey);
@ -237,6 +270,7 @@ bool Macro::Load(obs_data_t *obj)
{
_name = obs_data_get_string(obj, "name");
_paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel");
obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey");
obs_hotkey_load(_pauseHotkey, pauseHotkey);
@ -541,7 +575,6 @@ bool SwitcherData::runMacros()
if (!m->PerformAction()) {
blog(LOG_WARNING, "abort macro: %s",
m->Name().c_str());
return false;
}
}
}