docs: M4 implemented, intercom ports, phone test steps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
Samuel Zielke 1 day ago
parent c61c543a65
commit e4e29aa5dd

@ -48,9 +48,10 @@ Jeder Meilenstein endet mit einem Abnahmetest. Erst wenn er bestanden ist, begin
- **Abnahme:** Beide Macs neu starten – die Szene „OP-Live“ stellt sich ohne Eingriff wieder her. - **Abnahme:** Beide Macs neu starten – die Szene „OP-Live“ stellt sich ohne Eingriff wieder her.
## M4 – Intercom Stufe 1 ## M4 – Intercom Stufe 1
- [ ] Web-Server nur auf der Klinik-Schnittstelle - [x] Web-Server nur auf der Klinik-Schnittstelle
- [ ] QR-Code mit Adresse in der App - [x] QR-Code mit Adresse in der App
- [ ] Handy-Seite: Name/Rolle, Talkback hören, PGM-Vorschau (WebRTC) - [x] Handy-Seite: Name/Rolle, Talkback hören, PGM-Vorschau (WebRTC)
- **Stand 2026-10-22:** umgesetzt, mit Chrome (headless) am Mac geprüft; Abnahme mit iPhone und Android offen.
- **Abnahme:** iPhone und Android im Heimnetz, Verzögerung der Vorschau gemessen < 0,5 s. - **Abnahme:** iPhone und Android im Heimnetz, Verzögerung der Vorschau gemessen < 0,5 s.
## M5 – Intercom Stufe 2 ## M5 – Intercom Stufe 2
@ -95,6 +96,15 @@ _(nach jedem Meilenstein ergänzen)_
- Entfernte Routen werden 2 s auf dem Main Thread geparkt, damit der Render-Thread nie den letzten Verweis loslässt (sonst `free` im Callback). - Entfernte Routen werden 2 s auf dem Main Thread geparkt, damit der Render-Thread nie den letzten Verweis loslässt (sonst `free` im Callback).
- Sprechtaste global per Carbon-Hotkey (⌃⌥ Leertaste) – braucht keine Bedienungshilfen-Freigabe und meldet Drücken und Loslassen. - Sprechtaste global per Carbon-Hotkey (⌃⌥ Leertaste) – braucht keine Bedienungshilfen-Freigabe und meldet Drücken und Loslassen.
### M4 – Intercom Stufe 1 (umgesetzt 2026-10-22, Abnahme offen)
- WebRTC ohne Drittanbieter (Entscheidung 2026-10-21): Musubi ist ICE-lite-Gegenstelle und DTLS-Server. Eigene, schmale Umsetzung auf CryptoKit/CommonCrypto: STUN (RFC 5389/8445), DTLS 1.2 mit genau einer Cipher-Suite (ECDHE-ECDSA-AES128-GCM-SHA256) + `use_srtp`, SRTP AES-CM-HMAC-SHA1-80. Network.framework/Security bieten kein DTLS-SRTP.
- Geprüft gegen RFC-Testvektoren (5769, 3711), OpenSSL (`s_client -dtls1_2 -use_srtp`, gleiche exportierte SRTP-Schlüssel, fremdes Zertifikat wird abgelehnt) und headless Chrome (Ende-zu-Ende: verbunden in ~12 ms, H.264 dekodiert, Opus empfangen). Opt-in-Test: `MUSUBI_E2E=1 swift test --filter BrowserEndToEnd`.
- Das Client-Zertifikat des Browsers wird gegen den Fingerprint aus dem SDP-Angebot geprüft; ohne Übereinstimmung kein Schlüssel.
- Signalisierung per HTTP-POST (Angebot rein, Antwort raus), keine Kandidaten vom Handy nötig: ICE-lite lernt die Adresse aus der ersten STUN-Prüfung (mDNS-Kandidaten der Browser stören nicht).
- Vorschau: NDI-Proxy-Stream (`bandwidth lowest`) → 960×540, 25 fps, H.264 Constrained Baseline, ~1,2 Mbit/s, Keyframe alle 2 s und auf PLI.
- Talkback: Abgriff am Headset-Mikro (`AudioMatrix.addInputTap`), Sprechtaste schaltet; sonst Stille, damit der Ton-Takt der Handys weiterläuft. Opus über AudioToolbox, 20 ms, 32 kbit/s.
- Ohne verbundenes Handy wird nichts kodiert.
### M3 – Szenen und Fernsteuerung (bestanden 2026-10-21) ### M3 – Szenen und Fernsteuerung (bestanden 2026-10-21)
- Szene = Konfiguration der Regie + Konfiguration je Knoten. Bildschirme werden über den **Namen** erkannt (Position nur bei gleichnamigen Monitoren), weil `CGDirectDisplayID` je Rechner/Neustart wechselt. - Szene = Konfiguration der Regie + Konfiguration je Knoten. Bildschirme werden über den **Namen** erkannt (Position nur bei gleichnamigen Monitoren), weil `CGDirectDisplayID` je Rechner/Neustart wechselt.
- Musubi speichert den Live-Stand laufend (`~/Library/Application Support/Musubi/live-state.json`) und stellt ihn beim Start wieder her – nicht die zuletzt gespeicherte Szene. Ausgaben für fehlende Bildschirme bleiben vorgemerkt und starten, sobald der Bildschirm erscheint. - Musubi speichert den Live-Stand laufend (`~/Library/Application Support/Musubi/live-state.json`) und stellt ihn beim Start wieder her – nicht die zuletzt gespeicherte Szene. Ausgaben für fehlende Bildschirme bleiben vorgemerkt und starten, sobald der Bildschirm erscheint.

