mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-04-02 15:35:30 +08:00
[fix] fix Wayland reconnect black screen by keeping capturer warm and also fix Wayland mouse control
This commit is contained in:
@@ -12,22 +12,27 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "platform.h"
|
||||
#include "rd_log.h"
|
||||
#include "wayland_portal_shared.h"
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
namespace {
|
||||
|
||||
bool IsWaylandSession() {
|
||||
const char* session_type = getenv("XDG_SESSION_TYPE");
|
||||
if (session_type && strcmp(session_type, "wayland") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* wayland_display = getenv("WAYLAND_DISPLAY");
|
||||
return wayland_display && wayland_display[0] != '\0';
|
||||
int64_t NowMs() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
struct PipeWireRecoveryConfig {
|
||||
ScreenCapturerWayland::PipeWireConnectMode mode;
|
||||
bool relaxed_connect = false;
|
||||
};
|
||||
|
||||
constexpr auto kPipeWireCloseSettleDelay = std::chrono::milliseconds(200);
|
||||
|
||||
} // namespace
|
||||
|
||||
ScreenCapturerWayland::ScreenCapturerWayland() {}
|
||||
@@ -54,6 +59,8 @@ int ScreenCapturerWayland::Init(const int fps, cb_desktop_data cb) {
|
||||
|
||||
fps_ = fps;
|
||||
callback_ = cb;
|
||||
pointer_granted_ = false;
|
||||
shared_session_registered_ = false;
|
||||
display_info_list_.clear();
|
||||
display_info_list_.push_back(
|
||||
DisplayInfo(display_name_, 0, 0, kFallbackWidth, kFallbackHeight));
|
||||
@@ -62,6 +69,8 @@ int ScreenCapturerWayland::Init(const int fps, cb_desktop_data cb) {
|
||||
frame_width_ = kFallbackWidth;
|
||||
frame_height_ = kFallbackHeight;
|
||||
frame_stride_ = kFallbackWidth * 4;
|
||||
logical_width_ = kFallbackWidth;
|
||||
logical_height_ = kFallbackHeight;
|
||||
y_plane_.resize(kFallbackWidth * kFallbackHeight);
|
||||
uv_plane_.resize((kFallbackWidth / 2) * (kFallbackHeight / 2) * 2);
|
||||
|
||||
@@ -84,6 +93,13 @@ int ScreenCapturerWayland::Start(bool show_cursor) {
|
||||
|
||||
show_cursor_ = show_cursor;
|
||||
paused_ = false;
|
||||
pipewire_node_id_ = 0;
|
||||
UpdateDisplayGeometry(logical_width_ > 0 ? logical_width_ : kFallbackWidth,
|
||||
logical_height_ > 0 ? logical_height_
|
||||
: kFallbackHeight);
|
||||
pipewire_format_ready_.store(false);
|
||||
pipewire_stream_start_ms_.store(0);
|
||||
pipewire_last_frame_ms_.store(0);
|
||||
running_ = true;
|
||||
thread_ = std::thread([this]() { Run(); });
|
||||
return 0;
|
||||
@@ -94,6 +110,10 @@ int ScreenCapturerWayland::Stop() {
|
||||
if (thread_.joinable()) {
|
||||
thread_.join();
|
||||
}
|
||||
pipewire_node_id_ = 0;
|
||||
UpdateDisplayGeometry(logical_width_ > 0 ? logical_width_ : kFallbackWidth,
|
||||
logical_height_ > 0 ? logical_height_
|
||||
: kFallbackHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -127,23 +147,96 @@ std::vector<DisplayInfo> ScreenCapturerWayland::GetDisplayInfoList() {
|
||||
}
|
||||
|
||||
void ScreenCapturerWayland::Run() {
|
||||
if (!ConnectSessionBus() || !CreatePortalSession() || !SelectPortalSource() ||
|
||||
!StartPortalSession() || !OpenPipeWireRemote() ||
|
||||
!SetupPipeWireStream()) {
|
||||
static constexpr PipeWireRecoveryConfig kRecoveryConfigs[] = {
|
||||
{PipeWireConnectMode::kTargetObject, false},
|
||||
{PipeWireConnectMode::kAny, true},
|
||||
{PipeWireConnectMode::kNodeId, false},
|
||||
{PipeWireConnectMode::kNodeId, true},
|
||||
};
|
||||
|
||||
int recovery_index = 0;
|
||||
auto setup_pipewire = [this, &recovery_index]() -> bool {
|
||||
const auto& config = kRecoveryConfigs[recovery_index];
|
||||
return OpenPipeWireRemote() &&
|
||||
SetupPipeWireStream(config.relaxed_connect, config.mode);
|
||||
};
|
||||
auto setup_pipeline = [this, &setup_pipewire]() -> bool {
|
||||
return ConnectSessionBus() && CreatePortalSession() &&
|
||||
SelectPortalDevices() && SelectPortalSource() &&
|
||||
StartPortalSession() && setup_pipewire();
|
||||
};
|
||||
|
||||
if (!setup_pipeline()) {
|
||||
running_ = false;
|
||||
CleanupPipeWire();
|
||||
ClosePortalSession();
|
||||
CleanupDbus();
|
||||
return;
|
||||
}
|
||||
|
||||
while (running_) {
|
||||
if (!paused_) {
|
||||
const int64_t now = NowMs();
|
||||
const int64_t stream_start = pipewire_stream_start_ms_.load();
|
||||
const int64_t last_frame = pipewire_last_frame_ms_.load();
|
||||
const bool format_ready = pipewire_format_ready_.load();
|
||||
|
||||
const bool format_timeout =
|
||||
stream_start > 0 && !format_ready && (now - stream_start) > 1200;
|
||||
const bool first_frame_timeout =
|
||||
stream_start > 0 && format_ready && last_frame == 0 &&
|
||||
(now - stream_start) > 4000;
|
||||
const bool frame_stall = last_frame > 0 && (now - last_frame) > 5000;
|
||||
|
||||
if (format_timeout || first_frame_timeout || frame_stall) {
|
||||
if (recovery_index + 1 >=
|
||||
static_cast<int>(sizeof(kRecoveryConfigs) /
|
||||
sizeof(kRecoveryConfigs[0]))) {
|
||||
LOG_ERROR(
|
||||
"Wayland capture stalled and recovery limit reached, "
|
||||
"format_ready={}, stream_start={}, last_frame={}, attempts={}",
|
||||
format_ready, stream_start, last_frame, recovery_index);
|
||||
running_ = false;
|
||||
break;
|
||||
}
|
||||
|
||||
++recovery_index;
|
||||
const char* reason = format_timeout
|
||||
? "format-timeout"
|
||||
: (first_frame_timeout ? "first-frame-timeout"
|
||||
: "frame-stall");
|
||||
const auto& config = kRecoveryConfigs[recovery_index];
|
||||
LOG_WARN(
|
||||
"Wayland capture stalled ({}) - retrying PipeWire only, "
|
||||
"attempt {}/{}, mode={}, relaxed_connect={}",
|
||||
reason, recovery_index,
|
||||
static_cast<int>(sizeof(kRecoveryConfigs) /
|
||||
sizeof(kRecoveryConfigs[0])) -
|
||||
1,
|
||||
config.mode == PipeWireConnectMode::kTargetObject
|
||||
? "target-object"
|
||||
: (config.mode == PipeWireConnectMode::kNodeId ? "node-id"
|
||||
: "any"),
|
||||
config.relaxed_connect);
|
||||
|
||||
CleanupPipeWire();
|
||||
if (!setup_pipewire()) {
|
||||
LOG_ERROR("Wayland PipeWire-only recovery failed at attempt {}",
|
||||
recovery_index);
|
||||
running_ = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
CleanupPipeWire();
|
||||
if (!session_handle_.empty()) {
|
||||
std::this_thread::sleep_for(kPipeWireCloseSettleDelay);
|
||||
}
|
||||
ClosePortalSession();
|
||||
CleanupDbus();
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
} // namespace crossdesk
|
||||
|
||||
Reference in New Issue
Block a user