W3docs

WebRTC

WebRTC (Comunicación Web en Tiempo Real) es un estándar abierto y conjunto de APIs del navegador que permiten la comunicación directa entre navegadores sin necesidad de plugins.

WebRTC: Comunicación en Tiempo Real en el Navegador

WebRTC (Web Real-Time Communication) es un estándar abierto y conjunto de APIs del navegador que permiten a dos navegadores intercambiar audio, video y datos arbitrarios directamente entre sí — de igual a igual — sin enrutar los medios a través de un servidor y sin ningún plugin. Es la base de videoconferencias, llamadas de voz, compartición de pantalla, estado de juegos en vivo y transferencia de archivos de baja latencia.

Este capítulo explica qué ofrece WebRTC, las tres APIs sobre las que se construye, los conceptos de señalización y traversal de NAT que confunden a la mayoría de los principiantes, y un ejemplo completo funcional con canal de datos que puedes ejecutar en esta página.

Qué hace realmente WebRTC

El navegador ya sabe cómo comunicarse con un servidor (consulta Fetch API y WebSockets). WebRTC añade la pieza que faltaba: una forma de que dos clientes hablen entre sí. Una vez que se abre una conexión entre pares, los medios y los datos viajan por el camino más corto posible — a menudo directamente entre las dos máquinas — por eso la latencia de WebRTC es mucho menor que retransmitir todo a través de tu backend.

Usos típicos:

  • Llamadas de audio y video — voz/video en tiempo real, como Zoom o Google Meet.
  • Compartición de pantalla — captura una pantalla o ventana con getDisplayMedia() y transmítela a un par.
  • Datos en tiempo real — estado del juego, chat, posiciones del cursor o fragmentos de archivos a través de un RTCDataChannel.

Por qué usar WebRTC

  • De igual a igual, baja latencia. Los medios fluyen directamente entre los pares, no a través de tu servidor, por lo que los viajes de ida y vuelta son cortos y el costo de ancho de banda se mantiene bajo.
  • Sin plugins. Integrado en todos los navegadores modernos — sin Flash, sin aplicación nativa, sin descargas.
  • Cifrado por defecto. Los medios usan SRTP y los canales de datos usan DTLS; el cifrado es obligatorio y no se puede desactivar.
  • Multiplataforma. Funciona en navegadores de escritorio y móviles, y desde aplicaciones nativas mediante el mismo estándar.
  • Estándar abierto. Mantenido por el W3C e IETF, por lo que continúa mejorando sin bloqueo de proveedor.

Las tres APIs principales

WebRTC es en realidad tres APIs que trabajan juntas:

  1. MediaStream API (getUserMedia) — captura audio/video del micrófono, la cámara o la pantalla como un MediaStream.
  2. RTCPeerConnection — el corazón de WebRTC. Negocia, cifra y mantiene la conexión entre dos pares y transporta las pistas de medios.
  3. RTCDataChannel — un canal bidireccional para enviar datos arbitrarios (cadenas o binarios) de igual a igual, similar a WebSockets pero sin un servidor en el medio.

Señalización: la parte que WebRTC no hace

Dos navegadores no pueden encontrarse de la nada. Antes de que pueda abrirse una conexión entre pares, los pares deben intercambiar dos tipos de información:

  • SDP (Session Description Protocol) — una "oferta" y "respuesta" que describen códecs, formatos de medios y parámetros de conexión.
  • Candidatos ICE — posibles direcciones de red (pares IP/puerto) en las que se puede alcanzar a cada par.

WebRTC no define cómo ocurre este intercambio — eso es tu trabajo, y se llama señalización. Construyes un canal de señalización con el transporte de servidor que prefieras; WebSockets es la opción más común. El flujo siempre es:

  1. El llamante crea una oferta y la envía a través del servidor de señalización.
  2. El receptor recibe la oferta, crea una respuesta y la devuelve.
  3. Ambos pares intercambian candidatos ICE a medida que se descubren.
  4. Se establece la conexión directa entre pares; el servidor de señalización ya no es necesario.

STUN y TURN: atravesar cortafuegos

La mayoría de los dispositivos están detrás de NAT (Network Address Translation) y cortafuegos, por lo que un par rara vez conoce su propia dirección pública. Dos tipos de servidores resuelven esto:

  • Servidor STUN — le dice a un par su IP/puerto público para que los pares puedan intentar una conexión directa. Económico y sin estado; Google ejecuta unos públicos gratuitos.
  • Servidor TURN — retransmite los medios cuando una conexión directa es imposible (cortafuegos corporativos estrictos). Consume ancho de banda, por lo que es un recurso de respaldo, no la opción predeterminada.

