diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui
index 9de1230b..f1fc9e12 100644
--- a/forms/advanced-scene-switcher.ui
+++ b/forms/advanced-scene-switcher.ui
@@ -365,7 +365,7 @@
-
- Use thread priority (experimental)
+ Use thread priority
@@ -385,6 +385,13 @@
+ -
+
+
+ (raising the priority higher than "Normal" is usually not recommended)
+
+
+
-
diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp
index 0f2196f2..df59e982 100644
--- a/src/advanced-scene-switcher.cpp
+++ b/src/advanced-scene-switcher.cpp
@@ -64,8 +64,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
QComboBox *combo = reinterpret_cast(data);
- if (obs_source_media_get_state(source) !=
- OBS_MEDIA_STATE_NONE) {
+ if (strcmp(obs_source_get_id(source), "ffmpeg_source") == 0) {
const char *name = obs_source_get_name(source);
combo->addItem(name);
}
@@ -354,7 +353,7 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
ui->readPathLineEdit->setDisabled(true);
}
- if (switcher->th.joinable())
+ if (switcher->th && switcher->th->isRunning())
SetStarted();
else
SetStopped();
@@ -401,8 +400,17 @@ SceneSwitcher::SceneSwitcher(QWidget *parent)
item->setData(Qt::UserRole, text);
}
- for (std::string p : switcher->threadPrioritiesNamesOrderdByPrio) {
- ui->threadPriority->addItem(p.c_str());
+ for (int i = 0; i < switcher->threadPriorities.size(); ++i) {
+ ui->threadPriority->addItem(
+ switcher->threadPriorities[i].name.c_str());
+ ui->threadPriority->setItemData(
+ i, switcher->threadPriorities[i].description.c_str(),
+ Qt::ToolTipRole);
+ if (switcher->threadPriority ==
+ switcher->threadPriorities[i].value) {
+ ui->threadPriority->setCurrentText(
+ switcher->threadPriorities[i].name.c_str());
+ }
}
}
@@ -885,6 +893,9 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_set_int(obj, "priority7",
switcher->functionNamesByPriority[7]);
+ obs_data_set_int(obj, "threadPriority",
+ switcher->threadPriority);
+
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
obs_data_array_release(array);
@@ -1246,12 +1257,19 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
array_obj, "restriction");
uint64_t time = obs_data_get_int(array_obj, "time");
+ string mediaStr = MakeMediaSwitchName(source, scene,
+ transition, state,
+ restriction, time)
+ .toUtf8()
+ .constData();
+
switcher->mediaSwitches.emplace_back(
GetWeakSourceByName(scene),
GetWeakSourceByName(source),
GetWeakTransitionByName(transition), state,
restriction, time,
- (strcmp(scene, PREVIOUS_SCENE_NAME) == 0));
+ (strcmp(scene, PREVIOUS_SCENE_NAME) == 0),
+ mediaStr);
obs_data_release(array_obj);
}
@@ -1362,6 +1380,11 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
(DEFAULT_PRIORITY_7);
}
+ obs_data_set_default_int(obj, "threadPriority",
+ QThread::NormalPriority);
+ switcher->threadPriority =
+ obs_data_get_int(obj, "threadPriority");
+
obs_data_array_release(array);
obs_data_array_release(screenRegionArray);
obs_data_array_release(pauseScenesArray);
@@ -1392,6 +1415,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
********************************************************************************/
void SwitcherData::Thread()
{
+ blog(LOG_INFO, "Advanced Scene Switcher started");
//to avoid scene duplication when rapidly switching scene collection
this_thread::sleep_for(chrono::seconds(2));
@@ -1483,7 +1507,8 @@ void SwitcherData::Thread()
switchScene(scene, transition, lock);
}
}
-endLoop:;
+endLoop:
+ blog(LOG_INFO, "Advanced Scene Switcher stopped");
}
void switchScene(OBSWeakSource &scene, OBSWeakSource &transition,
@@ -1542,19 +1567,23 @@ bool SwitcherData::sceneChangedDuringWait()
void SwitcherData::Start()
{
- if (!th.joinable()) {
+ if (!(th && th->isRunning())) {
stop = false;
- switcher->th = thread([]() { switcher->Thread(); });
+ switcher->th = new SwitcherThread();
+ switcher->th->start((QThread::Priority)switcher->threadPriority);
}
}
+
void SwitcherData::Stop()
{
- if (th.joinable()) {
+ if (th && th->isRunning()) {
switcher->stop = true;
transitionCv.notify_one();
cv.notify_one();
- th.join();
+ th->wait();
+ delete th;
+ th = nullptr;
}
}
diff --git a/src/general.cpp b/src/general.cpp
index 3fe65e72..9bc85203 100644
--- a/src/general.cpp
+++ b/src/general.cpp
@@ -89,7 +89,7 @@ void SceneSwitcher::SetStopped()
void SceneSwitcher::on_toggleStartButton_clicked()
{
- if (switcher->th.joinable())
+ if (switcher->th && switcher->th->isRunning())
{
switcher->Stop();
SetStopped();
diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp
index e5be0b4c..591e2348 100644
--- a/src/headers/advanced-scene-switcher.hpp
+++ b/src/headers/advanced-scene-switcher.hpp
@@ -120,6 +120,7 @@ public slots:
void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked();
+ void on_mediaSwitches_currentRowChanged(int idx);
void on_mediaAdd_clicked();
void on_mediaRemove_clicked();
@@ -129,6 +130,7 @@ public slots:
void on_priorityUp_clicked();
void on_priorityDown_clicked();
+ void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos();
diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp
index b873f7ba..bcdca7b2 100644
--- a/src/headers/switcher-data-structs.hpp
+++ b/src/headers/switcher-data-structs.hpp
@@ -3,7 +3,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -214,18 +213,20 @@ struct MediaSwitch {
time_restriction restriction;
bool matched;
bool usePreviousScene;
+ std::string mediaSwitchStr;
inline MediaSwitch(OBSWeakSource scene_, OBSWeakSource source_,
OBSWeakSource transition_, obs_media_state state_,
time_restriction restriction_, uint64_t time_,
- bool usePreviousScene_)
+ bool usePreviousScene_, std::string mediaSwitchStr_)
: scene(scene_),
source(source_),
transition(transition_),
state(state_),
restriction(restriction_),
time(time_),
- usePreviousScene(usePreviousScene_)
+ usePreviousScene(usePreviousScene_),
+ mediaSwitchStr(mediaSwitchStr_)
{
}
};
@@ -252,11 +253,14 @@ struct TimeSwitch {
typedef enum { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 } NoMatch;
+class SwitcherThread;
+
/********************************************************************************
* SwitcherData
********************************************************************************/
struct SwitcherData {
- thread th;
+ SwitcherThread *th;
+
condition_variable cv;
mutex m;
bool transitionActive = false;
@@ -311,18 +315,33 @@ struct SwitcherData {
DEFAULT_PRIORITY_3, DEFAULT_PRIORITY_4, DEFAULT_PRIORITY_5,
DEFAULT_PRIORITY_6, DEFAULT_PRIORITY_7};
- std::vector threadPrioritiesNamesOrderdByPrio{
- "Lowest", "Low", "Normal", "High", "Highest", "Time critical",
+ struct ThreadPrio {
+ std::string name;
+ std::string description;
+ uint32_t value;
};
- std::map threadPriorities = {
- {"Lowest", QThread::LowestPriority},
- {"Low", QThread::LowPriority},
- {"Normal", QThread::NormalPriority},
- {"High", QThread::HighPriority},
- {"Highest", QThread::HighestPriority},
- {"Time critical", QThread::TimeCriticalPriority},
+
+ std::vector threadPriorities{
+ {"Idle",
+ "scheduled only when no other threads are running (lowest CPU load)",
+ QThread::IdlePriority},
+ {"Lowest", "scheduled less often than LowPriority",
+ QThread::LowestPriority},
+ {"Low", "scheduled less often than NormalPriority",
+ QThread::LowPriority},
+ {"Normal", "the default priority of the operating system",
+ QThread::NormalPriority},
+ {"High", "scheduled more often than NormalPriority",
+ QThread::HighPriority},
+ {"Highest", "scheduled more often than HighPriority",
+ QThread::HighestPriority},
+ {"Time critical",
+ "scheduled as often as possible (highest CPU load)",
+ QThread::TimeCriticalPriority},
};
+ uint32_t threadPriority = QThread::NormalPriority;
+
void Thread();
void Start();
void Stop();
@@ -442,7 +461,8 @@ struct SwitcherData {
for (size_t i = 0; i < timeSwitches.size(); i++) {
TimeSwitch &s = timeSwitches[i];
- if (!WeakSourceValid(s.scene) ||
+ if ((!s.usePreviousScene &&
+ !WeakSourceValid(s.scene)) ||
!WeakSourceValid(s.transition))
timeSwitches.erase(timeSwitches.begin() + i--);
}
@@ -452,6 +472,23 @@ struct SwitcherData {
!WeakSourceValid(idleData.transition)) {
idleData.idleEnable = false;
}
+
+ for (size_t i = 0; i < mediaSwitches.size(); i++) {
+ MediaSwitch &s = mediaSwitches[i];
+ if ((!s.usePreviousScene &&
+ !WeakSourceValid(s.scene)) ||
+ !WeakSourceValid(s.source) ||
+ !WeakSourceValid(s.transition))
+ mediaSwitches.erase(mediaSwitches.begin() +
+ i--);
+ }
}
inline ~SwitcherData() { Stop(); }
};
+
+extern SwitcherData *switcher;
+class SwitcherThread : public QThread {
+public:
+ explicit SwitcherThread(){};
+ void run() { switcher->Thread(); };
+};
diff --git a/src/hotkey.cpp b/src/hotkey.cpp
index 924eedbb..f95b5773 100644
--- a/src/hotkey.cpp
+++ b/src/hotkey.cpp
@@ -8,7 +8,7 @@ void startHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pr
if (pressed)
{
- if (!switcher->th.joinable())
+ if (!(switcher->th && switcher->th->isRunning()))
switcher->Start();
}
@@ -43,7 +43,7 @@ void stopHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotkey, bool pre
if (pressed)
{
- if (switcher->th.joinable())
+ if (switcher->th && switcher->th->isRunning())
switcher->Stop();
}
@@ -78,7 +78,7 @@ void startStopToggleHotkeyFunc(void* data, obs_hotkey_id id, obs_hotkey_t* hotke
if (pressed)
{
- if (switcher->th.joinable())
+ if (switcher->th && switcher->th->isRunning())
switcher->Stop();
else
switcher->Start();
diff --git a/src/media-switch.cpp b/src/media-switch.cpp
index 07dbb3a0..92e8767a 100644
--- a/src/media-switch.cpp
+++ b/src/media-switch.cpp
@@ -1,6 +1,37 @@
#include
#include "headers/advanced-scene-switcher.hpp"
+void SceneSwitcher::on_mediaSwitches_currentRowChanged(int idx)
+{
+ if (loading)
+ return;
+ if (idx == -1)
+ return;
+
+ QListWidgetItem *item = ui->mediaSwitches->item(idx);
+
+ QString mediaSceneStr = item->data(Qt::UserRole).toString();
+
+ lock_guard lock(switcher->m);
+ for (auto &s : switcher->mediaSwitches) {
+ if (mediaSceneStr.compare(s.mediaSwitchStr.c_str()) == 0) {
+ QString sceneName = GetWeakSourceName(s.scene).c_str();
+ QString sourceName =
+ GetWeakSourceName(s.source).c_str();
+ QString transitionName =
+ GetWeakSourceName(s.transition).c_str();
+ ui->mediaScenes->setCurrentText(sceneName);
+ ui->mediaSources->setCurrentText(sourceName);
+ ui->mediaTransitions->setCurrentText(transitionName);
+ ui->mediaStates->setCurrentIndex(s.state);
+ ui->mediaTimeRestrictions->setCurrentIndex(
+ s.restriction);
+ ui->mediaTime->setValue(s.time);
+ break;
+ }
+ }
+}
+
void SceneSwitcher::on_mediaAdd_clicked()
{
QString sourceName = ui->mediaSources->currentText();
@@ -32,7 +63,8 @@ void SceneSwitcher::on_mediaAdd_clicked()
lock_guard lock(switcher->m);
switcher->mediaSwitches.emplace_back(
scene, source, transition, state, restriction, time,
- (sceneName == QString(PREVIOUS_SCENE_NAME)));
+ (sceneName == QString(PREVIOUS_SCENE_NAME)),
+ switchText.toUtf8().constData());
}
void SceneSwitcher::on_mediaRemove_clicked()
@@ -41,17 +73,23 @@ void SceneSwitcher::on_mediaRemove_clicked()
if (!item)
return;
- int idx = ui->mediaSwitches->currentRow();
- if (idx == -1)
- return;
-
+ string mediaStr =
+ item->data(Qt::UserRole).toString().toUtf8().constData();
{
lock_guard lock(switcher->m);
-
auto &switches = switcher->mediaSwitches;
- switches.erase(switches.begin() + idx);
+
+ for (auto it = switches.begin(); it != switches.end(); ++it) {
+ auto &s = *it;
+
+ if (s.mediaSwitchStr == mediaStr) {
+ switches.erase(it);
+ break;
+ }
+ }
}
- qDeleteAll(ui->mediaSwitches->selectedItems());
+
+ delete item;
}
void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
@@ -86,5 +124,6 @@ void SwitcherData::checkMediaSwitch(bool &match, OBSWeakSource &scene,
transition = mediaSwitch.transition;
}
mediaSwitch.matched = matched;
+ obs_source_release(source);
}
}
diff --git a/src/priority.cpp b/src/priority.cpp
index 22019b9c..60f5e30e 100644
--- a/src/priority.cpp
+++ b/src/priority.cpp
@@ -1,44 +1,68 @@
#include
#include "headers/advanced-scene-switcher.hpp"
+void SceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
+{
+ if (loading || ui->threadPriority->count() != switcher->threadPriorities.size())
+ return;
+
+ lock_guard lock(switcher->m);
+
+ for (auto p : switcher->threadPriorities) {
+ if (p.name == text.toUtf8()
+ .constData()) {
+ switcher->threadPriority = p.value;
+ break;
+ }
+ }
+}
+
void SceneSwitcher::on_priorityUp_clicked()
{
int currentIndex = ui->priorityList->currentRow();
- if (currentIndex != -1 && currentIndex != 0)
- {
- ui->priorityList->insertItem(currentIndex - 1 ,ui->priorityList->takeItem(currentIndex));
- ui->priorityList->setCurrentRow(currentIndex -1);
+ if (currentIndex != -1 && currentIndex != 0) {
+ ui->priorityList->insertItem(
+ currentIndex - 1,
+ ui->priorityList->takeItem(currentIndex));
+ ui->priorityList->setCurrentRow(currentIndex - 1);
lock_guard lock(switcher->m);
- iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex - 1);
+ iter_swap(switcher->functionNamesByPriority.begin() +
+ currentIndex,
+ switcher->functionNamesByPriority.begin() +
+ currentIndex - 1);
}
}
void SceneSwitcher::on_priorityDown_clicked()
{
int currentIndex = ui->priorityList->currentRow();
- if (currentIndex != -1 && currentIndex != ui->priorityList->count() - 1)
- {
- ui->priorityList->insertItem(currentIndex + 1, ui->priorityList->takeItem(currentIndex));
+ if (currentIndex != -1 &&
+ currentIndex != ui->priorityList->count() - 1) {
+ ui->priorityList->insertItem(
+ currentIndex + 1,
+ ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1);
lock_guard lock(switcher->m);
- iter_swap(switcher->functionNamesByPriority.begin() + currentIndex, switcher->functionNamesByPriority.begin() + currentIndex + 1);
+ iter_swap(switcher->functionNamesByPriority.begin() +
+ currentIndex,
+ switcher->functionNamesByPriority.begin() +
+ currentIndex + 1);
}
}
bool SwitcherData::prioFuncsValid()
{
- auto it = std::unique(functionNamesByPriority.begin(), functionNamesByPriority.end());
+ auto it = std::unique(functionNamesByPriority.begin(),
+ functionNamesByPriority.end());
bool wasUnique = (it == functionNamesByPriority.end());
if (!wasUnique)
return false;
- for (int p : functionNamesByPriority)
- {
+ for (int p : functionNamesByPriority) {
if (p < 0 || p > 7)
return false;
}
return true;
}
-