From 4bfc18463bc582647a7d80b5abe0255ec92051e5 Mon Sep 17 00:00:00 2001 From: Mollusk Date: Sat, 18 Jul 2026 22:22:24 -0400 Subject: [PATCH] fix(screenshare): keep low-latency playback live --- CHANGELOG.md | 7 +++++++ src/screenshare/mod.rs | 22 ++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 338a320..fd2ad40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to PeerSpeak are documented here. ## [Unreleased] +### Fixed +- **Low-latency screen sharing stays near the live edge again.** mpv's + timestamp pacing could let stale frames accumulate across the reliable + PixelPass transport until a share was 7–10 seconds behind. Low-latency mode + now presents decoded frames immediately; Smooth mode retains timestamp pacing + when keeping shared-video audio and video synchronized matters more. + ## [0.6.4] — 2026-07-18 ### Added diff --git a/src/screenshare/mod.rs b/src/screenshare/mod.rs index 04a890c..3788e2d 100644 --- a/src/screenshare/mod.rs +++ b/src/screenshare/mod.rs @@ -607,14 +607,13 @@ fn event_for_log(ev: &PixelpassEvent) -> String { /// player is reaped in a background task so it doesn't linger as a zombie when /// its window closes. /// -/// The flags keep latency low while preserving A/V sync. We deliberately do -/// NOT pass mpv's `--untimed`: that displays each video frame the instant it -/// decodes, ignoring audio timestamps, which makes a shared *video* drift -/// progressively out of sync with its audio. Pacing to the audio clock costs a -/// little latency (negligible for pointing at a desktop) and keeps a shared -/// video in sync. We also leave hwdec at the `low-latency` default (software -/// decode): forcing `--hwdec=auto` froze some viewers on frame 1 while audio -/// kept playing. +/// The buffering posture chooses the latency/A/V-sync tradeoff. Low latency +/// passes mpv's `--untimed`, displaying frames as soon as they decode so a live +/// share cannot accumulate several seconds in the reliable QUIC/TCP/player +/// buffer chain. Smooth leaves timestamp pacing enabled, which keeps a shared +/// video's audio and video synchronized at the cost of extra live latency. +/// Hardware decoding remains opt-in: forcing `--hwdec=auto` froze some viewers +/// on frame 1 while audio kept playing. fn launch_player(url: &str, settings: &ScreenShareSettings) -> std::io::Result<()> { let mpv_args = mpv_args(settings); let vlc_args = vlc_args(settings); @@ -648,6 +647,12 @@ pub fn mpv_args(settings: &ScreenShareSettings) -> Vec { match settings.buffering { ShareBuffering::LowLatency => { args.push("--profile=low-latency".to_string()); + // Pixelpass carries MPEG-TS through reliable ordered QUIC/TCP. If + // mpv paces a live stream even slightly slower than capture, those + // downstream buffers retain stale frames and latency grows into + // seconds. Immediate presentation keeps this posture at the live + // edge; Smooth deliberately retains timestamp pacing for A/V sync. + args.push("--untimed".to_string()); args.push("--audio-buffer=0.2".to_string()); args.push("--demuxer-readahead-secs=0.5".to_string()); } @@ -828,6 +833,7 @@ mod tests { mpv_args(&ScreenShareSettings::default()), vec![ "--profile=low-latency", + "--untimed", "--audio-buffer=0.2", "--demuxer-readahead-secs=0.5", "--demuxer-max-bytes=2M",