Repository navigation
fix(video): stop the once-a-second hitch and play frames without a jitter buffer - #78
Merged
Merged
Conversation
WebRTC buffers received video by default to smooth playback, which on a LAN only puts the host's cursor further behind the user's hand. Set jitterBufferTarget (standard) and playoutDelayHint (Chrome) to 0 on the video receiver; audio keeps its buffer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
…rames With no GOP configured the encoder emitted an IDR every second. At 4K a keyframe is ~350 KB and takes ~28 ms to send, so the 2-3 frames behind it arrive late: a hitch every second that makes the cursor feel like it lags and catches up. Measured on the T6 with a RTP-level client over 60 s of a static desktop: 1 s GOP gave frame-gap p99 46.3 ms and 23 gaps over 50 ms; 10 s GOP gave p99 16.6 ms and none. The dynamic GOP is now 10 s of frames. Viewers still get an IDR at once when they join or report loss (PLI/FIR), but PLI-driven keyframes are spaced at least 500 ms apart: a misbehaving client was able to make the encoder emit ~2,600 IDRs a minute. Resuming encoding for a viewer bypasses the limit, since it needs an IDR to start decoding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
9 of 10 tasks
Rust-KVM
marked this pull request as ready for review
October 20, 2026 14:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by 4c · project thread
Summary
Before: on a LAN the remote cursor didn't keep up with the hand and the picture drifted and caught up in jumps. The encoder sent a 4K IDR (~350 KB, ~28 ms on the wire) every second, so the next 2-3 frames arrived late each second, and the browser's jitter buffer grew to absorb the bursts.
After: periodic IDRs come every 10 s, viewers still get one immediately on join or loss, and the browser plays video frames as soon as they decode.
Measured on the T6 (4K60 H.264, static desktop, 60 s, RTP-level client on the LAN, no input sent):
How
pipeline.rs: the dynamic GOP isfps × GOP_SECONDS(10). PLI/FIR-driven keyframes are spaced at least 500 ms apart (KEYFRAME_MIN_INTERVAL); a misbehaving client produced ~2,600 IDRs a minute before. Resuming encoding for a viewer usesforce_keyframe_now, so the limit can never leave a new viewer waiting a whole GOP.net/peer.rs:play_out_immediatelysetsjitterBufferTarget = 0and Chrome'splayoutDelayHint = 0on the video receiver only (audio keeps its buffer), viaReflect, so browsers without them ignore it.Remaining: with motion a 4K IDR reaches ~1.5 MB and arrives in ~128 ms, so there is still one hitch per 10 s. The send path delivers only ~95 Mbps on a gigabit LAN; that is the next fix.
Testing
cargo +nightly fmt --allcargo +nightly clippy -p rustkvm --release --all-targets -- -D warnings, and rkvm-web clippy for wasm32cargo +nightly test -p rustkvmRUSTKVM_VIDEO_GOP=600(table above)Checklist
#[allow(...)]suppressions and no newunwrap()/expect()in production pathsrkvm-proto🤖 Generated with Claude Code
https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF