> # ⛔ ABGELÖST (2026-06-05) — dieser Ansatz war die Ursache des 106%-Bugs
>
> Der unten beschriebene **Consumer-Umhängen-Ansatz mit go2rtc** (`cam0` loslassen →
> go2rtc gibt Gerät frei → `cam0_hires` greifen) hat sich als **prinzipiell racy**
> erwiesen: go2rtcs API kann nicht zuverlässig melden, wann FFmpeg `/dev/videoN`
> freigibt → zwei Encoder auf einem Gerät → **106% CPU + Freeze** (siehe `09_Bug_reports.md`).
>
> **Aktuelle, maßgebliche Architektur:** **Node-MJPEG-Schalter, go2rtc entfernt.**
> Node besitzt die Kameras selbst; das `close`-Event des eigenen FFmpeg ist der harte
> Beweis „Gerät frei". Das Race ist damit konstruktiv ausgeschlossen.
>
> | | alt (unten, abgelöst) | **neu (maßgeblich)** |
> |-|----------------------|----------------------|
> | Geräte-Öffner | go2rtc | **Node** `src/cameraSwitch.js` |
> | Live | go2rtc-WS + `video-stream.js` | MJPEG multipart → `
` |
> | HD-Grab | 2. go2rtc-Stream `cam_hires` (Race) | Schalter: Live stoppen (`close`=FD frei) → 1280 → zurück |
> | Multi-User | brach | gelöst (ein FFmpeg → Fan-out) |
>
> **→ Neue Architektur + Hardware-Testplan stehen weiter unten in diesem Dokument
> (Abschnitt „## Node-MJPEG-Schalter").** Alles ab hier bis dorthin ist **Historie**.
---
# AppRobotWebcam – Hi-Res-Snapshot via Consumer-Umhängen ⛔ (historisch)
> 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.
---
## Grundidee
Das Kernproblem aller bisherigen Versuche: **Eine USB-Kamera lässt sich nur einmal
öffnen**, und der Live-Viewer zwingt go2rtc, das Gerät zu halten (per on-demand-
Reconnect). Jeder Versuch, go2rtc das Gerät zu *entreißen* oder die Live-Quelle zur
Laufzeit *umzuschalten*, ist gescheitert (device-busy, bzw. `PATCH` hängt an → 107 %).
**Neuer Ansatz – das Problem umdrehen:** Nicht das Gerät dem Stream entreißen, sondern
**die Zuschauer vom Live-Stream wegziehen.** Hat `cam0` keine Zuschauer mehr, stoppt
go2rtc den Producer von selbst (on-demand) und gibt das Gerät frei. Dann kann ein
separater Hi-Res-Stream es kurz für sich haben.
### Warum das sicher ist (im Gegensatz zu allem vorher)
- **`cam0` wird nie verändert.** Kein `PATCH`/`PUT`/`DELETE` auf den Live-Stream.
Das Append-Problem (107 %) kann nicht auftreten.
- **Zur Laufzeit nur LESENDE go2rtc-Aufrufe**: `GET /api/streams`, `GET /api/frame.jpeg`.
Die einzige „schreibende" Änderung ist das Hinzufügen von `cam0_hires` in der Config
(per Redeploy, nicht zur Laufzeit).
- **Kleiner Schadensradius**: Geht etwas schief, ist die Erholung „Browser wieder auf
`cam0` hängen" → go2rtc startet `cam0` neu. Keine kaputte Stream-Definition, die bis
zum Neustart hängt.
Damit respektiert der Ansatz die eisernen Regeln aus `04_*` (Snapshot-Pfad read-only,
keine Laufzeit-Mutation von cam0/cam1).
---
## Architektur
| Stream | Quelle | on-demand | Zweck |
|--------|--------|-----------|-------|
| `cam0` | Kamera @640 | ja | **unverändert** – Live-Stream |
| `cam1` | Kamera @640 | ja | **unverändert** – Live-Stream |
| `cam0_hires` | Kamera @1280×960 | ja | **nur** für den Hi-Res-Grab (Phase 2) |
| `cam1_hires` | Kamera @1280×960 | ja | dito für cam1 |
**Platzhalter = rein clientseitig**, kein go2rtc-Stream nötig:
Der Browser friert beim Umhängen den zuletzt gezeigten Live-Frame auf einem `