1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 05:37:52 +03:00
Files
android_cast/tmp/20260612-MEDIASERVICE-AI-requirements.md
Anton Afanasyeu f6080f3306 docs
2026-06-12 21:23:00 +02:00

395 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Media service (SFU / MCU) — AI deployment prerequisites
**Document type:** Requirements / handoff (pre-SPEC)
**Date:** 2026-06-12
**Audience:** PO / sysop → AI agent for full deploy + tune on fresh Alpine HVM(s)
**Related:** [docs/specs/20100612_1_scaling.md](../docs/specs/20100612_1_scaling.md), [docs/DRs/20100612_1_scaling.md](../docs/DRs/20100612_1_scaling.md), [examples/sfu/README.md](../examples/sfu/README.md), [docs/20260608_BE_SERVICES_and_infra.md](../20260608_BE_SERVICES_and_infra.md) §SFU
**PDF:** `tmp/20260612-MEDIASERVICE-AI-requirements.pdf` — regenerate with `.venv-pdf/bin/python docs/_pdf_build/md_to_pdf.py` on the copy under `tmp/`
**Code names (product):** **SPIDERWEB** = SFU-alike, **SPIDER** = MCU-alike ([draft glossary](../docs/drafts/20100611_1_net_topology_glossary.txt))
---
---
---
## Table of contents
<!-- toc -->
- [1. Executive answer — HVM vs Docker vs monolith BE](#1-executive-answer-hvm-vs-docker-vs-monolith-be)
- [2. What you give the AI on day zero](#2-what-you-give-the-ai-on-day-zero)
- [3. Recommended instance layout (up to 3 HVMs)](#3-recommended-instance-layout-up-to-3-hvms)
- [4. Network, DNS, and firewall prerequisites](#4-network-dns-and-firewall-prerequisites)
- [5. Integration with existing BE (isolation model)](#5-integration-with-existing-be-isolation-model)
- [6. SFU vs MCU stack choice](#6-sfu-vs-mcu-stack-choice)
- [7. Packages and software (installed later by AI)](#7-packages-and-software-installed-later-by-ai)
- [8. Sizing and bandwidth (200/200 Mbit context)](#8-sizing-and-bandwidth-200200-mbit-context)
- [9. AI workflow after prerequisites are met](#9-ai-workflow-after-prerequisites-are-met)
- [10. Out of scope for first media PoP](#10-out-of-scope-for-first-media-pop)
- [11. PO checklist (copy before handoff)](#11-po-checklist-copy-before-handoff)
- [12. Changelog](#12-changelog)
<!-- /toc -->
---
## 1. Executive answer — HVM vs Docker vs monolith BE
### Recommendation (DR-aligned)
| Approach | Verdict | Why |
|----------|---------|-----|
| **SFU/MCU on current androidcast BE monolith** | **No** | PHP/MariaDB/RSSH/Gitea share CPU/RAM/NIC; `pm.max_children=5` today; blast radius; [INFRA.md](../docs/INFRA.md) keeps `:8089` as **other** Janus stack |
| **Fresh dedicated Alpine HVM(s)** | **Yes (primary)** | Isolated **media plane**; snapshots; UDP/WebRTC without touching hub/crashes |
| **Docker on dedicated HVM** | **Yes (preferred delivery)** | Reproducible Janus/mediasoup/coturn/ffmpeg; easy rollback; same host still “empty” at handoff |
| **Docker on existing BE** | **No** | Does not isolate bandwidth or failure domain |
**Practical model:** PO provides **13 empty Alpine HVMs** with SSH + DNS. AI installs **Docker (+ compose)** on them and runs **SPIDERWEB (SFU)** or **SPIDER (MCU)** stacks in containers. **Control plane** (signaling auth, room lifecycle, RBAC) talks to existing crashes BE via **HTTPS/OpenAPI-style APIs** — no co-location of MariaDB or PHP-FPM with media.
```mermaid
flowchart TB
subgraph Today["Today — monolith BE (unchanged)"]
FE["Gentoo FE apps.f0xx.org"]
BE["Alpine BE :80<br/>PHP MariaDB Gitea RSSH"]
end
subgraph New["New — media PoP (13 HVMs)"]
MED["media-1 Alpine HVM"]
DOCK["Docker: SFU + TURN + signaling sidecar"]
end
MOB["Android app"] --> FE
FE --> BE
MOB -.->|"WebRTC UDP/TCP<br/>post-alpha"| MED
DOCK --> MED
BE -.->|"REST: token room RBAC<br/>OpenAPI"| DOCK
class New fill:#e8f5e9,stroke:#2e7d32
```
**Not too heavy:** one HVM + Docker Compose is enough for **lab/stress**; three HVMs match **prod-shaped** split (SFU / TURN / transcode). Start with **1**; split when metrics or PO asks.
---
## 2. What you give the AI on day zero
Minimum handoff — **no media packages required yet** on the empty machine.
### 2.1 Access
| Item | Required | Example |
|------|----------|---------|
| **SSH target** | Yes | `ssh media@media-lab.example.org` or intra `10.7.x.x` |
| **Sudo** | Yes | passwordless `sudo` for `apk`, `rc-service`, docker |
| **SSH key** | Yes | laptop → HVM; optional: HVM → git read for deploy scripts |
| **Jump host** | If no public SSH | `ProxyJump` via `f0xx-monstro` / `alpine-be` (document in `~/.ssh/config`) |
### 2.2 Machine identity
| Item | Required | Notes |
|------|----------|-------|
| **Hostname** | Yes | e.g. `media-1.intra.raptor.org` |
| **OS** | Yes | Alpine 3.x x86_64 (match prod BE) |
| **vCPU / RAM** | Yes | See [§8](#8-sizing-and-bandwidth-200200-mbit-context) |
| **Root disk** | ≥ 40 GiB SSD | containers + logs |
| **Intra IP** | Yes | `10.7.0.0/8` address stable across reboots |
| **Public reach** | For external test | DNS name OR FE proxy only (see [§4](#4-network-dns-and-firewall-prerequisites)) |
### 2.3 PO-owned (snapshots, DNS, firewall)
| Item | Owner | AI needs |
|------|-------|----------|
| **VM snapshots** | PO | “Snapshot before AI session” + rollback name |
| **External DNS** | PO | A/AAAA or CNAME for WebRTC/signaling test |
| **Firewall / DNAT** | PO | UDP/TCP port list from [§4](#4-network-dns-and-firewall-prerequisites) opened on router/FE |
| **TLS certs** | PO or AI via DNS-01 | Lets Encrypt on FE or on media host |
### 2.4 Integration secrets (existing BE — read-only API)
| Item | Required | Purpose |
|------|----------|---------|
| **Crashes base URL** | Yes | `https://apps.f0xx.org/app/androidcast_project/crashes` |
| **Service account or API token** | Yes | Mint rooms / validate session (new `sfu` API or extend OpenAPI) |
| **RBAC model** | Reference | Same pattern as remote access / short links |
| **Gitea / deploy** | Optional | Pull `android_cast` branch `feature/sfu-relay` or deploy tarball |
AI does **not** need MariaDB root on monolith BE if all integration is **HTTP APIs**.
### 2.5 Decisions PO should state (or defaults)
| Decision | Default if silent |
|----------|-------------------|
| **Topology code name** | **SPIDERWEB** (SFU) first; MCU later |
| **Engine** | **mediasoup** (greenfield) — Janus on `:8089` is **other** stack, avoid unless PO picks Janus on **new** host |
| **Instance count** | **1** for lab; **3** for prod-shaped |
| **Public path** | Subdomain `media.apps.f0xx.org` → FE → media HVM (keeps TLS at FE) |
| **TURN** | **coturn** on same HVM (lab) or instance 2 (prod) |
---
## 3. Recommended instance layout (up to 3 HVMs)
### 3.1 Lab — single HVM (minimum handoff)
```mermaid
flowchart LR
subgraph HVM1["media-1 (single Alpine HVM)"]
NG["nginx :443 reverse proxy"]
SIG["signaling sidecar<br/>Node or Go"]
SFU["mediasoup / Janus SFU"]
TURN["coturn STUN/TURN"]
FF["ffmpeg worker optional"]
end
Client["App / browser"] --> NG
NG --> SIG
Client --> TURN
Client --> SFU
SIG --> SFU
BE["Existing BE PHP"] -.->|HTTPS| SIG
```
All services in **one docker-compose** stack; fine for stress and first WAN cast tests.
### 3.2 Prod-shaped — three HVMs
| VM | Role | Containers / daemons |
|----|------|----------------------|
| **media-1** | **SPIDERWEB SFU** | mediasoup (or Janus), nginx edge, signaling sidecar |
| **media-2** | **TURN + signaling** | coturn, optional dedicated signaling if scaled |
| **media-3** | **Transcode / MCU path** | ffmpeg workers, optional MCU (SPIDER) if not SFU-only |
```mermaid
flowchart TB
FE["FE TLS"] --> M1["media-1 SFU"]
FE --> M2["media-2 TURN"]
APP["Android"] -->|UDP WebRTC| M1
APP -->|UDP TURN| M2
BE["Monolith BE APIs"] -->|REST| M1
M1 --> M3["media-3 ffmpeg optional"]
```
PO can hand **one** machine first; AI documents split boundaries so instances 23 are **additive**, not rewrite.
---
## 4. Network, DNS, and firewall prerequisites
### 4.1 Traffic paths
```mermaid
flowchart TB
Internet["Internet clients"]
Router["Router 200/200 Mbit"]
FE["Gentoo FE"]
M["Media HVM(s)"]
BE["Androidcast BE :80"]
Internet --> Router --> FE
FE -->|"HTTPS signaling<br/>wss / REST"| M
FE --> BE
Internet -->|"UDP WebRTC<br/>after DNAT or 1:1"| M
```
**Do not** attach media to androidcast **`:8089`** vhost ([INFRA.md](../docs/INFRA.md) §2).
### 4.2 Ports to plan (PO opens on FE/router → media HVM)
| Port / proto | Service | Notes |
|--------------|---------|-------|
| **443/tcp** | HTTPS / WSS signaling | Via FE reverse proxy recommended |
| **3478/udp,tcp** | STUN/TURN (coturn) | Required for many NATs |
| **4915265535/udp** | WebRTC media (ICE) | Range size depends on engine; document in SFU SPEC |
| **8080/tcp** | SFU HTTP API (internal) | **Not** public; FE or intra only |
| **22/tcp** | SSH | Intra or VPN only in prod |
Exact ICE port range: set in mediasoup/Janus config during deploy; PO must allow **UDP range** on path to media HVM.
### 4.3 DNS names (examples)
| Name | Points to | Use |
|------|-----------|-----|
| `media.apps.f0xx.org` | FE → proxy → media-1 | Public signaling + health |
| `turn.apps.f0xx.org` | FE or media-2 | TURN URI in app |
| `media-lab.intra.raptor.org` | 10.7.x.x | AI + sysop intra testing |
---
## 5. Integration with existing BE (isolation model)
Media HVM **must not** share MariaDB or PHP-FPM with crashes console. Integration is **API-only**:
```mermaid
sequenceDiagram
participant App as Android app
participant FE as FE nginx
participant BE as Crashes BE PHP
participant SIG as Media signaling
participant SFU as SFU engine
App->>FE: HTTPS session / cast token
FE->>BE: existing auth APIs
App->>SIG: WSS create room (bearer)
SIG->>BE: POST validate token / RBAC
BE-->>SIG: room allowed + ttl
SIG->>SFU: create room
App->>SFU: WebRTC publish/subscribe UDP
```
| Integration | Method | Existing artifact |
|-------------|--------|-------------------|
| Health gate | GET | `api/sfu_health.php` (stub today) |
| Feature flag | config | `config.php``sfu.enabled`, URLs |
| Room mint / revoke | **New REST** | OpenAPI under crashes or `media-api` submodule |
| Auth | Bearer + session RBAC | Same as remote access / short links pattern |
| Metrics | POST ingest | Optional → `graph_upload.php` or new series |
| No direct DB | — | Media DB (if any) is **local** to HVM (Redis/SQLite) |
**OpenAPI:** extend [examples/crash_reporter/backend](../examples/crash_reporter/backend) or new `backend/media-signaling` repo later — AI needs **written** API contract before prod wire-up.
---
## 6. SFU vs MCU stack choice
| | **SPIDERWEB (SFU)** | **SPIDER (MCU)** |
|---|---------------------|------------------|
| **Use** | Multiparty cast; subscribers receive per-stream | Mix down; single output; higher CPU per room |
| **Engine candidates** | **mediasoup** (preferred greenfield), Janus VideoRoom | Janus MCU plugin, ffmpeg bridge, custom |
| **CPU** | Moderate per stream; scales with subscribers | High per room (encode) |
| **Latency** | Lower | Higher |
| **First milestone** | **Yes** | Phase 2 / media-3 |
**Janus on existing `:8089`:** treat as **foreign** — do not piggyback androidcast nginx. New Janus instance on **media HVM** only if PO rejects mediasoup.
**Docker vs bare metal on HVM:** use **Docker** for SFU/TURN/signaling; host only needs Alpine + docker + nginx + firewall tools.
---
## 7. Packages and software (installed later by AI)
PO delivers **almost empty** Alpine; AI installs when handoff complete.
### 7.1 Host (Alpine packages)
```text
# Baseline (all media HVMs)
openssh sudo bash curl wget git ca-certificates
nginx openssl iptables ip6tables
docker docker-cli-compose
# Optional host tools
tcpdump bind-tools jq python3
# If bare-metal fallback (no Docker) — not recommended first
# janus-gateway mediasoup — prefer official containers
```
### 7.2 Container images (typical compose)
| Service | Image / build | Role |
|---------|---------------|------|
| **mediasoup** or **janus** | Official or pinned Dockerfile in repo | SFU |
| **coturn** | `coturn/coturn` | STUN/TURN |
| **signaling** | Custom Node/Go from repo | Rooms, BE API client |
| **nginx** | `nginx:alpine` or host nginx | TLS termination at edge or intra |
| **ffmpeg** | `jrottenberg/ffmpeg` or alpine | Transcode sidecar (media-3) |
| **redis** | `redis:alpine` | Room state optional |
### 7.3 Repo deliverables (AI produces after deploy)
| Artifact | Location (proposed) |
|----------|---------------------|
| `docker-compose.yml` | `examples/sfu/deploy/` or `backend/media-pop/` |
| nginx FE fragment | `examples/sfu/deploy/nginx.fe-media.snippet` |
| BE config keys | `config.example.php``sfu.*` (already stubbed) |
| Smoke script | `examples/sfu/scripts/smoke_sfu.sh` |
| OpenAPI | `examples/sfu/openapi.yaml` |
---
## 8. Sizing and bandwidth (200/200 Mbit context)
WAN **200/200 Mbit** sits behind FE; media UDP may be **DNAT** to media HVM.
| Profile | vCPU | RAM | Notes |
|---------|------|-----|-------|
| **Lab / stress (1 HVM)** | **48** | **816 GiB** | SFU + TURN + signaling; ~1030 parallel WebRTC streams |
| **Prod SFU node** | **8+** | **16 GiB** | Dedicated NIC budget; see [SPEC §12.3](../docs/specs/20100612_1_scaling.md#123-network-bandwidth-and-egress) |
| **TURN only** | **2** | **4 GiB** | Mostly relay bandwidth |
| **ffmpeg node** | **8+** | **1632 GiB** | CPU-bound transcodes |
**Bandwidth rule of thumb (SFU):**
| Streams | Approx WAN need |
|---------|-----------------|
| 10 × 1 Mbps video | **~1015 Mbps** + overhead |
| 50 × 1 Mbps | **~5080 Mbps** — approaches 200 Mbit shared with rest of estate |
| 100+ viewers | **CDN/SFU PoP or second site** — not single 200 Mbit |
Stress test: measure on **intra** first, then **public DNS** through FE.
---
## 9. AI workflow after prerequisites are met
```mermaid
flowchart TD
A["PO: empty HVM + SSH + DNS + firewall list"] --> B["AI: verify ssh sudo intra ping"]
B --> C["AI: apk + docker + compose"]
C --> D["AI: deploy SFU stack lab compose"]
D --> E["AI: nginx FE fragment + BE sfu.enabled URLs"]
E --> F["Smoke: sfu_health + WSS + ICE"]
F --> G{"PO: load test OK?"}
G -->|yes| H["Document + optional 2nd/3rd HVM split"]
G -->|no| I["Tune UDP range CPU docker limits"]
I --> F
```
| Step | AI action | PO action |
|------|-----------|-----------|
| 0 | — | Snapshot empty VM |
| 1 | Probe CPU/RAM/NIC, `apk update` | Confirm DNS/firewall |
| 2 | Install docker, compose, pin versions | — |
| 3 | Bring up mediasoup + coturn + signaling | — |
| 4 | FE nginx `location /sfu/` or subdomain proxy | Reload FE nginx |
| 5 | Enable `sfu.enabled` + URLs on monolith BE **only** | Sync config.php |
| 6 | Run smoke + optional load/WebRTC client | Review metrics |
| 7 | Snapshot “golden” media PoP | — |
---
## 10. Out of scope for first media PoP
- Replacing LAN UDP cast (alpha path unchanged)
- Moving crashes/tickets/Gitea to media HVM
- Full GEO policy ([SPEC §14](../docs/specs/20100612_1_scaling.md#14-global-availability-and-geo-policy)) — later with F3/F10
- Production payments / recording storage
- Merging with Janus stack on BE `:8089`
---
## 11. PO checklist (copy before handoff)
```text
[ ] Alpine 3.x HVM provisioned (13); specs noted
[ ] SSH + sudo for AI; key installed
[ ] Intra IP 10.7.x.x stable
[ ] External DNS name for test (or FE-only proxy agreed)
[ ] Firewall: UDP 3478 + WebRTC range → media HVM
[ ] Snapshot taken (empty baseline)
[ ] Decision: SPIDERWEB (SFU) first — mediasoup default
[ ] Crashes BE base URL + API token for room validation
[ ] Confirm: do NOT use androidcast :8089 / monolith BE for SFU
[ ] Optional: 2nd/3rd HVM reserved for TURN + ffmpeg
```
---
## 12. Changelog
| Date | Change |
|------|--------|
| 2026-06-12 | Initial prerequisites — HVM vs Docker, 3-instance layout, BE API isolation, PO checklist |
---
**Documentation index:** [docs/README.md](../docs/README.md)