CreaRack-SL

MeetingRoom — Componente de videollamada WebRTC

Archivo: src/components/widgets/MeetingRoom.tsx Tipo: React component (island Astro, client:only="react") Sesión de origen: s79 (22-05-2026) · Último refactor: s80 (22-05-2026, PR#68)


Descripción

MeetingRoom es el componente React principal que implementa las videollamadas peer-to-peer en el Workspace. Gestiona toda la lógica de señalización, negociación WebRTC y renderizado de la sala de reunión.

Modo de uso (refactor s80 · 22-05-2026): el componente vive ahora en una ventana popup propia del navegador (/reunion, abierta con window.open(..., 'popup=yes,...') desde TeamChat). Ocupa el 100% del viewport del popup. Sin drag/resize/portal — la ventana del SO ya cumple esos roles y de regalo permite arrastrar la reunión al segundo monitor. Refactor motivado por que el modal flotante embebido en el WS se desmontaba al navegar entre páginas Astro (output: ‘static’ sin View Transitions), matando la sesión WebRTC. Ver [[decision—20260522—meetingroom-popup-window]].


Responsabilidades

ÁreaDetalle
SeñalizaciónEnvía/recibe señales (peer_joined, peer_left, ICE candidates, SDP offers/answers) mediante sendSignal y polling cada ~1.5 s
Gestión de peerspeersMapRef — mapa de RemotePeer con su RTCPeerConnection y estado de negociación
Streams localeslocalStream (cámara/mic) y stream de pantalla compartida
InterfazFullscreen dentro de la ventana popup; controles de audio, vídeo, pantalla y ajustes de dispositivos
Ajustes de dispositivosPanel overlay para seleccionar cámara, micrófono y altavoz (desde PR#62, 2026-05-22)
Cleanup robustobeforeunload + pagehide envían peer_left via navigator.sendBeacon cuando el usuario cierra el popup desde la X del SO (s80). Sin esto, los peers tardan ~5 s en detectar la desconexión.

Props

interface Props {
  /** Nombre del usuario que abre la reunión (Edu/Dani/Txell). */
  author: string;
  /** Destinatario ('Todos' o nombre concreto). */
  target: string;
  /**
   * Si true, no anuncia «X ha iniciado una reunión» al chat.
   * Usar cuando el usuario se une a una reunión ya convocada.
   */
  silent?: boolean;
  /** Cierre solicitado por el usuario (botón Colgar / Esc). El shell hace window.close(). */
  onClose: () => void;
}

Tipos / Schemas internos

interface RemotePeer { peerId: string; name: string; stream: MediaStream | null; pc: RTCPeerConnection }
interface SignalMessage { room: string; from_peer: string; from_name: string; to_peer: string | null; kind: string; payload: unknown }
interface VideoTileProps { stream: MediaStream; label: string }

ICE servers (hardcoded): stun.l.google.com:19302, stun1.l.google.com:19302


Lifecycle destacado

  1. useEffect de inicialización: llama a getUserMedia respetando selección previa → refreshDevices() → añade listener devicechange.
  2. Cleanup React: removeEventListener('devicechange', ...), para tracks, cierra RTCPeerConnections, envía peer_left.
  3. beforeunload + pagehide: navigator.sendBeacon('/api/webrtc/signal', {kind:'peer_left'}) — garantiza que los otros peers detecten la salida sin esperar al timeout de connection-state (añadido en s80).
  4. Polling de señales cada 1.5 s para recibir eventos de otros peers.

Persistencia localStorage

ClaveValor
meeting:cameraIddeviceId de la cámara seleccionada
meeting:micIddeviceId del micrófono seleccionado
meeting:speakerIddeviceId del altavoz seleccionado

Historial de cambios relevantes

SesiónCambio
s79 (22-05-2026, PR#62)Creación. Reemplaza JitsiMeetingModal. Modal flotante draggable + redimensionable con createPortal.
s80 (22-05-2026, PR#68)Refactor a fullscreen popup: eliminados drag/resize/clampPos/collapsed/createPortal (~150 LOC). Añadido beforeunload/pagehide con sendBeacon. Vive en /reunion abierto por window.open desde TeamChat.

Véase también

  • [[feature—workspace—webrtc-peer-to-peer]] — Feature completa: WebRTC P2P en el workspace, arquitectura general
  • [[decision—20260522—meetingroom-popup-window]] — ADR del cambio modal → popup (s80, PR#68)
  • [[entity—meeting—component—meeting-room-shell]] — Wrapper standalone que monta este componente en /reunion
  • [[decision—20260522—webrtc-reemplaza-jitsi]] — ADR previo: por qué se reemplazó Jitsi
  • [[feature—meeting—ajustes-dispositivos]] — Feature de selección de cámara/micrófono/altavoz