Files
threadnet-call/docs/axion1337-fork.md
T

134 lines
7.7 KiB
Markdown
Raw Normal View History

# threadnet-call: Fork-Anpassungen für axion1337.chat
Dieses Dokument beschreibt alles, was dieser Fork gegenüber Upstream Element Call ändert. Die
übrigen Dateien in `docs/` sind unverändertes Upstream-Material.
## 1. Warum Fork von `emmick4/element-call` (Branch `livekit`)?
Nicht direkt von `element-hq/element-call` geforkt, sondern von `emmick4/element-call`s
`livekit`-Branch, weil dieser bereits den noch nicht upstream gemergten PR
[element-hq/element-call#3736](https://github.com/element-hq/element-call/pull/3736)
enthält - config-driven `media_quality`. Ohne diesen PR wäre eigener Custom-Code nötig gewesen,
um Video-/Audio-Qualitätslimits pro Deployment konfigurierbar zu machen.
## 2. media_quality-Defaults
Konfiguriert in `vite-embedded.config.ts` (im `generateFile`-Plugin-Aufruf, der
`media_quality` in die zur Build-Zeit gebackene `config.json` des Embedded-Packages schreibt):
- Kamera: **1440p / 60fps / ~8 Mbps** (`video.max_resolution/max_framerate/max_bitrate`)
- Screen-Share: **1440p / 30fps / ~6 Mbps**
- 720p-Zwischen-Simulcast-Layer (`video.simulcast_layers`) - ohne diesen fiel die Übertragung
bei kleinsten Netzwerkschwankungen direkt von 1440p auf blockiges 360p
- `video_codec: "h264"` (siehe Incident unten für die Begründung)
Das sind Startwerte, keine harten Limits - Nutzer können in den Call-Settings weiter hochdrehen.
## 3. VP9-Incident (2026-07-28) — ⚠️ nicht ohne Browser-Repro erneut versuchen
Erster Versuch setzte `video_codec: "vp9"` (Commit `83db5224`). Das hat Calls **live komplett
kaputt gemacht** (kein Bild/Ton), obwohl die LiveKit-SFU-Server-Logs den
Codec-Regression-Fallback auf VP8 als scheinbar erfolgreich zeigten. Sofort zurückgerollt
(Commit `f845d81e`). Vermutete Ursache: LiveKit nutzt für VP9/AV1 SVC statt klassischem
Simulcast, aber `buildPublishOptions()` in diesem Fork setzt immer Simulcast-Layer - ein
echter Code-Fix wäre nötig, um das aufzulösen. **Root Cause nie abschließend isoliert** (hätte
einen Browser-Konsolen-/WebRTC-Internals-Repro gebraucht). Danach auf 720p-Zwischen-Layer +
`h264` (klassisches Simulcast, kein SVC-Risiko, oft hardwarebeschleunigt v.a. auf iOS)
umgestellt - live verifiziert (7/8 Tracks nativ H.264, 1 sauberer VP8-Fallback).
**Nicht erneut versuchen, ohne vorher einen echten Browser-Repro zu haben.**
## 4. npm-Publish zu Gitea (`@sorb/threadnet-call-embedded`)
⚠️ Dieser Abschnitt beschrieb bis 2026-08-09 einen manuellen/lokalen Vorgang, der
seit dem 2026-08-06 nicht mehr zutrifft — korrigiert bei einer Doku-Durchsicht.
Das Embedded-Package (`embedded/web/package.json`, aktuell `0.19.2-threadnet.7`) wird zu
Gitea's npm-Registry veröffentlicht (`https://rohana.axion1337.de/api/packages/sorb/npm/`,
Scope `@sorb`). Der obere Versionierungs-Track hier (`0.19.2-threadnet.N`) ist unabhängig von
den Docker-Image-Tags, unter denen das fertig gebaute Widget im gitops-Repo deployt wird (z.B.
`v0.2.3-elementcall-h264` als `threadnet-web`-Image-Tag) - zwei getrennte Versionsschemata für
zwei verschiedene Artefakte (npm-Package vs. Docker-Image).
**Der Publish läuft über den `publish_npm`-Job in `.gitlab-ci.yml`**, nicht mehr manuell:
`needs: build_embedded`, ausgelöst per Tag oder auf `main` (`when: manual`, bewusst kein
Automatismus - Veröffentlichen bleibt ein Akt). Bricht ab, wenn `embedded/web/dist` zu wenige
Dateien enthält (Schutz gegen die leeren Pakete aus threadnet-call#4), und veröffentlicht mit
`--tag threadnet` statt `latest`, weil unsere Versionen als npm-Prereleases gelten. Auth über
die CI-Variable `GITEA_NPM_TOKEN` (Gitea-Token, Scope `write:package`) - die frühere lokale,
untrackte `.npmrc` mit Klartext-Token ist damit hinfällig.
Das committete `.github/workflows/publish-embedded-packages.yaml` ist unbenutztes
Upstream-Material (zielt weiterhin auf `registry.npmjs.org`/`@element-hq`) - Gitea Actions
läuft hier nicht, siehe Repo-Topologie unten.
## 5. Bewusst keine Server-seitige ML-Rauschunterdrückung
Nur der client-seitige WebRTC-Standardtoggle (Echo/Noise/Gain-Suppression, aus derselben
Upstream-PR-Linie) wurde übernommen. Bewusst **kein** LiveKit-Agents-basiertes Server-seitiges
ML-Noise-Cancellation (z.B. selbst gehostetes DTLN/RNNoise) - LiveKits eigene Dokumentation
beschreibt diesen Baustein als für AI-Voice-Agents gedacht, nicht für Mensch-zu-Mensch-Calls
(kein unterstützter Weg, bereinigtes Audio an andere Teilnehmer weiterzuleiten).
## 6. Produktname im Widget (`.env.production`)
`VITE_PRODUCT_NAME=aXion1337.Chat` in `.env.production` — eine Zeile, keine
Quelldatei angefasst. Upstream liest den Namen an jeder Stelle als
`import.meta.env.VITE_PRODUCT_NAME || "Element Call"`; die Variable zu setzen ist
deshalb die vollständige Umbenennung **ohne Merge-Reibung**.
Der Name folgt der Regel aus `management/shared/branding.md`: „in der Anwendung"
heißt es aXion1337.Chat — und das Call-Widget läuft in der Anwendung.
**Was dadurch tatsächlich umbenannt wird** (Inventur 2026-08-06, embedded-Modus):
| Stelle | sichtbar wo |
|---|---|
| `error.matrix_rtc_transport_missing` | Fehlermeldung „Der Server ist nicht für … konfiguriert" |
| `error.open_elsewhere_description` | „… wurde in einem anderen Tab geöffnet" |
| `DeveloperSettingsTab` Versionszeile | Einstellungen → Entwicklermodus |
| `usePageTitle``document.title` | im iframe unsichtbar, der Vollständigkeit halber |
**Was im Embedded-Build ohnehin nie erscheint** — und deshalb *nicht* angefasst
wurde:
- **Die Logo-SVGs.** Alle vier sind importiert und liegen im Bundle — gerendert wird
im Widget aber keins, und zwar jeweils durch dieselbe Bedingung gesperrt:
| SVG | gerendert von | Sperre |
|---|---|---|
| `Logo` | `Header.tsx` (`HeaderLogo`) | `FullScreenView` zeigt den Header nur bei `header === "standard"` |
| `LogoMark`, `LogoType` | `CallFooter.tsx` | `showLogo = headerStyle === HeaderStyle.Standard` |
| `LogoLarge` | `LoginPage`, `RegisterPage` | gibt es nur standalone |
`HeaderStyle.Standard` ist der Default für **Nicht**-Widget-Nutzung; als Widget ist
der Header `None` (Desktop) oder `AppBar` (Web/Mobile) — siehe `UrlParams.ts`. Das
gilt auch für Fehlerseiten: `FullScreenView` prüft dieselbe Bedingung, ein Absturz
im Widget zeigt also kein Logo.
⚠️ Nicht danach greppen, ob ein Logo „irgendwo vorkommt" — im gebauten Bundle steht
`<desc>Element Call (Beta)</desc>` aus `Logo.svg` drin, obwohl es nie gezeichnet
wird. Maßgeblich ist die Render-Bedingung, nicht der Treffer.
- **`header_label` („Element Call-Startseite") und `login_subheading`.** Startseite
und Login gibt es nur im Standalone-Modus.
- **Die drei deutschen `developer_mode.matrixRTCMode.*.description`.** Die reden über
*Gegenstellen* („alle beteiligten Element Call Clients v0.17.0 oder neuer") — das
ist eine Kompatibilitätsaussage über fremde Clients, keine Selbstbezeichnung. Sie
umzubenennen wäre inhaltlich falsch.
⚠️ `build:embedded:development` läuft mit `--mode development` und lädt
`.env.production` nicht — ein Dev-Build zeigt weiter „Element Call". Beabsichtigt;
ausgeliefert wird der Produktions-Build.
**Verifiziert** am CI-Artefakt von Pipeline 189 (`ac688d3`), nicht am Quelltext: das
gebaute Bundle enthält „aXion1337.Chat"; die verbliebenen „Element Call"-Treffer sind
Source-Maps, die 22 Sprachdateien (`header_label`, standalone) und die
`<desc>`-Zeile aus `Logo.svg` — keine davon im Widget sichtbar.
## Repo-Topologie (seit 2026-07-31)
**Kanonisch ist `git.lab/axion1337.chat/threadnet-call`** (Homelab-GitLab) — die Kopie auf
`rohana.axion1337.de/sorb/threadnet-call` ist ein automatischer **Push-Mirror** (Lesekopie,
Issues, npm-Registry). **Niemals direkt nach rohana pushen** — der Mirror überschreibt
divergente Stände.