Volver a la wiki

Descripción

Cloudflare Pages Function (functions/api/webrtc/signal.ts) que actúa como canal de señalización efímero para las videollamadas WebRTC peer-to-peer del workspace del equipo (Edu/Dani/Txell).

El endpoint no transporta vídeo ni audio: solo intercambia los ~2 KB de metadatos técnicos (SDP offer/answer + ICE candidates) que los browsers necesitan para negociar la conexión directa. Una vez establecida la conexión, el vídeo va browser-a-browser vía STUN, sin pasar por ningún servidor.

Introducido en s79 (22-05-2026) como reemplazo de Jitsi. Ver [[decision—20260522—webrtc-reemplaza-jitsi]].


Operaciones

GET /api/webrtc/signal

Consulta mensajes de señalización pendientes para un peer.

Query params:

ParámetroTipoObligatorioDescripción
roomstring✓Identificador de la sala
peerstring✓ID del peer que consulta
sinceinteger—ID del último mensaje recibido (paginación pull-incremental). Default: 0

Lógica de filtrado:

Cleanup inline: antes de consultar, borra automáticamente todos los mensajes con created_at < now - 60s. Sin cron dedicado.

Respuesta: array JSON de objetos con payload ya parseado.


POST /api/webrtc/signal

Publica un mensaje de señalización.

Body JSON:

{
  "room": "string",
  "from_peer": "string",
  "from_name": "Edu | Dani | Txell",
  "kind": "peer_joined | peer_left | offer | answer | ice",
  "payload": {},
  "to_peer": "string | null"
}

Reglas de validación:

Respuesta 201: { id: <last_row_id>, ok: true }


Autenticación

Usa resolveTeamMember() de functions/_lib/staff, que valida la CF Access JWT cookie del request. Solo los 3 miembros del equipo (Edu/Dani/Txell) pueden acceder; cualquier otro recibe 401 Not authenticated as team member.


Flujo de señalización completo

Peer A entra a la sala
  → POST kind=peer_joined (broadcast, to_peer=null)

Peer B hace poll (GET since=0)
  → recibe peer_joined de A

Peer B → POST kind=offer (to_peer=A, payload=SDP offer)
Peer A → GET → recibe offer
Peer A → POST kind=answer (to_peer=B, payload=SDP answer)
Peer B → GET → recibe answer

Ambos intercambian ICE candidates (POST kind=ice, to_peer=otro)
→ Conexión P2P establecida — el vídeo ya no pasa por este endpoint

Polling continúa cada 1.5s para detectar nuevos peers / ICE candidates tardíos

Límites de tamaño de payload

Tipo de mensajeTamaño típicoLímite configurado
SDP offer/answer~2 KB8 KB
ICE candidate~200 B8 KB
peer_joined/left< 100 B8 KB

Errores HTTP

CódigoCondición
400Faltan params room/peer/kind
400kind no permitido
400from_name no es TeamMember válido
401Cookie CF Access ausente o inválida
403from_name no coincide con miembro autenticado (anti-spoofing)
413Payload > 8.000 bytes
500Fallo en INSERT D1

Implementación

Véase también

Subir