Salles de sous-groupe

Salles de sous-groupe (breakout rooms)

Ce que ça fait

Répartit les participants d’une salle en plusieurs sous-salles, avec un jeton d’accès par participant — sans dépendre d’une fonctionnalité serveur qui n’existe que sur LiveKit Cloud (voir « Pièges »).

Ce que Legba fait, ce que l’application fait

Legba planifie (planBreakoutRooms) et provisionne (createBreakoutRooms) : il crée les sous-salles et émet un jeton par participant. Le reste — livrer ce jeton au bon navigateur, et faire basculer une connexion d’une salle à l’autre — reste du côté de l’application, avec les briques déjà fournies par @legba-core/realtime.

Étape 1 — Répartir et provisionner (backend)

import { createRoomService, planBreakoutRooms, createBreakoutRooms } from "@legba-core/realtime";

const rooms = createRoomService({ serverUrl, apiKey, apiSecret });

const plan = planBreakoutRooms(participantIdentities, {
  groupSize: 5,
  roomNamePrefix: "salle-groupe",
  mode: "random", // ou "sequential" pour préserver l'ordre fourni
});

const { tokensByIdentity } = await createBreakoutRooms(rooms, plan, {
  apiKey,
  apiSecret,
  role: "participant",
});

Pour une répartition décidée à la main (le modérateur choisit qui va où dans son interface), construire directement la liste d’assignations et sauter planBreakoutRooms :

const manualPlan = [
  { roomName: "salle-groupe-vip", participantIdentities: ["alice"] },
  { roomName: "salle-groupe-debutants", participantIdentities: ["bob", "carol"] },
];
const { tokensByIdentity } = await createBreakoutRooms(rooms, manualPlan, { apiKey, apiSecret, role: "participant" });

Étape 2 — Livrer le jeton (application)

Comment transmettre tokensByIdentity[identity] au bon navigateur est un choix d’architecture propre à chaque application — un canal de données (sendData, LGB-015) vers ce participant précis, une réponse HTTP, un WebSocket applicatif, etc. Legba ne l’impose pas.

Étape 3 — Basculer de salle (navigateur)

Chaque client (modérateur compris) reçoit son jeton et fait un disconnect() suivi d’un connect() — les mêmes méthodes que LGB-013, rien de nouveau :

// room : instance LegbaClientRoom déjà connectée à la salle principale
await room.disconnect();
await room.connect({ serverUrl, token: tokenPourCetteSousSalle });

Observer une sous-salle sans la quitter

Un modérateur qui veut surveiller une sous-salle sans quitter la salle principale ouvre simplement une deuxième instance LegbaClientRoom :

const salleMoniteur = createLegbaRoom();
await salleMoniteur.connect({ serverUrl, token: tokenObservateur });
// room (première instance) reste connectée à la salle principale pendant ce temps

Pièges

  • moveParticipant/forwardParticipant du SDK LiveKit ne fonctionnent jamais en self-hosted — vérifié contre un vrai serveur livekit-server : twirp error unknown: not implemented. Confirmé par l’équipe LiveKit elle-même : ces RPC nécessitent un routage entre nœuds qui n’existe que sur LiveKit Cloud. C’est pour ça que cette recette provisionne des jetons plutôt que d’encaspuler ces méthodes.
  • createBreakoutRooms est idempotent sur la création des salles (une salle de destination déjà existante n’est pas une erreur), mais rejette une répartition manuelle incohérente (une identité assignée à deux salles, une salle sans participant) avant tout appel réseau.
  • Le disconnect()/connect() côté client entraîne une brève coupure de connexion (perceptible mais très courte) — ce n’est pas un changement de salle invisible comme le serait un vrai moveParticipant côté serveur.
  • Livrer les jetons reste hors du périmètre de Legba : choisir un canal de livraison qui n’expose jamais un jeton à un participant autre que celui pour qui il a été émis.