Skip to content

feat: debug page keeps the grid in single view, with short stream checks (#100) - #163

Merged
compot-dev merged 6 commits into
v2from
feat/debug-grid-probe
Oct 14, 2026
Merged

compot-dev merged 6 commits into
v2from
feat/debug-grid-probe

Conversation

@compot-dev

@compot-dev compot-dev commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #100 (option 2 with a short probe, agreed with the maintainer).

In single view (and the U view) the debug page, /snapshot.jpg and /stats.json show the whole grid (2×2 / 3×3 by the configured slots, the U view 3×3):

  • the camera on screen plays in its cell, framed in blue;
  • every other configured slot gets a short stream check about every 45 s while the page is in use: an ordinary RtspSession (or HTTP MJPEG request) without audio, ~3 s of packets counted (frames by marker bit, key frames, bitrate; size for MJPEG), then closed. No decoder is used. The cell shows e.g. Stream OK · H.265 · 25 fps · 3.1 Mbit/s · checked 12 s ago or the error (No answer from camera, Wrong login or password, PLAY OK but no video …), in green or red;
  • /stats.json gets slots (with on_screen and a probe object per cell); single and cells stay as they were.

Limits:

  • at most 2 checks at a time, one new one every 2 s, never two to one camera;
  • never the camera on screen: some cameras take one RTSP client only (XM). A check of a camera the TV is about to connect to is cancelled first;
  • udp:// slots and the U cell are not checked in single view (the port);
  • Auto is checked over TCP, UDP / multicast slots in their own mode;
  • checks stop in multi-view, on pause, and 60 s after the last request to the debug server.

New: StreamProbe (one check), StreamProbes (scheduling), StreamProbeTest. README EN/RU/ZH: one bullet in the debug page section.

Version 2.03 (versionCode 28).

…cks of the other slots (#100)

In single view (and the U view) the page, the snapshot and stats.json
(under 'slots') show the whole grid: the camera on screen framed, every
other configured slot checked about every 45 s while the page is in use
- an RTSP or HTTP MJPEG session without audio, ~3 s of packets counted
(frames, key frames, bitrate; size for MJPEG), then closed. No decoder.
At most two checks at a time, never two to one camera, never the camera
on screen (XM cameras take one client), no udp:// slots; checks stop
in multi-view, on pause, and 60 s after the last debug request.
@compot-dev
compot-dev force-pushed the feat/debug-grid-probe branch from e6f558c to e58286a Compare October 14, 2026 14:36
@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (1) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Debug builds fail before stream checks run 📎 Requirement gap ≡ Correctness
Description
StreamProbe.Counter declares firstFrameMs twice, so the Java compiler rejects the new probe
implementation. The application cannot build or execute the grid and stream-check behavior covered
by this change until the duplicate field is removed.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbe.java[R94-96]

+        long firstMs = -1;
+        long lastFrameMs = -1;
+        long firstFrameMs = -1;
Evidence
The changed probe source contains two declarations of the same firstFrameMs field, which is a Java
compile-time error and prevents the PR's grid/check functionality from running.

Show a frame or stream-check result in each cell
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[94-96]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`StreamProbe.Counter` declares `firstFrameMs` twice, which causes Java compilation to fail and prevents the debug grid stream checks from being shipped.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[94-96]
## Recommended Fix
Remove the duplicate `firstFrameMs` declaration and keep a single field initialized to `-1`, then run the Android build and probe unit tests.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. An empty selected slot disappears ✓ Resolved
Description
probeGridSize() chooses a 2×2 grid solely from configured URLs, without accounting for mActive.
If the user selects an unconfigured slot from 5 through 8 while only slots 1 through 4 are
configured, both the snapshot and slots stop at slot 4, so neither shows the selected slot or
marks any cell as on screen.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[1547]

+        return udpViewShown ? 3 : quadGridSize(mHosts, DEFAULT_URL);
Evidence
The menu permits selecting any camera slot, while grid sizing examines configured URLs only. Both
new grid builders iterate only over that computed size, and onScreen identifies the selected slot
by its index.

android/app/src/main/java/com/openipc/decoder/MenuManager.java[199-225]
android/app/src/main/java/com/openipc/decoder/Decoder.java[756-762]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1330-1357]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1545-1553]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1591-1599]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Selecting an unconfigured slot from 5 through 8 can leave the single-view debug grid at 2×2, omitting the slot on screen.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1545-1553]
## Recommended Fix
In single view, choose a 3×3 probe grid whenever the active slot is outside the first four, even if its URL is unconfigured. Keep the U-view grid behavior unchanged.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Wrong-password cameras get repeated failed logins ✓ Resolved
Description
StreamProbe.run treats onFailure as a note and keeps waiting the full 8 s CONNECT_WINDOW_MS,
while RtspSession.networkLoop reconnects after every failure with a 1 s → 2 s → 4 s back-off, so
one check can make about three login attempts. A slot with a wrong password (or a camera that is
down) therefore takes several failed authentications every 45 s for as long as the debug page is
open, which can trip the lockout many cameras apply after a few bad logins; each check also writes
up to three RTSP connection failed warnings to the 500-line log the page shows.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbe.java[R286-289]

