From c0d9deacd902715ada081d13581e7fd79894d4a2 Mon Sep 17 00:00:00 2001 From: chk <79915315+ChKendel@users.noreply.github.com> Date: Thu, 4 Jun 2026 21:25:50 +0200 Subject: [PATCH] Claude: Phase 2 seems to work --- doc/05_screenShot_roadmap.md | 37 +++++++++++++++++++++++++++++++----- src/snapshotService.js | 4 +++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/doc/05_screenShot_roadmap.md b/doc/05_screenShot_roadmap.md index d4362f6..6202090 100644 --- a/doc/05_screenShot_roadmap.md +++ b/doc/05_screenShot_roadmap.md @@ -1,9 +1,8 @@ # AppRobotWebcam – Hi-Res-Snapshot via Consumer-Umhängen -> Status: **Phase 1 abgeschlossen** (2026-06-04): -> **Linchpin beantwortet: `freed: true`.** go2rtc gibt das Gerät frei, sobald der letzte -> Consumer weg ist. Zwei Folgeprobleme blockieren Phase 2: Stream erholt sich nicht -> (bleibt schwarz), und go2rtc läuft nach dem Test auf 106 % (erfordert Container-Recreate). +> Status: **Phase 2 implementiert und funktional** (2026-06-04): +> HD-Grab liefert echten 1280×960-Frame (76071 bytes bestätigt). Bekanntes Problem +> behoben: `_hires`-Streams aus Kameraliste gefiltert. CPU ~35 % stabil. > Vorgeschichte & gescheiterte Ansätze: siehe `04_Delay_roadmap.md` (Abschnitt > „KONSOLIDIERT"). Diese Datei beschreibt den Ansatz, der die dort dokumentierten > Fehler **strukturell** umgeht. @@ -225,9 +224,37 @@ der zweite Consumer, der go2rtc in einen unklaren Zustand beim Reconnect trieb. --- +## Phase 2 — Ergebnis (2026-06-04) + +### ✅ Funktioniert +- HD-Grab pro Kamera via HD-Button: **76071 bytes, echter 1280×960-Frame** bestätigt +- Freeze-Canvas zeigt echten 640er-Frame (via `/api/snapshot/:id`, robust im MJPEG-Modus) +- Stream erholt sich nach Grab korrekt (Live zurück, ~35 % CPU stabil) +- Mutex verhindert parallele Grabs + +### 🐛 Bug gefunden + behoben: `_hires`-Filter +`/api/snapshot`-Liste enthielt alle go2rtc-Streams inkl. `cam0_hires`/`cam1_hires`. +Folge: Viewer baute Live-Boxen für Hires-Streams → go2rtc versuchte Geräte zu öffnen +→ „Resource busy" (cam0/cam1 hielten sie bereits). + +Fix in `snapshotService.js`: `.filter(id => !id.endsWith('_hires'))` auf die Kameraliste. +Danach: nur cam0/cam1 im Viewer, `_hires`-Streams bleiben dormant. ✓ + +### Offener Punkt: „Snapshot alle" mit HD +Aktuell: Button lädt 640er-Frames aller Kameras herunter. +Gewünscht: HD-Grabs für alle Kameras synchron auslösen. + +**Machbarkeit:** sicher und möglich. Cam0 und cam1 liegen auf getrennten Geräten +(`/dev/video0` ≠ `/dev/video2`) → parallele Grabs ohne Geräte-Konflikt. +Nötige Änderung: globalen `hiresLock` durch per-Kamera-Locks ersetzen (`{ cam0: false, cam1: false }`). +Blackout: beide Kameras ~8–10 s gleichzeitig (für Homing besser als versetzt). +**Noch nicht implementiert — wartet auf Entscheid.** + +--- + ## PHASE 2 — Den Hi-Res-Grab ergänzen (Schritt 4 + 5) -Phase 1 hat `freed: true` geliefert. **Phase 2 kann gestartet werden.** +Phase 1 hat `freed: true` geliefert. **Phase 2 implementiert (s.o.).** Realer Pausenwert aus der Messung: `zeroConsumerAt: 4850 ms` → Schritt 3/5 mit **5 s** planen (statt der geratenen 4 s). diff --git a/src/snapshotService.js b/src/snapshotService.js index 445fa20..dc80254 100644 --- a/src/snapshotService.js +++ b/src/snapshotService.js @@ -216,7 +216,9 @@ function createSnapshotRouter(go2rtcUrl) { if (!r.ok) throw new Error(`go2rtc HTTP ${r.status}`); const streams = await r.json(); res.json({ - cameras: Object.keys(streams).map(id => ({ id, url: `/api/snapshot/${id}` })), + cameras: Object.keys(streams) + .filter(id => !id.endsWith('_hires')) + .map(id => ({ id, url: `/api/snapshot/${id}` })), }); } catch (err) { res.status(503).json({ error: `go2rtc nicht erreichbar: ${err.message}` });