dailz 46e7a9785d fix(webrtc): bypass str0m LeakyBucketPacer for low-latency LAN streaming
Final piece of the latency puzzle. Server-side frame_age was 6ms but browser
jitterBufferDelay still spiked to 500+ ms during active periods.

Root cause found via librarian investigation of str0m 0.20 source:

  str0m LeakyBucketPacer (active when BWE enabled) limits send rate to
  BWE_estimate * 1.1. For a 100KB IDR frame at 8Mbps pacing, the pacer
  queue adds ~100ms of send-side latency. Multiple frames stack during
  burst encode, causing receiver jitter buffer to grow.

  Video streams are PACED BY DEFAULT in str0m (audio is unpaced).
  Evidence: str0m/src/streams/send.rs:1116 default unpaced logic.

Fix: call stream_tx.set_unpaced(true) on the video stream when media
is added. BWE remains enabled for bitrate adaptation / TWCC feedback,
but the pacer no longer throttles our video egress.

Why this is the right call for wl-webrtc:

- LAN scenario: dedicated link, no competing flows to smooth against
- Encoder cap (8 Mbps) + VBV buffer (250ms) already provide rate control
- The pacer's smoothing benefit (avoid bursts that compete with TCP) is
  irrelevant for our use case
- BWE adaptation still works (we still receive EgressBitrateEstimate events
  and adapt encoder bitrate via BitrateCommand::UpdateBitrate)

Verification expectations:

- Active-period jitterBufferDelay: 500+ ms -> < 200 ms
- 'Stop mouse, client continues 10s' symptom: should disappear entirely
- Server-side frame_age: unchanged (~6ms)
- Bitrate/resolution adaptation: unchanged (still uses BWE)
- MP4 mode: unaffected (different code path)

Tests:
- cargo build --release: 0 new warnings (19 baseline preserved)
- cargo test: 96 lib + 3 integration, 0 failed
- SAFETY comments preserved verbatim
- 1 file changed, 7 insertions(+), 1 deletion(-)

Closes the latency investigation started in #23 / #24 / #25.
2026-06-21 09:10:28 +08:00
2026-06-13 22:46:41 +08:00

wl-webrtc

Wayland screen capture and encoding tool.

Prerequisites

  • Rust toolchain (1.70+): rustup default stable
  • FFmpeg 6.0+ dev libraries with VAAPI support:
    • Arch: pacman -S ffmpeg
    • Ubuntu/Debian: apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libva-dev
    • Fedora: dnf install ffmpeg-devel libva-devel
  • Wayland dev libraries:
    • Arch: pacman -S wayland-protocols
    • Ubuntu/Debian: apt install libwayland-dev wayland-protocols
    • Fedora: dnf install wayland-devel wayland-protocols-devel
  • DRM dev libraries:
    • Arch: pacman -S libdrm
    • Ubuntu/Debian: apt install libdrm-dev
    • Fedora: dnf install libdrm-devel

Build

cargo build --release

Run

# Basic capture to file
wl-webrtc --output output.mp4

# With custom FPS and bitrate
wl-webrtc --output output.mp4 --fps 60 --bitrate 8000000

# Specify DRM device for hardware encoding
wl-webrtc --output output.mp4 --drm-device /dev/dri/renderD128

# Verbose mode
wl-webrtc --output output.mp4 -v

CLI Arguments

Argument Default Description
-o, --output (required) Output file path (e.g., output.mp4)
--output-name auto Wayland output name to capture
--fps 30 Target frames per second
--codec h264 Video codec (h264 only for MVP)
--hw-accel vaapi Hardware acceleration method
--drm-device auto DRM render device path
--bitrate auto Target bitrate in bps
--gop-size auto Group of Pictures size
-v, --verbose false Enable verbose logging
--port 0 WebTransport server port (unused in MVP)
S
Description
No description provided
Readme
2.2 MiB
Languages
Rust 98.7%
Shell 1.2%