From b3217b9dbb731ec69cd1ebde201aa2178143d961 Mon Sep 17 00:00:00 2001 From: Luke Hoersten Date: Mon, 15 Jun 2026 07:41:45 -0500 Subject: scrypted: don't reset idle timer on each painted frame + finer timing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes plus a README refresh: 1. scrypted: pushStreamFrame previously reset the per-stream idle timer on every successful /frame response. That made the timer anchored to "frames are flowing" rather than to "the camera event that triggered the stream", so a continuously-streaming source would never let the stream time out. Removed the reset. The startStream → stopStream(false) cancel-and-replace path on repeated events still keeps the stream alive while the event keeps firing; idle (no new events) now actually ends the stream at idle_timeout_ms. 2. firmware: break the previous coarse recv/dec/paint timing into lock : try_lock returned ttfb : first httpd_req_recv chunk landed body : remaining bytes received dec : hardware JPEG decode paint : esp_lcd_panel_draw_bitmap returned post : state-counter bookkeeping + unlock Logged every 10 frames at INFO. Splits the previously-fat recv bucket into TCP/HTTP handshake overhead (ttfb) vs wire-time (body), and surfaces any tail bookkeeping cost. 3. README: replace the stale "5 fps ceiling caused by CPU RGB conversion" guess with the actual measured per-phase budget and re-rank the backlog accordingly. Double-buffering the panel (paint 24 ms → ~2 ms) is now the highest-value next move; the previously-listed DMA-2D rewrite is moot because the CPU loop is already gone. --- scrypted/scrypted-viewport.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'scrypted/scrypted-viewport.ts') diff --git a/scrypted/scrypted-viewport.ts b/scrypted/scrypted-viewport.ts index d4bf8a5..1c90128 100644 --- a/scrypted/scrypted-viewport.ts +++ b/scrypted/scrypted-viewport.ts @@ -690,16 +690,13 @@ class ScryptedViewportProvider extends ScryptedDeviceBase this.console.warn(`"${v.name}" /frame -> 400: ${reason}`); } else if (!res.ok) { this.console.warn(`"${v.name}" /frame -> ${res.status}`); - } else { - // Frame painted; reset Scrypted-side idle timer alongside the - // device's own (each successful paint extends both). - const s = this.streams.get(v.name); - if (s) { - clearTimeout(s.timeout); - s.timeout = setTimeout(() => this.stopStream(v.name), - Math.max(5000, v.idleTimeoutMs)); - } } + // Do NOT reset the idle timer on successful paint. The timer is + // anchored to the triggering CAMERA EVENT, not to "frames are + // flowing" — otherwise a continuously-streaming source means the + // stream never times out. Repeated events naturally cancel-and- + // restart the stream via startStream → stopStream(false), which + // covers the "still active" case. } private findByName(name: string): Viewport | undefined { -- cgit v1.2.3