141 lines
5.7 KiB
Markdown
141 lines
5.7 KiB
Markdown
# AppRobotWebcam – Roadmap
|
||
|
||
## Ziel
|
||
|
||
Sauberer, fokussierter Webcam-Service als Docker-Container. Kein Robot-Control, kein
|
||
ArUco – nur zwei Verantwortlichkeiten:
|
||
|
||
1. **Live-Video** mit minimaler Latenz (WebRTC via go2rtc)
|
||
2. **Standbilder** auf Abruf via HTTP REST (`/api/snapshot/cam{n}`)
|
||
|
||
Das Homing-Projekt holt seine Standbilder über den Snapshot-Endpunkt – keine weitere Kopplung.
|
||
|
||
---
|
||
|
||
## Architektur (final)
|
||
|
||
```
|
||
USB Kameras
|
||
│
|
||
▼
|
||
go2rtc (Capture · H.264-Encode · WebRTC) ── intern, Port 1984 + UDP 8555
|
||
│
|
||
▼
|
||
Node.js / Express ── öffentlich, Port 8444
|
||
├── / eigener Viewer (go2rtc <video-stream>-Component)
|
||
├── /api/ws WebRTC-Signaling → proxied zu go2rtc
|
||
├── /api/snapshot/* Standbilder → proxied zu go2rtc /api/frame.jpeg
|
||
└── /health
|
||
```
|
||
|
||
**Warum go2rtc statt eigenem FFmpeg-Stream:**
|
||
Erste Version (eigener Node-FFmpeg-MJPEG-Stream über WebSocket) hatte spürbare Latenz.
|
||
go2rtc ist ein spezialisierter Streaming-Server: WebRTC mit ~50–150 ms, automatisches
|
||
Encoding, ICE-Negotiation, robuster Client mit Auto-Fallback (WebRTC→MSE→MJPEG).
|
||
|
||
**Warum Node davor (statt go2rtc direkt):**
|
||
- Ein einziger öffentlicher Port (8444); go2rtc-Admin bleibt unerreichbar
|
||
- Stabile Snapshot-Schnittstelle, entkoppelt von go2rtc-Interna
|
||
- Eigener, schlanker Viewer
|
||
|
||
**Stack-Entscheide:**
|
||
|
||
| Komponente | Wahl | Begründung |
|
||
|------------|------|------------|
|
||
| Streaming | go2rtc | WebRTC out-of-the-box, niedrige Latenz, internet-tauglich |
|
||
| Webserver | Node.js + Express | wartbar, user-präferiert |
|
||
| Proxy | http-proxy-middleware | reicht HTTP + WebSocket transparent durch |
|
||
| Live-Protokoll | WebRTC (Fallback MSE/MJPEG) | niedrigste Latenz, skaliert über Internet |
|
||
| Snapshot-API | HTTP GET → JPEG | einfachste Schnittstelle für Consumer |
|
||
| Container | docker-compose, `configs` inline | kein Dockerfile-File, Portainer-tauglich |
|
||
|
||
---
|
||
|
||
## Tasks
|
||
|
||
### Phase 1 – Grundgerüst ✅
|
||
- [x] Projektstruktur, package.json, docker-compose mit inline-Config
|
||
- [x] Erste Version (Node-FFmpeg-MJPEG über WebSocket) – verworfen wegen Latenz
|
||
|
||
### Phase 2 – Umstieg auf go2rtc / WebRTC ✅
|
||
- [x] go2rtc als Streaming-Backend (Kamera-Capture + WebRTC)
|
||
- [x] go2rtc-Config in docker-compose eingebettet (`configs.content`)
|
||
- [x] Node als Reverse-Proxy (`/api/ws`, `/api/frame.jpeg`, Player-Scripts)
|
||
- [x] Eigener Viewer mit go2rtc `<video-stream>`-Component (Auto-Fallback)
|
||
- [x] Stabile Snapshot-API `/api/snapshot/cam{n}`
|
||
- [x] Auflösung fest 640×480 → Latenz „akzeptabel" (war vorher das Hauptproblem)
|
||
|
||
### Phase 3 – Latenz final tunen (offen)
|
||
- [ ] Messvergleich WebRTC ⟷ MJPEG durchführen → siehe `03_Protocoll_roadmap.md`
|
||
- [ ] Falls nötig: Auflösung 320×240 testen (kleiner = weniger Browser-Last)
|
||
- [ ] Falls nötig: Keyframe-Intervall senken (`-g 15`), zerolatency-Tuning
|
||
- [ ] Prüfen ob Kamera natives H.264 liefert (`v4l2-ctl --list-formats`) → kein Re-Encode
|
||
|
||
### Phase 4 – Internet-Härtung (offen, vor Produktiv-Schaltung)
|
||
- [ ] **TLS via Caddy** – empfohlen, weil Caddy WebSocket-Proxy nativ und zuverlässig kann.
|
||
Aktuell verbindet Browser `/api/ws` direkt zu go2rtc Port 1984.
|
||
Caddy bündelt beides hinter einer Domain:
|
||
```
|
||
robot.example.com {
|
||
handle /api/ws* { reverse_proxy localhost:1984 }
|
||
handle /api/stream* { reverse_proxy localhost:1984 }
|
||
handle /video-*.js { reverse_proxy localhost:1984 }
|
||
handle { reverse_proxy localhost:8444 }
|
||
}
|
||
```
|
||
Danach: viewer.js `go2rtcPort` auf 443 (wss://) setzen, Node GO2RTC_PORT=443.
|
||
- [ ] **WebRTC-Candidate**: `stun:8555` testen; bei NAT-Problemen → feste IP/Domain:
|
||
`candidates: [robot.example.com:8555]` in go2rtc-Config
|
||
- [ ] **TURN**: nur wenn STUN + UDP 8555 nicht reicht (sehr restriktive NATs)
|
||
- [ ] **Zugriffsschutz**: Basic-Auth am Caddy (1–3 bekannte User)
|
||
- [ ] **Firewall**: TCP 443 (Caddy) + UDP 8555 (WebRTC) forwarden; 1984 + 8444 intern
|
||
|
||
### Phase 5 – Robustheit (optional)
|
||
- [ ] Kamera hot-plug: go2rtc-Verhalten bei Device-Verlust prüfen
|
||
- [ ] Resource Limits dokumentieren (`mem_limit`, `cpus`)
|
||
- [ ] JSON-Logging
|
||
- [ ] Snapshot-Metadaten / optionaler Webhook nach Snapshot
|
||
|
||
---
|
||
|
||
## Abgrenzung zu appRobotVideoControls
|
||
|
||
| Feature | appRobotVideoControls | appRobotWebcam |
|
||
|---------|-----------------------|----------------|
|
||
| Video-Streaming | eigener FFmpeg-MJPEG/WS | go2rtc / WebRTC |
|
||
| Snapshots | komplex (dual-pipe) | HTTP REST, einfach |
|
||
| Robot-Control (G-Code) | ✅ | ❌ anderes Projekt |
|
||
| ArUco / Homing | ✅ | ❌ anderes Projekt |
|
||
| Separates Dockerfile | ✅ (OpenCV-Build) | ❌ (inline in compose) |
|
||
|
||
---
|
||
|
||
## Ports
|
||
|
||
| Dienst | Port | Exponiert? |
|
||
|--------|------|-----------|
|
||
| Node Viewer + API + Signaling | TCP 8444 | ja (Firewall) |
|
||
| WebRTC Media | UDP 8555 | ja (Firewall) |
|
||
| go2rtc HTTP/Debug-UI | TCP 1984 | nein (nur intern/LAN) |
|
||
|
||
---
|
||
|
||
## Datei-Struktur
|
||
|
||
```
|
||
appRobotWebcam/
|
||
├── src/
|
||
│ └── snapshotService.js Snapshot-Router (proxied go2rtc /api/frame.jpeg)
|
||
├── public/
|
||
│ ├── index.html Viewer (lädt go2rtc <video-stream>)
|
||
│ └── viewer.js baut Kamera-Views, Auto-Fallback WebRTC→MSE→MJPEG
|
||
├── doc/
|
||
│ ├── 01_WebcamRoadmap.md (diese Datei)
|
||
│ ├── 03_Protocoll_roadmap.md WebRTC⟷MJPEG-Vergleich (nachzuholen)
|
||
│ └── 05_OptionalToDo_roadmap.md Control-Integration (Optionen)
|
||
├── docker-compose.yaml einzige Deploy-Datei (go2rtc-Config eingebettet)
|
||
├── go2rtc.yaml nur Referenz/lokal (Config ist in compose eingebettet)
|
||
├── package.json
|
||
└── server.js Node-Einstiegspunkt
|
||
```
|