From a09a4235d3a7bca4a4a70c2a158e05d97520a1a7 Mon Sep 17 00:00:00 2001 From: dailz Date: Fri, 22 May 2026 11:42:42 +0800 Subject: [PATCH] fix(portal): replace blocking send with try_send in PW process callback PipeWire .process callback called frame_tx.send() on a bounded(3) channel. If the encoder stalled, this blocked the PipeWire data loop, delaying buffer recycling and potentially causing XRUNs. Replace with try_send + AtomicU64 drop counter. Frames are silently dropped when the channel is full (preferred for screen capture: latest frame wins). A warning is logged every 30 dropped frames. Fixes #2 from BUGS.md. --- src/cap_portal.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cap_portal.rs b/src/cap_portal.rs index bff3400..2e870c4 100644 --- a/src/cap_portal.rs +++ b/src/cap_portal.rs @@ -1,4 +1,5 @@ use std::os::fd::{AsRawFd, FromRawFd, OwnedFd}; +use std::sync::atomic::{AtomicU64, Ordering}; use std::thread::{self, JoinHandle}; use anyhow::Result; @@ -33,6 +34,7 @@ pub struct CapPortal { struct PwThreadCtx { frame_tx: Sender, + dropped: AtomicU64, shutdown_read: OwnedFd, pw_fd: OwnedFd, node_id: u32, @@ -69,6 +71,7 @@ impl CapPortal { let ctx = PwThreadCtx { frame_tx, + dropped: AtomicU64::new(0), shutdown_read: unsafe { OwnedFd::from_raw_fd(efd) }, pw_fd, node_id, @@ -178,6 +181,7 @@ fn pipewire_thread(ctx: PwThreadCtx) { let PwThreadCtx { frame_tx, + dropped, shutdown_read, pw_fd, node_id, @@ -269,6 +273,7 @@ fn pipewire_thread(ctx: PwThreadCtx) { .process({ let format_info = format_info.clone(); let frame_tx = frame_tx.clone(); + let dropped = dropped; move |stream, _| { let raw_buf = unsafe { stream.dequeue_raw_buffer() }; if raw_buf.is_null() { @@ -341,7 +346,14 @@ fn pipewire_thread(ctx: PwThreadCtx) { pts, }; - let _ = frame_tx.send(PwEvent::Frame(frame)); + if let Err(crossbeam_channel::TrySendError::Full(_)) = + frame_tx.try_send(PwEvent::Frame(frame)) + { + let prev = dropped.fetch_add(1, Ordering::Relaxed); + if prev > 0 && prev % 30 == 0 { + tracing::warn!("dropped {prev} frames total: encoder backlog"); + } + } unsafe { stream.queue_raw_buffer(raw_buf) }; } })