Listas estos servidores en la configuración iceServers que se pasa a RTCPeerConnection:

const configuration = {
  iceServers: [
    { urls: 'stun:stun.l.google.com:19302' },
    // A TURN server is added for hard-to-reach networks:
    // { urls: 'turn:turn.example.com', username: 'user', credential: 'pass' }
  ],
};

const peerConnection = new RTCPeerConnection(configuration);

Ejemplo: capturar la cámara con getUserMedia

El primer paso de cualquier videollamada es obtener el stream local. getUserMedia devuelve una Promise, por lo que puedes usar async/await:

<video id="localVideo" autoplay playsinline muted></video>
const localVideo = document.getElementById('localVideo');

async function startCamera() {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true,
    });
    localVideo.srcObject = stream; // show the live camera feed
    return stream;
  } catch (error) {
    console.error('Could not access camera/microphone:', error.message);
  }
}

startCamera();

getUserMedia solo funciona en un contexto seguro (HTTPS o localhost) y solicita permiso al usuario — nunca puedes grabar a alguien silenciosamente.

Ejemplo: un canal de datos completo entre dos pares

La forma más clara de ver WebRTC en funcionamiento es conectar dos objetos RTCPeerConnection entre sí en un solo script. Aquí ambos pares viven en la misma página, por lo que podemos conectar su señalización directamente en lugar de a través de un servidor — el intercambio de SDP/ICE es exactamente lo que un servidor de señalización real transportaría. Pega esto en la consola del navegador en cualquier página HTTPS para verlo ejecutarse:

// Two peers, normally on different machines.
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();

// --- Signaling: hand each peer's ICE candidates to the other.
// In production this travels over WebSockets; here we call directly.
caller.onicecandidate = (e) => e.candidate && callee.addIceCandidate(e.candidate);
callee.onicecandidate = (e) => e.candidate && caller.addIceCandidate(e.candidate);

// The callee listens for the channel the caller opens.
callee.ondatachannel = (event) => {
  const channel = event.channel;
  channel.onmessage = (e) => {
    console.log('Callee received:', e.data);
    channel.send('pong'); // reply over the same channel
  };
};

// The caller creates the data channel.
const channel = caller.createDataChannel('chat');
channel.onopen = () => channel.send('ping');
channel.onmessage = (e) => console.log('Caller received:', e.data);

// --- Offer / answer negotiation.
async function connect() {
  const offer = await caller.createOffer();
  await caller.setLocalDescription(offer);
  await callee.setRemoteDescription(offer);

  const answer = await callee.createAnswer();
  await callee.setLocalDescription(answer);
  await caller.setRemoteDescription(answer);
}

connect();
// Logs:
// Callee received: ping
// Caller received: pong

El patrón es el mismo para video: en lugar de createDataChannel, llamas a peerConnection.addTrack(track, stream) por cada pista de getUserMedia, y lees los medios entrantes en un manejador ontrack:

const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
stream.getTracks().forEach((track) => peerConnection.addTrack(track, stream));

// The remote peer's media arrives here:
peerConnection.ontrack = (event) => {
  document.getElementById('remoteVideo').srcObject = event.streams[0];
};

Errores comunes

  • Requiere HTTPS. getUserMedia y getDisplayMedia fallan fuera de un contexto seguro (HTTPS o localhost).
  • Aún necesitas un servidor de señalización. WebRTC gestiona los medios, pero debes construir tú mismo el intercambio de oferta/respuesta/ICE — generalmente a través de WebSockets.
  • Crea siempre la oferta/respuesta en orden. setLocalDescription debe ejecutarse antes que setRemoteDescription para el lado correspondiente, o la negociación falla.
  • No olvides un servidor TURN en producción. STUN solo falla en redes restrictivas; sin TURN, entre el 10 y el 20% de las conexiones en el mundo real no se establecerán.
  • Los permisos pueden denegarse. Envuelve getUserMedia en try/catch y gestiona el rechazo de forma elegante.

Resumen

WebRTC proporciona al navegador comunicación verdadera de igual a igual con audio, video y datos. Usa getUserMedia para capturar medios, RTCPeerConnection para negociar y mantener la conexión, y RTCDataChannel para datos arbitrarios. WebRTC no proporciona señalización — intercambias las ofertas/respuestas SDP y los candidatos ICE tú mismo, normalmente a través de WebSockets, y configuras servidores STUN/TURN para atravesar NAT. Con esas piezas en su lugar, puedes construir videollamadas, compartición de pantalla y colaboración en tiempo real completamente en el navegador.

Práctica

Práctica
¿Cuáles de las siguientes son capacidades reales de WebRTC?
¿Cuáles de las siguientes son capacidades reales de WebRTC?
Was this page helpful?