+            @Override
+            public void onFailure(String message) {
+                failure[0] = message;
+            }
Evidence
The probe's onFailure only stores the message (StreamProbe.java 286-289), and waitFor polls only the
played latch until the 8 s window ends (317, 328-340). Meanwhile RtspSession.networkLoop catches
the failure, calls callback.onFailure, logs a warning for the first 3 failures, sleeps
retryDelay(retryMs) and loops again until stop(), doubling from minRetryMs=1000. A new RtspSession
is created for each probe, so the failure count and logging start over every 45 s.

android/app/src/main/java/com/openipc/decoder/RtspSession.java[218-252]
android/app/src/main/java/com/openipc/decoder/RtspSession.java[46-49]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[276-340]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A stream check keeps its RtspSession running for the whole 8 s connect window. RtspSession reconnects after every failure, so a slot with wrong credentials gets about three failed logins per check, every 45 s, and the log fills with warnings.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[276-340]
## Recommended Fix
In `StreamProbe.run`, add a second CountDownLatch (or reuse a shared one) that `onFailure` counts down before PLAY has been reached. Have `waitFor` return as soon as either latch fires, and treat a failure before PLAY as the end of the check: stop the session and build the error result from `failure[0]`. This way each check makes one connection attempt.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Changed camera settings show stale checks ✓ Resolved
Description
StreamProbes caches results by URL alone and retains each slot's last start time when its URL or
transport changes. After a transport change, the old result can appear as the new setting's result;
after either kind of change, a fresh check can wait for the remaining 45-second interval.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbes.java[R144-150]

+            urls = slotUrls.clone();
+            modes = slotModes.clone();
+            screenUrl = screen;
+            wanted = want;
+            lastUpdateMs = SystemClock.elapsedRealtime();
+            if (lastStartMs.length != urls.length) lastStartMs = new long[urls.length];
+            cancelStaleLocked();
Evidence
Decoder passes current settings to update(), but the scheduler keeps lastStartMs, cancellation
compares only URLs, and result lookup checks only URLs. next() then enforces the previous start
time against the new setting.

android/app/src/main/java/com/openipc/decoder/Decoder.java[1535-1543]
android/app/src/main/java/com/openipc/decoder/StreamProbes.java[77-89]
android/app/src/main/java/com/openipc/decoder/StreamProbes.java[142-150]
android/app/src/main/java/com/openipc/decoder/StreamProbes.java[174-196]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[275-278]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Results and scheduling intervals survive changes to the URL or transport that the check is meant to test.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbes.java[142-150]
- android/app/src/main/java/com/openipc/decoder/StreamProbes.java[174-177]
- android/app/src/main/java/com/openipc/decoder/StreamProbes.java[187-196]
## Recommended Fix
Track the URL and effective probe transport for each result and running probe. On either setting change, cancel the old probe, invalidate its result, and make the slot eligible for a new check.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View review recommended (4)
5. Single-view cells hide transport modes ✓ Resolved
Description
probeSlots() writes transport_mode but omits the transport field read by the page's where(c)
renderer. In single and U view, both the grid and the narrow-screen list consequently omit the
configured mode shown for existing multi-view cells.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R1585-1586]

