From b1485adfd212f750fed17018fbc5bab03ba9ab44 Mon Sep 17 00:00:00 2001 From: Kishi85 Date: Wed, 17 Jun 2026 16:12:36 +0200 Subject: [PATCH 1/3] fix(linux/pipewire): Do not stop pw_thread_loop twice and early Before it was stopped at the beginning and end of the destructor. Doing it once at the end is what makes sense logically. --- src/platform/linux/pipewire.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/platform/linux/pipewire.cpp b/src/platform/linux/pipewire.cpp index a571f0e471c..af9f6166a23 100644 --- a/src/platform/linux/pipewire.cpp +++ b/src/platform/linux/pipewire.cpp @@ -117,16 +117,12 @@ namespace pipewire { ~pipewire_t() { BOOST_LOG(debug) << "[pipewire] Destroying pipewire_t"sv; - if (loop) { - BOOST_LOG(debug) << "[pipewire] Stop PW thread loop"sv; - pw_thread_loop_stop(loop); - } try { cleanup_stream(); } catch (const std::exception &e) { - BOOST_LOG(error) << "[pipewire] Standard exception caught in ~pipewire_t: "sv << e.what(); + BOOST_LOG(error) << "[pipewire] Standard exception caught in ~pipewire_t cleanup_stream: "sv << e.what(); } catch (...) { - BOOST_LOG(error) << "[pipewire] Unknown exception caught in ~pipewire_t"sv; + BOOST_LOG(error) << "[pipewire] Unknown exception caught in ~pipewire_t cleanup_stream"sv; } pw_thread_loop_lock(loop); From c5a18c34db5d9546f245c2b8425974cc63de475c Mon Sep 17 00:00:00 2001 From: Kishi85 Date: Thu, 4 Jun 2026 16:10:30 +0200 Subject: [PATCH 2/3] fix(linux/pipewire): avoid video stream freeze (on display switch) This is a trial-and-error workaround to avoid video stream freezing when display switching that somehow happens when not using the added thread sleeps due to a racecondition that needs to be further diagnosed. Pipewire state change logging is also move to information log level to improve initial issue analysis without enabling debug logging --- src/platform/linux/pipewire.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/platform/linux/pipewire.cpp b/src/platform/linux/pipewire.cpp index af9f6166a23..6deb9464ed4 100644 --- a/src/platform/linux/pipewire.cpp +++ b/src/platform/linux/pipewire.cpp @@ -438,8 +438,13 @@ namespace pipewire { }; static void on_stream_state_changed(void *user_data, enum pw_stream_state old, enum pw_stream_state state, const char *err_msg) { - BOOST_LOG(debug) << "[pipewire] PipeWire stream state: " << pw_stream_state_as_string(old) - << " -> " << pw_stream_state_as_string(state); + if (err_msg != nullptr) { + BOOST_LOG(info) << "[pipewire] PipeWire stream error '" << err_msg << "' on state: " << pw_stream_state_as_string(old) + << " -> " << pw_stream_state_as_string(state); + } else { + BOOST_LOG(info) << "[pipewire] PipeWire stream state: " << pw_stream_state_as_string(old) + << " -> " << pw_stream_state_as_string(state); + } auto *d = static_cast(user_data); @@ -871,18 +876,20 @@ namespace pipewire { case platf::capture_e::timeout: if (!pull_free_image_cb(img_out)) { // Detect if shutdown is pending - BOOST_LOG(debug) << "[pipewire] PipeWire: timeout -> interrupt nudge"; + BOOST_LOG(debug) << "[pipewire] PipeWire: timeout -> shutdown pending -> interrupt nudge"; pipewire.frame_cv().notify_all(); return platf::capture_e::interrupted; } if (!push_captured_image_cb(std::move(img_out), false)) { - BOOST_LOG(debug) << "[pipewire] PipeWire: !push_captured_image_cb -> ok"; + BOOST_LOG(debug) << "[pipewire] PipeWire: timeout -> !push_captured_image_cb -> ok"; + std::this_thread::sleep_for(10us); // Workaround: delay OK to avoid video stream freezing return platf::capture_e::ok; } break; case platf::capture_e::ok: if (!push_captured_image_cb(std::move(img_out), true)) { - BOOST_LOG(debug) << "[pipewire] PipeWire: !push_captured_image_cb -> ok"; + BOOST_LOG(debug) << "[pipewire] PipeWire: ok -> !push_captured_image_cb -> ok"; + std::this_thread::sleep_for(10us); // Workaround: delay OK to avoid video stream freezing return platf::capture_e::ok; } break; From e787fbc598a18b6839f7448ec6024de41378a2a0 Mon Sep 17 00:00:00 2001 From: Kishi85 Date: Thu, 25 Jun 2026 10:07:53 +0200 Subject: [PATCH 3/3] fix(video): add try_pop() to thread_safe.h and use it to free images in video.cpp Also remove sleep workaround from pipewire.cpp Co-Authored-By: psyke83 --- src/platform/linux/pipewire.cpp | 2 -- src/thread_safe.h | 12 +++++++++++- src/video.cpp | 3 +-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/platform/linux/pipewire.cpp b/src/platform/linux/pipewire.cpp index 6deb9464ed4..7c9fed69c7e 100644 --- a/src/platform/linux/pipewire.cpp +++ b/src/platform/linux/pipewire.cpp @@ -882,14 +882,12 @@ namespace pipewire { } if (!push_captured_image_cb(std::move(img_out), false)) { BOOST_LOG(debug) << "[pipewire] PipeWire: timeout -> !push_captured_image_cb -> ok"; - std::this_thread::sleep_for(10us); // Workaround: delay OK to avoid video stream freezing return platf::capture_e::ok; } break; case platf::capture_e::ok: if (!push_captured_image_cb(std::move(img_out), true)) { BOOST_LOG(debug) << "[pipewire] PipeWire: ok -> !push_captured_image_cb -> ok"; - std::this_thread::sleep_for(10us); // Workaround: delay OK to avoid video stream freezing return platf::capture_e::ok; } break; diff --git a/src/thread_safe.h b/src/thread_safe.h index 4f2448f1b59..3714c0469ec 100644 --- a/src/thread_safe.h +++ b/src/thread_safe.h @@ -38,6 +38,16 @@ namespace safe { _cv.notify_all(); } + status_t try_pop() { + std::lock_guard lg {_lock}; + if (!_status) { + return util::false_v; + } + auto val = std::move(_status); + _status = util::false_v; + return val; + } + // pop and view should not be used interchangeably status_t pop() { std::unique_lock ul {_lock}; @@ -72,7 +82,7 @@ namespace safe { } auto val = std::move(_status); - _status.reset(); + _status = util::false_v; return val; } diff --git a/src/video.cpp b/src/video.cpp index 0900d999de6..74b10778dba 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -1461,8 +1461,7 @@ namespace video { continue; } - while (capture_ctx->images->peek()) { - capture_ctx->images->pop(); + while (capture_ctx->images->try_pop()) { } ++capture_ctx;