# DESIGN — modes & directions de `@mostajs/media-mcu` (rôles ingest / program / full)

**Auteur** : Dr Hamid MADANI <drmdh@msn.com>
**Date** : 2026-06-06
**Statut** : PROPOSITION — design doc (alimente le plan de dev media-mcu ; cohérent DEVRULES §9 #03/#12, §10)
**Origine** : besoin RaceVision (`@mostajs/race-event`) — caméras = écriture seule, spectateurs = lecture seule, régie = les deux. Question : faut-il **3 builds** (in/out)/(in)/(out) ? **Réponse : non.**

> **État du module** : `@mostajs/media-mcu@0.1.0` **existe déjà** (`mosta-media-stack/mosta-media-mcu`) mais **n'est pas terminé — il est parqué** (des bugs persistent). Ce document cadre donc une **nouvelle itération / amélioration** : (1) **finir + stabiliser** l'existant (corriger les bugs en suspens), puis (2) ajouter la capacité **rôles/direction** + **program-bus** décrite ci-dessous. À faire d'abord : un **audit des bugs** du module parqué (livrable #02) avant d'implémenter.

> Décision : **un seul codebase**, deux **modes média** (SFU, MCU) et trois **rôles de direction** (ingest / program / full) activés par **configuration + scope de clé API** — pas trois applications. La maquette de référence est la régie « A » de RaceVision (`mosta-geo/examples/realtime-cyclists/docs/img/racevision-mixer-*.png`).

---

## 1. Les deux modes média

| Mode | Topologie | Rôle | Quand l'utiliser |
|---|---|---|---|
| **SFU** (Selective Forwarding Unit) | **1 → N** sans mixage : route les flux tels quels | distribuer chaque source à plusieurs abonnés | ingérer les caméras, **multiview** régie, diffusion faible latence à un nombre modéré |
| **MCU** (Multipoint Control Unit) | **N → 1** : **mixe/compose** plusieurs sources en UN flux | composer un programme unique | **Plateau LIVE TALK** (incrustations, split), **programme réalisé** (sortie unique) |

> SFU = « aiguillage » ; MCU = « table de mixage ». RaceVision utilise **les deux** : SFU pour ingérer/prévisualiser, MCU pour composer le plateau et le programme.

---

## 2. Les trois rôles de direction (dans le MÊME module)

Le cœur reste **`(in/out)`**. On n'en fait pas 3 builds : on **active les surfaces** par un mode runtime et on **impose la direction par le scope de la clé API** (le modèle READ/WRITE déjà en place).

| Rôle (`MCU_ROLE`) | Surfaces actives | Direction | Clé API exigée |
|---|---|---|---|
| **ingest** | entrée WHIP uniquement | **(in)** écriture seule | `operations:[write]` (caméras/coureurs) |
| **program** | sortie WHEP/HLS uniquement | **(out)** lecture seule | `operations:[read]` (spectateurs) |
| **full** | entrée + sortie + bus programme | **(in/out)** | `operations:[admin]` (régie) |

Pourquoi par clé et non par build :
- **WebRTC sépare déjà les sens** : **WHIP** = ingest (write), **WHEP** = egress (read). Une caméra n'ouvre que WHIP, un spectateur que WHEP/HLS → ce sont deux **surfaces** du même nœud.
- **Moindre privilège** porté par le scope (`write`/`read`/`admin`), pas par du code dupliqué (DRY, DEVRULES §10).
- Le mode `MCU_ROLE` ne sert qu'à l'**isolation de process / scaling / durcissement** (déployer un nœud d'ingest séparé d'un nœud de sortie), pas à changer la logique.

---

## 3. La sortie de masse ne passe PAS par le MCU

Les **milliers de spectateurs** ne tapent jamais le MCU en WebRTC. Le MCU ne produit **qu'un seul flux programme**, **packagé en HLS** (`@mostajs/media-server` + CDN). Le « (out) lecture seule scalable » = **HLS/CDN**, pas une instance MCU.

```
caméras (WHIP, write) ─► [SFU: multiview] ─► [MCU full: bus programme + plateau] ─► programme (1 flux)
                                                                        ├─► HLS packager + CDN ─► milliers de spectateurs (read, HLS)
                                                                        └─► WHEP (out) ─► faible latence, petit nombre (read)
```

---

## 4. Mode recommandé pour chaque utilisation (RaceVision)

| Utilisation | Mode | Rôle/direction | Clé |
|---|---|---|---|
| Caméra **moto / voiture / ambulance / podium** (publication) | **SFU** | **ingest (in)** via WHIP | **WRITE** |
| **Multiview** régie (prévisualiser toutes les caméras) | **SFU** | egress (out) côté régie | **admin** |
| **Studio LIVE TALK** (animateur + invités composés) | **MCU** | **full (in/out)** | **admin** |
| **Programme** réalisé (sortie unique) | **MCU** | **program (out, 1 flux)** | **admin** (production) |
| **Spectateurs (milliers)** | **HLS** (via media-server+CDN) | **out** lecture seule | **READ** |
| Spectateurs **faible latence** (petit nombre, option) | **SFU/WHEP** | program (out) | **READ** |
| Coureur publiant **sa propre** caméra | **SFU** | ingest (in) WHIP | **WRITE** |

---

## 5. Surface d'API proposée (additive, rétro-compatible)

- `MCU_ROLE=ingest|program|full` (défaut `full`) — n'active que les surfaces du rôle.
- Endpoints directionnels distincts : `…/whip` (ingest, write) · `…/whep` (egress, read) · `…/hls` (egress, read).
- Réutilise le middleware api-keys de l'écosystème : `operations` (write/read/admin) + `transports` (ws/whip/whep/hls) + `projects` (scope course).
- **Program-bus / switcher** (nouvelle capacité, cf. maquette régie) : API de sélection de la source au programme, transitions (cut/fade/wipe), superpositions (graphics), bandeau sponsor, mixeur audio — détaillée dans le design UI RaceVision (`mosta-geo/examples/realtime-cyclists/docs/DESIGN-UI-RACEVISION.md`).

---

## 6. Conséquences

- **Pas de fork** : un module, 2 modes, 3 rôles. Maintenance unique.
- **Sécurité** : direction imposée par la clé, pas par la confiance du client.
- **Scaling** : déployer N nœuds `ingest` + M nœuds `program` du même binaire si besoin ; la masse part en HLS.
- À refléter dans `media-mcu` : `llms.txt`, `CHANGELOG.md`, plan de dev (#03), doc technique (#12).

---

*Design — Dr Hamid MADANI <drmdh@msn.com> — 2026-06-06.*