@ -47,9 +47,17 @@ Sobald die bestellte Hardware da ist, wird der echte Aufbau zu Hause nachgestell
- [ ] M3 Vorbereitung Knoten (Mac mini): Musubi in `/Applications` (nicht `~/Applications`, sonst kein Bonjour), Rolle Knoten (`defaults write studio.zielke.musubi role node`), Technik-Schnittstelle (`defaults write studio.zielke.musubi interfaceName en7`), Autostart (`open /Applications/Musubi.app --args --login-item on`), automatische Anmeldung an, FileVault aus, „Nach Stromausfall neu starten“ an - [ ] M3 Vorbereitung Knoten (Mac mini): Musubi in `/Applications` (nicht `~/Applications`, sonst kein Bonjour), Rolle Knoten (`defaults write studio.zielke.musubi role node`), Technik-Schnittstelle (`defaults write studio.zielke.musubi interfaceName en7`), Autostart (`open /Applications/Musubi.app --args --login-item on`), automatische Anmeldung an, FileVault aus, „Nach Stromausfall neu starten“ an
- [ ] M3 Vorbereitung Regie (MacBook): Musubi in `/Applications`, Einstellungen (⌘,): Rolle Regie, Technik-Netz, „Beim Anmelden starten“ - [ ] M3 Vorbereitung Regie (MacBook): Musubi in `/Applications`, Einstellungen (⌘,): Rolle Regie, Technik-Netz, „Beim Anmelden starten“
- [x] M3: Mac mini neu starten → Musubi startet ohne Fenster, stellt beide Ausgaben wieder her, Regie verbindet sich (2026-10-21) - [x] M3: Mac mini neu starten → Musubi startet ohne Fenster, stellt beide Ausgaben wieder her, Regie verbindet sich (2026-10-21)
- [ ] M3: Szene „OP-Live“ übersteht Neustart beider Macs (Durchlauf in einem Stück; Regie = MacBook) - [x] M3: Szene „OP-Live“ übersteht Neustart beider Macs (Durchlauf in einem Stück; Regie = MacBook) (2026-10-21)
- [ ] M3: Netzwerkkabel zwischen den Macs 30 s ziehen → Knoten zeigt weiter, Regie verbindet sich danach von selbst - [ ] M3: Netzwerkkabel zwischen den Macs 30 s ziehen → Knoten zeigt weiter, Regie verbindet sich danach von selbst
- [ ] M4/M5: Handy über zweite Schnittstelle: Hören, Sprechen, Vorschau - [ ] M4 Vorbereitung (MacBook, Heimnetz): Einstellungen (⌘,) → Klinik-Netz = WLAN-Schnittstelle (z. B. `en0`). Zum Testen darf es dieselbe wie das Technik-Netz sein (Hinweis in Bernstein ist dann richtig). Ansicht „Intercom“: Vorschau = PGM-Quelle (OBS „pgm“ oder Test Patterns), Talkback = Headset-Mikro.
- [ ] M4: macOS-Firewall (falls an): Musubi eingehende Verbindungen erlauben. Ports: TCP 8080 (Seite), UDP 50000 (Ton/Bild).
- [ ] M4: iPhone (Safari) im selben WLAN: QR-Code scannen → Seite lädt, Name/Rolle eintragen, „Verbinden“ → Bild erscheint, Musubi listet das Handy unter „Verbunden“ mit grünem Punkt.
- [ ] M4: Android (Chrome) dasselbe, gleichzeitig mit dem iPhone verbunden.
- [ ] M4: Talkback: Sprechtaste (⌃⌥ Leertaste) halten und sprechen → beide Handys hören dich; loslassen → still. Falls iOS „Ton einschalten“ zeigt, einmal tippen.
- [ ] M4: Vorschau-Verzögerung messen: Uhr mit Millisekunden als NDI-Quelle (z. B. OBS-Browserquelle mit Uhr) als Vorschau wählen, Monitor mit der Quelle und Handy nebeneinander fotografieren; Differenz = Verzögerung: iPhone ___ ms, Android ___ ms (Ziel < 500 ms).
- [ ] M4: WLAN am Handy 10 s aus → Seite meldet „Neuer Versuch in 3 s“ und verbindet sich von selbst wieder; Musubi entfernt das alte Handy nach spätestens 30 s.
- [ ] M4: Handy-Display sperren und entsperren → Verbindung kommt zurück (sonst notieren, wie sich iOS/Android verhalten).
- [ ] M5: Handy über zweite Schnittstelle: Sprechen
- [ ] M6: Tally auf dem Handy folgt dem Micro Panel - [ ] M6: Tally auf dem Handy folgt dem Micro Panel
## Messwerte ## Messwerte

