fix(screenshare): keep low-latency playback live

This commit is contained in:
2026-07-18 22:22:24 -04:00
parent 26d66007de
commit 4bfc18463b
2 changed files with 21 additions and 8 deletions
+7
View File
@@ -4,6 +4,13 @@ All notable changes to PeerSpeak are documented here.
## [Unreleased] ## [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 710 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 ## [0.6.4] — 2026-07-18
### Added ### Added
+14 -8
View File
@@ -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 /// player is reaped in a background task so it doesn't linger as a zombie when
/// its window closes. /// its window closes.
/// ///
/// The flags keep latency low while preserving A/V sync. We deliberately do /// The buffering posture chooses the latency/A/V-sync tradeoff. Low latency
/// NOT pass mpv's `--untimed`: that displays each video frame the instant it /// passes mpv's `--untimed`, displaying frames as soon as they decode so a live
/// decodes, ignoring audio timestamps, which makes a shared *video* drift /// share cannot accumulate several seconds in the reliable QUIC/TCP/player
/// progressively out of sync with its audio. Pacing to the audio clock costs a /// buffer chain. Smooth leaves timestamp pacing enabled, which keeps a shared
/// little latency (negligible for pointing at a desktop) and keeps a shared /// video's audio and video synchronized at the cost of extra live latency.
/// video in sync. We also leave hwdec at the `low-latency` default (software /// Hardware decoding remains opt-in: forcing `--hwdec=auto` froze some viewers
/// decode): forcing `--hwdec=auto` froze some viewers on frame 1 while audio /// on frame 1 while audio kept playing.
/// kept playing.
fn launch_player(url: &str, settings: &ScreenShareSettings) -> std::io::Result<()> { fn launch_player(url: &str, settings: &ScreenShareSettings) -> std::io::Result<()> {
let mpv_args = mpv_args(settings); let mpv_args = mpv_args(settings);
let vlc_args = vlc_args(settings); let vlc_args = vlc_args(settings);
@@ -648,6 +647,12 @@ pub fn mpv_args(settings: &ScreenShareSettings) -> Vec<String> {
match settings.buffering { match settings.buffering {
ShareBuffering::LowLatency => { ShareBuffering::LowLatency => {
args.push("--profile=low-latency".to_string()); 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("--audio-buffer=0.2".to_string());
args.push("--demuxer-readahead-secs=0.5".to_string()); args.push("--demuxer-readahead-secs=0.5".to_string());
} }
@@ -828,6 +833,7 @@ mod tests {
mpv_args(&ScreenShareSettings::default()), mpv_args(&ScreenShareSettings::default()),
vec![ vec![
"--profile=low-latency", "--profile=low-latency",
"--untimed",
"--audio-buffer=0.2", "--audio-buffer=0.2",
"--demuxer-readahead-secs=0.5", "--demuxer-readahead-secs=0.5",
"--demuxer-max-bytes=2M", "--demuxer-max-bytes=2M",