docs: M3 findings, test plan steps, README for build, signing and launch arguments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
Samuel Zielke 2 days ago
parent 27494fe1a1
commit 439e2505eb

@ -14,7 +14,7 @@ Erster Einsatz: OP-Liveübertragung (ATEM im OP, Regie im Saal, eine Netzwerklei
## Status
Planung abgeschlossen, Entwicklung startet mit Meilenstein 0. Siehe [docs/04-fahrplan.md](docs/04-fahrplan.md).
M0 abgenommen. M1 (Bild), M2 (Ton-Matrix) und M3 (Szenen und Fernsteuerung) umgesetzt, Langzeittests und Teile der Abnahmen offen. Siehe [docs/04-fahrplan.md](docs/04-fahrplan.md).
## Dokumente
@ -38,14 +38,32 @@ open Musubi.xcodeproj
```
Das `.xcodeproj` ist generiert und nicht im Repo. Nach Änderungen an `project.yml` erneut `xcodegen` ausführen.
Ohne NDI SDK in `Vendor/NDI/` bricht der Build mit einem Hinweis ab. Tests: im Schema `Musubi` (⌘U) oder `cd Packages/MusubiKit && swift test` – beides braucht das SDK, weil alle Module mitgebaut werden.
Signiert wird mit **Developer ID Application** (Team `XY4C2RG3L5`), Hardened Runtime an. Ohne dieses Zertifikat im Schlüsselbund `CODE_SIGN_IDENTITY`/`DEVELOPMENT_TEAM` in `project.yml` anpassen.
**Installieren immer nach `/Applications`** – in privaten Ordnern blockiert macOS Bonjour (Fernsteuerung).
### Startargumente (für Tests und Knoten ohne Bildschirm)
| Argument | Wirkung |
|---|---|
| `--route "<NDI-Name>=<Bildschirm-Index>"` | Quelle im Vollbild auf Bildschirm (0 = Hauptbildschirm) |
| `--audio-route "ndi:<NDI-Name>=<Gerät>:<Kanal>"` | NDI-Ton auf Ausgangskanal (Gerätename als Teilstring, Kanal ab 1) |
| `--audio-route "input:<Eingang>=<Gerät>:<Kanal>"` | Mikrofon (über die Sprechtaste) auf Ausgangskanal |
| `--load-scene "<Name>"` | gespeicherte Szene laden |
| `--login-item on\|off` | Beim Anmelden starten |
Rolle und Schnittstelle ohne Bildschirm: `defaults write studio.zielke.musubi role node` bzw. `interfaceName en7`.
Protokolle: Console.app, Subsystem `studio.zielke.musubi`. Minuten-Statistik: `~/Library/Logs/Musubi/stats-*.csv` (Bild), `audio-*.csv` (Ton).
Ohne NDI SDK in `Vendor/NDI/` bricht der Build mit einem Hinweis ab. Tests (Swift Testing, 44 Stück): im Schema `Musubi` (⌘U) oder `cd Packages/MusubiKit && swift test` – beides braucht das SDK, weil alle Module mitgebaut werden.
## Struktur
| Pfad | Inhalt |
|---|---|
| `App/` | App-Target: Einstieg, Hauptfenster, String Catalog |
| `Packages/MusubiKit/` | Module `MusubiCore`, `NDIKit` (+ `CNDI`-Modulemap), `VideoOutput`, `AudioMatrix`, `DesignSystem` |
| `App/` | App-Target: Einstieg, Koordinator (Rolle, Szenen, Live-Stand), Oberfläche, String Catalog |
| `Packages/MusubiKit/` | Module `MusubiCore`, `NDIKit` (+ `CNDI`-Modulemap), `VideoOutput`, `AudioMatrix` (+ `CAudioRing`), `Remote`, `DesignSystem` |
| `design/Theme.swift` | Design-Tokens; im Package als Symlink eingebunden |
| `project.yml` | XcodeGen-Projektdefinition |

@ -40,10 +40,11 @@ Jeder Meilenstein endet mit einem Abnahmetest. Erst wenn er bestanden ist, begin
- **Abnahme:** 4 Stunden ohne Knacksen und ohne hörbaren Versatz; Sprechtaste reagiert ohne Verzögerung.
## M3 – Szenen und Fernsteuerung
- [ ] Szenen speichern, laden, exportieren (JSON)
- [ ] Rolle Regie/Knoten; Knoten per Bonjour finden
- [ ] Regie setzt Szene am Knoten; Knoten meldet Status zurück
- [ ] Beim Start letzte Szene laden
- [x] Szenen speichern, laden, exportieren (JSON)
- [x] Rolle Regie/Knoten; Knoten per Bonjour finden
- [x] Regie setzt Szene am Knoten; Knoten meldet Status zurück
- [x] Beim Start letzte Szene laden
- **Stand 2026-10-21:** umgesetzt; Neustart Mac mini einzeln bestanden, Durchlauf in einem Stück und Neustart der Regie (MacBook) offen.
- **Abnahme:** Beide Macs neu starten – die Szene „OP-Live“ stellt sich ohne Eingriff wieder her.
## M4 – Intercom Stufe 1
@ -93,3 +94,14 @@ _(nach jedem Meilenstein ergänzen)_
- Drift-Regler langsam auslegen (Sekunden): der Füllstand ist durch die Blöcke ein Sägezahn. Im Betrieb ±150 ppm Korrektur, 0 Aussetzer in 2 min auf MOTU Out 2, CPU 0,3 %.
- 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.
### M3 – Szenen und Fernsteuerung (umgesetzt 2026-10-21, Abnahme teilweise)
- 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.
- Die Regie ist maßgeblich: Beim (Wieder-)Verbinden schickt sie ihre Soll-Belegung an den Knoten. Kennt sie den Knoten noch nicht, übernimmt sie dessen Stand.
- **Bonjour braucht die App in `/Applications`.** In privaten Ordnern (`~/Applications`, Build-Ordner) kann `mDNSResponder` die Info.plist nicht lesen und lehnt `NSBonjourServices` ab (`NoAuth -65555`). NDI ist nicht betroffen (eigenes Multicast).
- Direkt nach dem Start meldet macOS einige Sekunden „Local network prohibited“. Verbindungen brauchen daher Zeitgrenze + Wiederholung (6 s / 3 s).
- Signatur mit Developer ID + Hardened Runtime: Freigaben (lokales Netzwerk, Mikrofon) bleiben über Builds erhalten. Mikrofon braucht das Entitlement `com.apple.security.device.audio-input`.
- **Als Anmeldeobjekt startet macOS die App ohne Fenster.** Alles Wichtige startet deshalb in `applicationDidFinishLaunching`, nicht in einer SwiftUI-`.task`.
- Der Wechsel auf 50 Hz löst synchron „Bildschirme geändert“ aus. Ohne Schutz startete jede Ausgabe doppelt (zweites Fenster blieb nach „Beenden“ stehen). Ausgabe jetzt vor dem Moduswechsel eintragen, Abgleich nie verschachtelt.
- Offen: Beim ersten Neustart-Versuch hatte die Regie kurz vorher „keine Ausgaben“ für den Knoten gespeichert – Ursache nicht reproduzierbar (evtl. Klick auf „Ausgabe beenden“). Jede Änderung wird jetzt protokolliert (Kategorie `scene`).

@ -44,7 +44,11 @@ Sobald die bestellte Hardware da ist, wird der echte Aufbau zu Hause nachgestell
- [ ] M2: Sprechtaste (⌃⌥ Leertaste, gedrückt halten und umschalten) – Ton auf Out 1 ohne spürbare Verzögerung, Knopf rot nur während des Sprechens
- [ ] M2: MOTU während des Betriebs abziehen und wieder anstecken → Ton kommt von selbst zurück
- [ ] M2: PGM-Ton über M2 Out 2 → Ui12 Kanal 4; Talkback M2 Out 1 → Ui12 Kanal 3 (nur Aux 2)
- [ ] M3: Szene „OP-Live“ übersteht Neustart beider Macs
- [ ] 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“
- [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)
- [ ] 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
- [ ] M6: Tally auf dem Handy folgt dem Micro Panel

Loading…
Cancel
Save

Powered by TurnKey Linux.