+                c.put("url", u ? UDP_CELL_URL : DebugServer.redact(url));
+                if (!u) c.put("transport_mode", mTransports[i] != null ? mTransports[i].name() : null);
Evidence
The new slot maps contain transport_mode, whereas where(c) renders only transport; both
browser cell and row rendering call where(c). Existing multi-view maps populate both fields.

android/app/src/main/java/com/openipc/decoder/Decoder.java[1583-1587]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1489-1493]
android/app/src/main/java/com/openipc/decoder/DebugServer.java[494-496]
android/app/src/main/java/com/openipc/decoder/DebugServer.java[506-515]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new slot objects lack the transport field consumed by the browser page.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1583-1587]
- android/app/src/main/java/com/openipc/decoder/DebugServer.java[494-496]
## Recommended Fix
Populate each configured slot's `transport` label in the new slot schema, using the existing labeling convention for the on-screen session and a clear probe transport label for other slots.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Empty video packets can pass a check ✓ Resolved
Description
Counter.onPacket() counts a frame whenever the RTP marker bit is set, even if its validated header
leaves no video payload. A camera sending header-only marked packets can therefore produce an ok
result without sending a whole video frame.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbe.java[R115-116]

+            // The marker bit ends an access unit: one frame
+            if ((buf[offset + 1] & 0x80) != 0) frameEnd(nowMs);
Evidence
The packet path accepts end == header, increments counts, and calls frameEnd() on a marker bit.
A nonzero frame count is sufficient for result() to report success.

