Aller au contenu

Architecture du SFU

Le SFU est un serveur WebRTC autonome, écrit en Rust, bâti sur la bibliothèque str0m. Il relaie les paquets sans les transcoder (voir Architecture générale).

Le SFU démarre plusieurs threads de travail (sfu-0, sfu-1, etc.), dont le nombre est configurable.

  • Chaque thread possède son propre socket UDP (port de base + index du thread).
  • Les participants d’une même salle sont répartis entre les threads selon un hachage de (salle, client), ce qui parallélise les poignées de main DTLS et le traitement média.
  • Les threads communiquent par des files bornées (canaux crossbeam) ; la profondeur de ces files est exposée en métrique (vuisio_cross_thread_queue_depth, voir Supervision).

Chaque thread déroule la même boucle, à haute fréquence :

flowchart LR
    R["Réception<br/>UDP (str0m)"] --> P["Poll<br/>sorties de str0m"]
    P --> X["Propagation<br/>hooks + relai"]
    X --> F["Flush<br/>envoi UDP groupé"]
    F --> R

Lors de la propagation, pour chaque paquet média sortant :

  1. si c’est de l’audio et qu’un hook on_media_transform est défini, il peut remplacer la charge utile (anonymisation) ;
  2. le paquet est relayé aux participants locaux ;
  3. le hook on_media_out est appelé (observation du flux, par exemple pour l’archivage) ;
  4. les paquets destinés aux clients d’autres threads sont regroupés et transmis par les files inter-threads.

Le SFU ne décode jamais le média : il choisit la couche simulcast adaptée et relaie les paquets RTP tels quels.

Le SFU reconnaît un ensemble de commandes internes envoyées par datachannel (changer de nom, de rôle, signaler un partage d’écran, chat, réaction, lever la main…). Tout message non reconnu est transmis au hook on_command, qui décide quoi en faire.

Les configurations de salle (nom, plafond, verrouillage, mot de passe) sont gérées par un registre et persistées dans Redis ; les participants, eux, ne vivent qu’en mémoire. Chaque thread tient la part des salles dont il a la charge.

Le serveur se construit avec VuisioServerBuilder : on lui passe les hooks, le port d’écoute, puis on le lance.

VuisioServerBuilder::new()
.hooks(my_hooks)
.listen_port(3000)
.run()
.await;

C’est ce que fait l’orchestrateur (bin/vuisio), après avoir préparé les hooks à partir des modules enregistrés.