@ -25,6 +25,17 @@ Keine Internetfreigabe, kein Routing zwischen den Netzen. Musubi bindet jeden Di
Maske 255.255.255.0, kein Gateway. Maske 255.255.255.0, kein Gateway.
## Intercom: Ports und Bindung
Musubi bindet beide Dienste ausschließlich an die Klinik-Schnittstelle (Einstellungen → Klinik-Netz); über das Technik-Netz oder Loopback sind sie nicht erreichbar.
| Port | Protokoll | Zweck |
|---|---|---|
| 8080 | TCP (HTTP, ab M5 HTTPS) | Handy-Seite und Signalisierung (SDP-Angebot/-Antwort) |
| 50000 | UDP | WebRTC: ICE-lite, DTLS, SRTP (Talkback Opus, PGM-Vorschau H.264), alle Handys auf einem Port |
Für die Klinik-IT: Handys müssen den Mac auf diesen beiden Ports direkt erreichen (keine Client-Isolation im WLAN).
## Intercom: Reihenfolge der Wege ## Intercom: Reihenfolge der Wege
1. **Eigenes Netz der Klinik-IT** – lokal, schnellster Weg. Bevorzugt. 1. **Eigenes Netz der Klinik-IT** – lokal, schnellster Weg. Bevorzugt.

Loading…
Cancel
Save

Powered by TurnKey Linux.