# 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 `Element Call (Beta)` 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 ``-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.