mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-04-14 05:36:36 -05:00
Remove workaround to avoid race conditions
This commit is contained in:
parent
5366a4a6ed
commit
4a3d019f06
|
|
@ -155,6 +155,7 @@ void SwitcherData::Thread()
|
|||
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
mainLoopLock = &lock;
|
||||
|
||||
bool match = false;
|
||||
OBSWeakSource scene;
|
||||
|
|
@ -230,19 +231,6 @@ void SwitcherData::Thread()
|
|||
|
||||
ClearWebsocketMessages();
|
||||
|
||||
// After this point we will call frontend functions like
|
||||
// obs_frontend_set_current_scene() and
|
||||
// obs_frontend_set_current_transition()
|
||||
//
|
||||
// During this time SaveSceneSwitcher() could be called
|
||||
// leading to a deadlock with the frontend function being stuck
|
||||
// in QMetaObject::invokeMethod() holding the mutex and
|
||||
// OBS being stuck in SaveSceneSwitcher().
|
||||
//
|
||||
// So we have to unlock() risking race conditions as these are
|
||||
// less frequent than the above described deadlock
|
||||
lock.unlock();
|
||||
|
||||
if (match) {
|
||||
if (macroMatch) {
|
||||
runMacros();
|
||||
|
|
|
|||
|
|
@ -11,36 +11,39 @@ bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
|||
{MacroActionSwitchScene::Create, MacroActionSwitchSceneEdit::Create,
|
||||
"AdvSceneSwitcher.action.switchScene"});
|
||||
|
||||
void waitForTransitionChange(OBSWeakSource &transition)
|
||||
static void waitForTransitionChange(OBSWeakSource &transition,
|
||||
std::unique_lock<std::mutex> *lock,
|
||||
Macro *macro)
|
||||
{
|
||||
const auto time = 100ms;
|
||||
obs_source_t *source = obs_weak_source_get_source(transition);
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
|
||||
bool stillTransitioning = true;
|
||||
while (stillTransitioning && !switcher->abortMacroWait) {
|
||||
switcher->macroTransitionCv.wait_for(lock, time);
|
||||
while (stillTransitioning && !switcher->abortMacroWait &&
|
||||
!macro->GetStop()) {
|
||||
switcher->macroTransitionCv.wait_for(*lock, time);
|
||||
float t = obs_transition_get_time(source);
|
||||
stillTransitioning = t < 1.0f && t > 0.0f;
|
||||
}
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
void waitForTransitionChangeFixedDuration(int duration)
|
||||
static void waitForTransitionChangeFixedDuration(
|
||||
int duration, std::unique_lock<std::mutex> *lock, Macro *macro)
|
||||
{
|
||||
duration += 200; // It seems to be necessary to add a small buffer
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds(duration);
|
||||
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
while (!switcher->abortMacroWait) {
|
||||
if (switcher->macroTransitionCv.wait_until(lock, time) ==
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getTransitionOverrideDuration(OBSWeakSource &scene)
|
||||
static int getTransitionOverrideDuration(OBSWeakSource &scene)
|
||||
{
|
||||
int duration = 0;
|
||||
obs_source_t *source = obs_weak_source_get_source(scene);
|
||||
|
|
@ -54,7 +57,7 @@ int getTransitionOverrideDuration(OBSWeakSource &scene)
|
|||
return duration;
|
||||
}
|
||||
|
||||
bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
|
||||
static bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
|
||||
{
|
||||
obs_source_t *source = obs_weak_source_get_source(transition);
|
||||
bool ret = obs_transition_fixed(source);
|
||||
|
|
@ -62,7 +65,7 @@ bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
|
|||
return ret;
|
||||
}
|
||||
|
||||
OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
||||
static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
||||
{
|
||||
OBSWeakSource transition;
|
||||
obs_source_t *source = obs_weak_source_get_source(scene);
|
||||
|
|
@ -74,8 +77,8 @@ OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
|||
return transition;
|
||||
}
|
||||
|
||||
int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
double duration)
|
||||
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
double duration)
|
||||
{
|
||||
OBSWeakSource transition = t;
|
||||
if (!switcher->transitionOverrideOverride) {
|
||||
|
|
@ -96,6 +99,37 @@ int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
|||
return obs_frontend_get_transition_duration();
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
const int expectedTransitionDuration = getExpectedTransitionDuration(
|
||||
scene, transition, _duration.seconds);
|
||||
switcher->abortMacroWait = false;
|
||||
|
||||
bool isInMainLoop = QThread::currentThread() == switcher->th;
|
||||
if (isInMainLoop) {
|
||||
if (expectedTransitionDuration < 0) {
|
||||
waitForTransitionChange(transition, switcher->GetLock(),
|
||||
GetMacro());
|
||||
} else {
|
||||
waitForTransitionChangeFixedDuration(
|
||||
expectedTransitionDuration, switcher->GetLock(),
|
||||
GetMacro());
|
||||
}
|
||||
} else {
|
||||
std::mutex temp;
|
||||
std::unique_lock<std::mutex> lock(temp);
|
||||
if (expectedTransitionDuration < 0) {
|
||||
waitForTransitionChange(transition, &lock, GetMacro());
|
||||
} else {
|
||||
waitForTransitionChangeFixedDuration(
|
||||
expectedTransitionDuration, &lock, GetMacro());
|
||||
}
|
||||
}
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::PerformAction()
|
||||
{
|
||||
auto scene = _scene.GetScene();
|
||||
|
|
@ -103,17 +137,7 @@ bool MacroActionSwitchScene::PerformAction()
|
|||
switchScene({scene, transition, (int)(_duration.seconds * 1000)},
|
||||
obs_frontend_preview_program_mode_active());
|
||||
if (_blockUntilTransitionDone && scene) {
|
||||
const int expectedTransitionDuration =
|
||||
getExpectedTransitionDuration(scene, transition,
|
||||
_duration.seconds);
|
||||
switcher->abortMacroWait = false;
|
||||
if (expectedTransitionDuration < 0) {
|
||||
waitForTransitionChange(transition);
|
||||
} else {
|
||||
waitForTransitionChangeFixedDuration(
|
||||
expectedTransitionDuration);
|
||||
}
|
||||
return !switcher->abortMacroWait;
|
||||
return WaitForTransition(scene, transition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public:
|
|||
bool _blockUntilTransitionDone = true;
|
||||
|
||||
private:
|
||||
const char *getType() { return "MacroActionSwitchScene"; }
|
||||
bool WaitForTransition(OBSWeakSource &scene, OBSWeakSource &transition);
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,17 @@ static std::map<WaitType, std::string> waitTypes = {
|
|||
static std::random_device rd;
|
||||
static std::default_random_engine re(rd());
|
||||
|
||||
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
||||
std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroWaitCv.wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionWait::PerformAction()
|
||||
{
|
||||
double sleepDuration;
|
||||
|
|
@ -39,14 +50,15 @@ bool MacroActionWait::PerformAction()
|
|||
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||
auto macro = GetMacro();
|
||||
|
||||
switcher->abortMacroWait = false;
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroWaitCv.wait_until(lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
bool isInMainLoop = QThread::currentThread() == switcher->th;
|
||||
if (isInMainLoop) {
|
||||
waitHelper(switcher->GetLock(), GetMacro(), time);
|
||||
} else {
|
||||
std::mutex temp;
|
||||
std::unique_lock<std::mutex> lock(temp);
|
||||
waitHelper(&lock, GetMacro(), time);
|
||||
}
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
|
|
|
|||
|
|
@ -741,9 +741,6 @@ bool SwitcherData::checkMacros()
|
|||
|
||||
bool SwitcherData::runMacros()
|
||||
{
|
||||
// TODO: Don't rely on creating a copy of each macro once new frontend
|
||||
// events are available - see:
|
||||
// https://github.com/obsproject/obs-studio/commit/feda1aaa283e8a99f6ba1159cfe6b9c1f2934a61
|
||||
for (auto m : macros) {
|
||||
if (m->Matched()) {
|
||||
vblog(LOG_INFO, "running macro: %s", m->Name().c_str());
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ struct SwitcherData {
|
|||
|
||||
std::condition_variable cv;
|
||||
std::mutex m;
|
||||
std::unique_lock<std::mutex> *mainLoopLock;
|
||||
|
||||
bool transitionActive = false;
|
||||
bool waitForTransition = false;
|
||||
bool stop = false;
|
||||
|
|
@ -251,6 +253,7 @@ struct SwitcherData {
|
|||
void Thread();
|
||||
void Start();
|
||||
void Stop();
|
||||
std::unique_lock<std::mutex> *GetLock() { return mainLoopLock; }
|
||||
|
||||
void setWaitScene();
|
||||
bool sceneChangedDuringWait();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user