android/app/src/main/java/com/openipc/decoder/StreamProbe.java[95-116]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[213-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An RTP marker on a packet with no video payload counts as a complete frame.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[95-116]
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[218-222]
## Recommended Fix
Reject packets with no codec payload before incrementing packet or frame counts, and have the callback report unusable packets as such.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Invalid image parts pass stream checks ✓ Resolved
Description
Counter.onJpegFrame() counts every HTTP multipart part as a frame, whether or not JPEG parsing
finds a valid image. When an MJPEG endpoint returns nonempty but non-JPEG parts, the check reports
Stream OK rather than identifying that no usable video arrived.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbe.java[R122-125]

+            packets++;
+            bytes += length;
+            if (firstMs < 0) firstMs = nowMs;
+            if (width == 0) {
Evidence
HttpMjpeg.readParts() forwards any nonempty part; onJpegFrame() increments counts regardless of
JPEG size parsing, and the result is successful whenever a frame was counted.

android/app/src/main/java/com/openipc/decoder/HttpMjpeg.java[190-229]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[119-135]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[213-223]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Nonempty multipart parts count as JPEG frames without image validation.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[119-135]
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[218-223]
## Recommended Fix
Validate the JPEG framing of each received part before counting it as a frame or returning it as usable video; report no usable video if none pass.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. TV can collide with a check of its camera ✓ Resolved
Description
willShow and stopAll only set Probe.cancelled, leaving the probe’s RTSP session open until its
thread notices the flag during a polling loop and calls session.stop(). Because Decoder starts
single-camera or multi-view playback immediately after those calls, the probe can still occupy a
single-client camera when the TV tries to connect.
Code

android/app/src/main/java/com/openipc/decoder/StreamProbes.java[R159-164]

+    void willShow(String url) {
+        synchronized (lock) {
+            screenUrl = url;
+            cancelStaleLocked();
+        }
+    }
Evidence
cancelStaleLocked sets a volatile cancellation flag but does not stop the probe’s session.
StreamProbe.run checks that flag in polling loops, potentially up to 200 ms later, and stops the
session afterward; meanwhile, Decoder proceeds from willShow() to configuring and starting
playback, or from stopAll() to starting the multi-view cells.

android/app/src/main/java/com/openipc/decoder/StreamProbes.java[188-197]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[279-317]
android/app/src/main/java/com/openipc/decoder/Decoder.java[606-613]
android/app/src/main/java/com/openipc/decoder/RtspSession.java[183-196]
android/app/src/main/java/com/openipc/decoder/StreamProbes.java[158-171]
android/app/src/main/java/com/openipc/decoder/StreamProbes.java[187-196]
android/app/src/main/java/com/openipc/decoder/StreamProbe.java[275-315]
android/app/src/main/java/com/openipc/decoder/Decoder.java[609-613]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`StreamProbes.willShow` and `stopAll` return before a cancelled probe closes its RTSP session. Playback can therefore reach a single-client camera while the probe still occupies its connection.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbes.java[123-197]
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[236-290]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[609-613]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[692-696]
## Recommended Fix
Give each `Probe` a reference to its `RtspSession`, set in `StreamProbe.run` before `session.start()`. Have `cancelStaleLocked` call `session.stop()` directly when cancelling a probe, rather than relying on the next poll; the supplied findings state that this call is nonblocking and safe from another thread. Ensure both single-camera and multi-view handoffs start playback only after the matching probe sessions have closed, without blocking the UI thread.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

9. Each activity restart leaks a scheduler thread ✓ Resolved
Description
StreamProbes creates a ScheduledThreadPoolExecutor (and a worker pool) for each
Decoder.onCreate, and nothing ever shuts them down: onDestroy does not touch streamProbes.
Once the debug page has been used, the scheduler's core thread never times out, so each activity
recreation (shared link, uiMode/locale change, relaunch) leaves one more idle probe-sched thread
behind.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[182]

+        streamProbes = new StreamProbes(mUserAgent);
Evidence
The executors are created per instance in StreamProbes' field initializers. allowCoreThreadTimeOut
is set only on workers. Decoder.onDestroy only clears the debug source and shuts down audio.

android/app/src/main/java/com/openipc/decoder/StreamProbes.java[105-136]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2026-2030]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
StreamProbes' scheduler and worker executors are never shut down, so each Decoder instance leaks a thread.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbes.java[105-172]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2026-2030]
## Recommended Fix
Add a `shutdown()` method to StreamProbes that calls `stopAll()`, then `scheduler.shutdownNow()` and `workers.shutdown()`. Call it from `Decoder.onDestroy()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can switch off images and animations for a plain-text comment

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread android/app/src/main/java/com/openipc/decoder/StreamProbes.java
Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/StreamProbe.java
Comment thread android/app/src/main/java/com/openipc/decoder/StreamProbe.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/StreamProbes.java
Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java
…nd non-JPEG parts are no video, a cancel closes the check's socket at once, transport in slots, threads stopped with the activity
@compot-dev

Copy link
Copy Markdown
Collaborator Author

Qodo findings, all fixed in 4234ae4 (version bump stays last, eef7025):

  1. Stale checks after a setting change — results and running checks are keyed by URL + the transport the check uses (StreamProbe.key); a change drops the slot's result, cancels its check and makes it due at once.
  2. No transport in slots — transport added: in use for the camera on screen, otherwise check over TCP/UDP/multicast, HTTP, UDP listen, UDP push.
  3. Empty marked packets — a packet without payload is not counted and not reported usable.
  4. Non-JPEG parts — a part counts only if it starts with SOI and has a frame header or ends with EOI.
  5. Cancel vs. TV connect — a check's session is started through its cancel handle; cancel() stops the session synchronously (socket closed before willShow/stopAll return), and a check cancelled before start never starts.
  6. Thread leak — StreamProbes.shutdown() from onDestroy; the scheduler thread also times out when idle.

Tests added for 1, 3 and 4. /review

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Qodo findings, all fixed in 4234ae4 (version bump stays last, eef7025):

  1. Stale checks after a setting change — results and running checks are keyed by URL + the transport the check uses (StreamProbe.key); a change drops the slot's result, cancels its check and makes it due at once.
  2. No transport in slots — transport added: in use for the camera on screen, otherwise check over TCP/UDP/multicast, HTTP, UDP listen, UDP push.
  3. Empty marked packets — a packet without payload is not counted and not reported usable.
  4. Non-JPEG parts — a part counts only if it starts with SOI and has a frame header or ends with EOI.
  5. Cancel vs. TV connect — a check's session is started through its cancel handle; cancel() stops the session synchronously (socket closed before willShow/stopAll return), and a check cancelled before start never starts.
  6. Thread leak — StreamProbes.shutdown() from onDestroy; the scheduler thread also times out when idle.

Tests added for 1, 3 and 4. /review

I can’t rerun the Qodo review from this thread because the review action isn’t available here. The published report currently shows findings 1–6 resolved; you can push another commit or trigger /review where the review action is enabled, and I can explain any resulting finding.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

Comment on lines +94 to +96
long firstMs = -1;
long lastFrameMs = -1;
long firstFrameMs = -1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Debug builds fail before stream checks run 📎 Requirement gap ≡ Correctness

StreamProbe.Counter declares firstFrameMs twice, so the Java compiler rejects the new probe
implementation. The application cannot build or execute the grid and stream-check behavior covered
by this change until the duplicate field is removed.
Agent Prompt
## Issue description
`StreamProbe.Counter` declares `firstFrameMs` twice, which causes Java compilation to fail and prevents the debug grid stream checks from being shipped.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/StreamProbe.java[94-96]

## Recommended Fix
Remove the duplicate `firstFrameMs` declaration and keep a single field initialized to `-1`, then run the Android build and probe unit tests.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/StreamProbe.java
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit eef7025

@compot-dev
compot-dev force-pushed the feat/debug-grid-probe branch from eef7025 to 038cbdc Compare October 14, 2026 15:44
…ith a wrong password), the slot on screen beyond 4 gets the 3×3 grid
@compot-dev
compot-dev force-pushed the feat/debug-grid-probe branch from 038cbdc to 27e2372 Compare October 14, 2026 15:55
@compot-dev

Copy link
Copy Markdown
Collaborator Author

Qodo on 038cbdc:

  1. Duplicate firstFrameMs: not the case. StreamProbe.Counter declares it once (line 96), and CI compiles and tests 038cbdc.
  2. Empty selected slot beyond 4: fixed in ca58d89. The single-view debug grid is 3×3 whenever the slot on screen is 5–8.
  3. Repeated logins with a wrong password: fixed in ca58d89. A failure ends the check at once, so the session's own reconnect back-off never makes a second login attempt within one check.

Also 3edae3b: an empty slot shows grey, not red.

Checked on Aceline-1 (.144, 8 cameras incl. XM .53, single view on slot 4): all 7 other slots got Stream OK with codec / fps / bitrate, and the camera on screen kept playing (20 fps). The low fps of .247 / .248 (6.6 / 5.3) matches ffmpeg's frame timestamps from the same cameras at dusk.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Qodo on 038cbdc:

  1. Duplicate firstFrameMs: not the case. StreamProbe.Counter declares it once (line 96), and CI compiles and tests 038cbdc.
  2. Empty selected slot beyond 4: fixed in ca58d89. The single-view debug grid is 3×3 whenever the slot on screen is 5–8.
  3. Repeated logins with a wrong password: fixed in ca58d89. A failure ends the check at once, so the session's own reconnect back-off never makes a second login attempt within one check.

Also 3edae3b: an empty slot shows grey, not red.

Checked on Aceline-1 (.144, 8 cameras incl. XM .53, single view on slot 4): all 7 other slots got Stream OK with codec / fps / bitrate, and the camera on screen kept playing (20 fps). The low fps of .247 / .248 (6.6 / 5.3) matches ffmpeg's frame timestamps from the same cameras at dusk.

Thanks for the update. Based on your report:

  • finding 1 is addressed in 038cbdc.
  • finding 2 and finding 3 are addressed in ca58d89.
  • The grey empty-slot behavior was added in 3edae3b.
  • Your Aceline-1 validation confirms the intended stream-check behavior without disrupting the on-screen camera.

The published review is now stale relative to those commits; I can’t regenerate it from this thread, but no further action is indicated from the results you reported.

@compot-dev
compot-dev merged commit c2f7025 into v2 Oct 14, 2026
4 checks passed
@compot-dev
compot-dev deleted the feat/debug-grid-probe branch October 14, 2026 16:03
compot-dev added a commit that referenced this pull request Oct 15, 2026
…nd non-JPEG parts are no video, a cancel closes the check's socket at once, transport in slots, threads stopped with the activity
compot-dev added a commit that referenced this pull request Oct 15, 2026
…ith a wrong password), the slot on screen beyond 4 gets the 3×3 grid
compot-dev added a commit that referenced this pull request Oct 15, 2026
feat: debug page keeps the grid in single view, with short stream checks (#100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Debug page: always the full grid, also while the TV shows a single camera

1 participant