Repository navigation
fix(video): replug HDMI in software when the receiver is stuck relocking - #77
Merged
Merged
Conversation
v4l2src negotiates the capture format once. When the HDMI source re-locks with different timings or a different colour format (host display sleep, GPU retrain, re-plug), the receiver starts writing a new frame layout while the pipeline keeps the old caps, so the encoder reads the planes wrong and viewers get green and magenta stripes with no error on the bus. The supervisor only restarted pipelines that had died, so this never healed. The supervisor now also: - polls the capture node (VIDIOC_G_FMT + VIDIOC_QUERY_DV_TIMINGS, read-only, one fd kept open) every 2s and rebuilds the pipeline when the format or timings differ from the start-of-pipeline baseline on two polls in a row; signal loss alone is not a change; - rebuilds at once when a capture buffer's size differs from the first one; - rebuilds when no raw frame arrives for 10s while a signal is present, backing off on repeats. Each rebuild logs the old and new source, and the negotiated capture caps are logged once per pipeline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
On hardware the receiver reports 593.95 and 593.96 MHz alternately on a steady 4K60 signal, so the source watch rebuilt the pipeline every 30 seconds. Compare only the frame layout and video mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
Hardware showed the real failure behind the striped picture: after the host woke from a 15-hour sleep, the rockchip_hdmirx receiver looped once a second. Every lock ends in hdmirx_format_change, which queues a source-change event even when the mode is unchanged; v4l2src restarts the stream on each event, and the restart relocks and queues the next one. Frames are cut mid-DMA, and only a physical replug ended it. Format and timings never changed, so the source-change rebuild from the previous commits never fired, and on hardware it misfired on pixel-clock jitter. Replace it with what actually recovers the input: - subscribe to V4L2 source-change events on a monitoring fd, counted on a small thread (the kernel keeps only the newest pending event); - 6+ events within 10 s is a relock storm: pulse hot-plug detect through /sys/class/hdmirx/hdmirx/status (off, 2 s, on) so the source renegotiates, backing off 30 s, 60 s, ... while the storm persists; - drop the format/timing comparison and the buffer-size check; keep the stall rebuild and the negotiated-caps log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
…stall Device logs from a host sleep/wake showed the HID writer timing out on the absolute mouse while the host stopped polling, then the host re-enumerating USB. Two things made input feel laggy and drifting around that: - While the host polls slowly, every queued pointer move was replayed one by one, so the cursor trailed seconds behind and then raced. The writer now takes everything queued at once and keeps only the last position of consecutive absolute moves (button changes and wheel steps keep their place, so presses and releases land where they happened), and sums consecutive relative moves. - A timeout on one device dropped every queued report, key-ups included, which can leave a key held on the host. Dropped reports now leave behind the latest keyboard and pointer state, which is resent (every 500 ms until the host reads again) unless newer input supersedes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
… a host stall" This reverts commit e7e1916. On hardware the mouse stuttered with it deployed and was smooth again after rolling the device back to f92cfc0, so the change goes until the cause is understood. The HDMI relock fix stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF
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: after the controlled host slept for about 15 hours and woke up, the remote desktop showed green and magenta horizontal stripes. Reconnecting and restarting the app did not help; only physically unplugging and replugging HDMI fixed it.
After: the app spots the broken state within about 6 seconds and does the replug itself, by dropping HDMI hot-plug detect for 2 seconds and raising it again. If it keeps happening it retries with backoff (30 s, 60 s, … up to 10 min) and logs each attempt.
What hardware showed (dmesg on the T6, kernel 6.1.99, rockchip_hdmirx): the receiver was in a once-a-second loop. Each lock ends in
hdmirx_format_change, which queues a V4L2 source-change event even when the mode is unchanged (New format: 3840x2160p59.99every time). v4l2src restarts the stream on each event (hdmirx_stop_streaming wait last irq timeout, return bufs!), and the restart relocks and queues the next event. Frames get cut mid-DMA. Format, stride and timings never changed. After a physical replug the lock took longer (i:117), the loop stopped and capture has been stable since.How
hardware/v4l2.rs: a monitoring fd on the capture node subscribes toV4L2_EVENT_SOURCE_CHANGE. A small thread drains events every 200 ms, because the kernel keeps only the newest pending one.RelockWatchcalls 6+ events within 10 s a storm. A healthy input reports none; a mode change or a replug reports a few.pulse_hotplugwritesoffthenonto/sys/class/hdmirx/hdmirx/status(driverstatus_store→hdmirx_hpd_ctrl) and retriesonso HPD is never left low.video.rs: the supervisor acts on the storm verdict, and still rebuilds the pipeline when it dies or capture stalls with a signal present. It logs the negotiated capture caps once per pipeline.Follow-up outside this repo: the driver should only queue the source-change event when timings actually change. That belongs on the local buildroot kernel branch.
Testing
cargo +nightly fmt --allcargo +nightly clippy --workspace --release --all-targets -- -D warningscargo +nightly test --workspace(app/tests/capture_source.rs: storm detection, backoff, reset, ioctl parsing)Checklist
#[allow(...)]suppressions and no newunwrap()/expect()in production pathsMissedTickBehavior::Delayrkvm-protoAGENTS.mdupdated🤖 Generated with Claude Code
https://claude.ai/code/session_01GRSn3XsjYLc494XwPez2mF