Cómo comenzar a usar WebRTC

WebRTC es un nuevo frente en la larga guerra por una Web abierta y sin limitaciones.

Brendan Eich, inventor de JavaScript

Comunicación en tiempo real sin complementos

Imagina un mundo en el que tu teléfono, TV y computadora puedan comunicarse en una plataforma común. Imagina que fuera fácil agregar videochat y el uso compartido de datos entre pares a tu app web. Esa es la visión de WebRTC.

¿Quieres probarlo? WebRTC está disponible en computadoras y dispositivos móviles en Google Chrome, Safari, Firefox y Opera. Un buen punto de partida es la app de videochat simple en appr.tc:

  1. Abre appr.tc en tu navegador.
  2. Haz clic en Unirse para unirte a una sala de chat y permitir que la app use tu cámara web.
  3. Abre la URL que se muestra al final de la página en una pestaña nueva o, mejor aún, en otra computadora.

Inicio rápido

¿No tienes tiempo para leer este artículo o solo quieres ver el código?

Como alternativa, puedes ir directamente al codelab de WebRTC, una guía paso a paso que explica cómo compilar una app de videochat completa, incluido un servidor de señalización simple.

Una breve historia de WebRTC

Uno de los últimos desafíos importantes de la Web es permitir la comunicación humana a través de voz y video: comunicación en tiempo real o RTC, en resumen. La RTC debe ser tan natural en una app web como ingresar texto en una entrada de texto. Sin ella, tu capacidad de innovar y desarrollar nuevas formas de interacción para las personas se limita.

Históricamente, la RTC ha sido corporativa y compleja, lo que requiere tecnologías de audio y video costosas para obtener licencias o desarrollarlas de forma interna. La integración de la tecnología de RTC con el contenido, los datos y los servicios existentes ha sido difícil y lenta, en especial en la Web.

El videochat de Gmail se hizo popular en 2008 y, en 2011, Google presentó Hangouts, que usa Talk (al igual que Gmail). Google compró GIPS, una empresa que desarrolló muchos componentes necesarios para la RTC, como códecs y técnicas de cancelación de eco. Google convirtió en código abierto las tecnologías desarrolladas por GIPS y se asoció con los organismos de estándares relevantes en el Internet Engineering Task Force (IETF) y el World Wide Web Consortium (W3C) para garantizar el consenso de la industria. En mayo de 2011, Ericsson creó la primera implementación de WebRTC.

WebRTC implementó estándares abiertos para la comunicación de datos, audio y video en tiempo real y sin complementos. La necesidad era real:

  • Muchos servicios web usaban RTC, pero necesitaban descargas, apps nativas o complementos. Entre ellos, Skype, Facebook y Hangouts.
  • Descargar, instalar y actualizar complementos es complejo, propenso a errores y molesto.
  • Los complementos son difíciles de implementar, depurar, solucionar problemas, probar y mantener, y pueden requerir licencias y una integración con tecnología compleja y costosa. A menudo, es difícil persuadir a las personas para que instalen complementos en primer lugar.

Los principios rectores del proyecto WebRTC son que sus APIs deben ser de código abierto, gratuitas, estandarizadas, integradas en navegadores web y más eficientes que las tecnologías existentes.

¿Dónde estamos ahora?

WebRTC se usa en varias apps, como Google Meet. WebRTC también se integró en WebKitGTK+ y en apps nativas de Qt.

WebRTC implementa estas tres APIs: - MediaStream (también conocida como getUserMedia) - RTCPeerConnection - RTCDataChannel

Las APIs se definen en estas dos especificaciones:

Las tres APIs son compatibles con Chrome, Safari, Firefox, Edge y Opera en dispositivos móviles y computadoras.

getUserMedia: Para ver demostraciones y código, consulta los ejemplos de WebRTC o prueba los ejemplos increíbles de Chris Wilson que usan getUserMedia como entrada para audio web.

RTCPeerConnection: Para ver una demostración simple y una app de videochat completamente funcional, consulta WebRTC samples Peer connection y appr.tc, respectivamente. Esta app usa adapter.js, un shim de JavaScript que Google mantiene con la ayuda de la comunidad de WebRTC para abstraer las diferencias de navegador y los cambios de especificación.

RTCDataChannel: Para ver esto en acción, consulta los muestrarios de WebRTC y mira una de las demostraciones de canales de datos.

En el codelab de WebRTC, se muestra cómo usar las tres APIs para compilar una app sencilla de videochat y uso compartido de archivos.

Tu primera experiencia con WebRTC

Las apps de WebRTC deben hacer lo siguiente:

  • Transmitir audio, video y otros datos
  • Obtén información de red, como direcciones IP y puertos, y cámbiala con otros clientes de WebRTC (conocidos como pares) para habilitar la conexión, incluso a través de NAT y firewalls.
  • Coordina la comunicación de señalización para informar errores y, también, iniciar o cerrar sesiones.
  • Intercambiar información sobre el contenido multimedia y las capacidades del cliente, como la resolución y los códecs
  • Comunicar audio, video o datos de transmisión

Para adquirir y comunicar datos de transmisión, WebRTC implementa las siguientes APIs:

  • MediaStream obtiene acceso a flujos de datos, como los de la cámara y el micrófono del usuario.
  • RTCPeerConnection habilita las llamadas de audio o video con funciones de encriptación y administración de ancho de banda.
  • RTCDataChannel habilita la comunicación punto a punto de datos genéricos.

(Más adelante, se analizarán en detalle los aspectos de la red y la señalización de WebRTC).

API de MediaStream (también conocida como API de getUserMedia)

La API de MediaStream representa transmisiones de contenido multimedia sincronizadas. Por ejemplo, una transmisión tomada de la entrada de la cámara y el micrófono tiene pistas de audio y video sincronizadas. (No confundas MediaStreamTrack con el elemento <track>, que es algo completamente diferente).

Probablemente, la forma más fácil de comprender la API de MediaStream es verla en acción:

  1. En tu navegador, ve a Muestras de WebRTC getUserMedia.
  2. Abre la consola.
  3. Inspecciona la variable stream, que está en el alcance global.

Cada MediaStream tiene una entrada, que puede ser un MediaStream generado por getUserMedia(), y una salida, que se puede pasar a un elemento de video o a un RTCPeerConnection.

El método getUserMedia() toma un parámetro de objeto MediaStreamConstraints y muestra un Promise que se resuelve en un objeto MediaStream.

Cada MediaStream tiene un label, como 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'. Los métodos getAudioTracks() y getVideoTracks() devuelven un array de MediaStreamTrack.

En el ejemplo de getUserMedia, stream.getAudioTracks() muestra un array vacío (porque no hay audio) y, si se supone que hay una cámara web en funcionamiento conectada, stream.getVideoTracks() muestra un array de un MediaStreamTrack que representa la transmisión de la cámara web. Cada MediaStreamTrack tiene un tipo ('video' o 'audio'), un label (algo como 'FaceTime HD Camera (Built-in)') y representa uno o más canales de audio o video. En este caso, solo hay una pista de video y no hay audio, pero es fácil imaginar casos de uso en los que haya más, como una app de chat que recibe transmisiones de la cámara frontal, la cámara posterior, el micrófono y una app que comparte su pantalla.

Para adjuntar un MediaStream a un elemento de video, configura el atributo srcObject. Anteriormente, se configuraba el atributo src en una URL de objeto creada con URL.createObjectURL(), pero ya no se usa.

getUserMedia también se puede usar como un nodo de entrada para la API de Web Audio:

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

Las apps y extensiones basadas en Chromium también pueden incorporar getUserMedia. Si agregas los permisos audioCapture o videoCapture al manifiesto, se puede solicitar y otorgar el permiso solo una vez durante la instalación. A partir de ese momento, no se le solicita permiso al usuario para acceder a la cámara ni al micrófono.

El permiso solo se debe otorgar una vez para getUserMedia(). La primera vez, se muestra un botón Permitir en la infobar del navegador. A fines de 2015, Chrome dejó de admitir el acceso HTTP a getUserMedia() porque se clasificó como una función potente.

La intención es habilitar un MediaStream para cualquier fuente de datos de transmisión, no solo para una cámara o un micrófono. Esto permitiría la transmisión desde datos almacenados o fuentes de datos arbitrarias, como sensores o otras entradas.

getUserMedia() realmente cobra vida en combinación con otras APIs y bibliotecas de JavaScript:

  • Webcam Toy es una app de cabina de fotos que usa WebGL para agregar efectos extraños y maravillosos a las fotos que se pueden compartir o guardar de forma local.
  • FaceKat es un juego de seguimiento facial compilado con headtrackr.js.
  • ASCII Camera usa la API de Canvas para generar imágenes ASCII.
Imagen ASCII generada por idevelop.ro/ascii-camera
¡Arte ASCII de gUM!

Limitaciones

Las restricciones se pueden usar para establecer valores de resolución de video para getUserMedia(). Esto también permite admitir otras restricciones, como la relación de aspecto, el modo de orientación (cámara frontal o posterior), la velocidad de fotogramas, la altura y el ancho, y un método applyConstraints().

Para ver un ejemplo, consulta WebRTC samples getUserMedia: select resolution.

Si configuras un valor de restricción no permitido, se muestra un DOMException o un OverconstrainedError si, por ejemplo, no está disponible una resolución solicitada. Para ver esto en acción, consulta WebRTC samples getUserMedia: select resolution para ver una demostración.

Captura de pantalla y pestaña

Las apps de Chrome también permiten compartir un video en vivo de una sola pestaña del navegador o de todo el escritorio a través de las APIs de chrome.tabCapture y chrome.desktopCapture. (Para obtener una demostración y más información, consulta Compartir pantalla con WebRTC). El artículo tiene algunos años, pero sigue siendo interesante).

También es posible usar la captura de pantalla como fuente de MediaStream en Chrome con la restricción experimental chromeMediaSource. Ten en cuenta que la captura de pantalla requiere HTTPS y solo debe usarse para el desarrollo, ya que se habilita a través de una marca de línea de comandos, como se explica en esta publicación.

Señalización: Control de sesión, información de red y multimedia

WebRTC usa RTCPeerConnection para comunicar datos de transmisión entre navegadores (también conocidos como pares), pero también necesita un mecanismo para coordinar la comunicación y enviar mensajes de control, un proceso conocido como señalización. WebRTC no especifica los métodos ni los protocolos de señalización. La señalización no forma parte de la API de RTCPeerConnection.

En su lugar, los desarrolladores de apps de WebRTC pueden elegir el protocolo de mensajería que prefieran, como SIP o XMPP, y cualquier canal de comunicación dúplex (de dos vías) adecuado. El ejemplo de appr.tc usa XHR y la API de Channel como mecanismo de señalización. El codelab usa Socket.io que se ejecuta en un servidor de Node.

La señalización se usa para intercambiar tres tipos de información:

  • Mensajes de control de sesión: Para inicializar o cerrar la comunicación y, además, informar errores.
  • Configuración de red: ¿cuáles son la dirección IP y el puerto de tu computadora para el resto del mundo?
  • Funciones multimedia: ¿Qué códecs y resoluciones pueden controlar tu navegador y el navegador con el que se quiere comunicar?

El intercambio de información a través de la señalización debe haberse completado correctamente antes de que pueda comenzar la transmisión punto a punto.

Por ejemplo, imagina que Alice quiere comunicarse con Roberto. Este es un ejemplo de código de la especificación de WebRTC del W3C, que muestra el proceso de señalización en acción. El código supone la existencia de algún mecanismo de señalización creado en el método createSignalingChannel(). Ten en cuenta que, actualmente, RTCPeerConnection tiene un prefijo en Chrome y Opera.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

Primero, Alicia y Roberto intercambian información de red. (La expresión encontrar candidatos hace referencia al proceso de encontrar interfaces de red y puertos con el framework de ICE).

  1. Alice crea un objeto RTCPeerConnection con un controlador onicecandidate, que se ejecuta cuando los candidatos de red están disponibles.
  2. Alice envía datos de candidatos serializados a Roberto a través de cualquier canal de señalización que use, como WebSocket o algún otro mecanismo.
  3. Cuando Roberto recibe un mensaje de candidato de Alicia, llama a addIceCandidate para agregarlo a la descripción del par remoto.

Los clientes de WebRTC (también conocidos como pares, o Alice y Bob en este ejemplo) también deben verificar e intercambiar información de audio y video local y remota, como la resolución y las capacidades de códec. La señalización para intercambiar información de configuración de contenido multimedia se realiza mediante el intercambio de una oferta y una respuesta con el Protocolo de descripción de sesión (SDP):

  1. Alicia ejecuta el método createOffer() de RTCPeerConnection. El resultado de esto se pasa a un RTCSessionDescription: la descripción de la sesión local de Alice.
  2. En la devolución de llamada, Alice establece la descripción local con setLocalDescription() y, luego, envía esta descripción de la sesión a Bob a través de su canal de señalización. Ten en cuenta que RTCPeerConnection no comenzará a recopilar candidatos hasta que se llame a setLocalDescription(). Esto se codifica en el borrador de IETF de JSEP.
  3. Bob establece la descripción que le envió Alice como la descripción remota con setRemoteDescription().
  4. Roberto ejecuta el método createAnswer() RTCPeerConnection y le pasa la descripción remota que obtuvo de Alicia para que se pueda generar una sesión local compatible con la suya. Se pasa un RTCSessionDescription a la devolución de llamada createAnswer(). Roberto la establece como la descripción local y se la envía a Alice.
  5. Cuando Alice obtiene la descripción de la sesión de Roberto, la establece como la descripción remota con setRemoteDescription.
  6. Ping!

Los objetos RTCSessionDescription son objetos blob que cumplen con el protocolo de descripción de sesión (SDP). En forma serializada, un objeto SDP se ve de la siguiente manera:

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

La adquisición y el intercambio de información de red y multimedia se pueden realizar de forma simultánea, pero ambos procesos deben completarse antes de que se pueda iniciar la transmisión de audio y video entre pares.

La arquitectura de oferta/respuesta descrita anteriormente se denomina Protocolo de establecimiento de sesión de JavaScript o JSEP. (Hay una excelente animación que explica el proceso de señalización y transmisión en el video de demostración de Ericsson para su primera implementación de WebRTC).

Diagrama de arquitectura de JSEP
Arquitectura de JSEP

Una vez que se completa correctamente el proceso de señalización, los datos se pueden transmitir directamente de igual a igual, entre el llamador y el llamado, o, si eso falla, a través de un servidor de retransmisión intermediario (más información sobre esto más adelante). La transmisión es la tarea de RTCPeerConnection.

RTCPeerConnection

RTCPeerConnection es el componente de WebRTC que controla la comunicación estable y eficiente de los datos de transmisión entre pares.

El siguiente es un diagrama de arquitectura de WebRTC que muestra el rol de RTCPeerConnection. Como verás, las partes verdes son complejas.

Diagrama de arquitectura de WebRTC
Arquitectura de WebRTC (de webrtc.org)

Desde la perspectiva de JavaScript, lo principal que debes comprender de este diagrama es que RTCPeerConnection protege a los desarrolladores web de la gran cantidad de complejidades que se esconden debajo. Los códecs y protocolos que usa WebRTC realizan una gran cantidad de trabajo para que sea posible la comunicación en tiempo real, incluso a través de redes poco confiables:

  • Ocultación de pérdida de paquetes
  • Cancelación de eco
  • Adaptabilidad del ancho de banda
  • Almacenamiento en búfer de jitter dinámico
  • Control automático de ganancia
  • Reducción y supresión de ruido
  • Limpieza de imágenes

El código anterior del W3C muestra un ejemplo simplificado de WebRTC desde una perspectiva de señalización. A continuación, se incluyen instructivos de dos apps de WebRTC que funcionan. El primero es un ejemplo simple para demostrar RTCPeerConnection y el segundo es un cliente de videochat completamente operativo.

RTCPeerConnection sin servidores

El siguiente código se toma de los muestras de conexión de pares de WebRTC, que tiene RTCPeerConnection y remotos (y video local y remoto) en una página web. Esto no constituye algo muy útil (el llamador y el llamado están en la misma página), pero hace que el funcionamiento de la API de RTCPeerConnection sea un poco más claro, ya que los objetos RTCPeerConnection de la página pueden intercambiar datos y mensajes directamente sin tener que usar mecanismos de señalización intermedios.

En este ejemplo, pc1 representa al par local (llamante) y pc2 representa al par remoto (llamado).

Emisor

  1. Crea un RTCPeerConnection nuevo y agrega la transmisión desde getUserMedia(): ```js // Servers es un archivo de configuración opcional. (Más adelante, se incluye una explicación sobre TURN y STUN). pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. Crea una oferta y configúrala como la descripción local de pc1 y como la descripción remota de pc2. Esto se puede hacer directamente en el código sin usar señalización, ya que el llamador y el llamado están en la misma página: js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

Destinatario

  1. Crea pc2 y, cuando se agregue la transmisión de pc1, muéstrala en un elemento de video: js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

Servidores de API plus de RTCPeerConnection

En el mundo real, WebRTC necesita servidores, por más simples que sean, para que pueda ocurrir lo siguiente:

  • Los usuarios se descubren entre sí y comparten detalles del mundo real, como nombres.
  • Las apps cliente de WebRTC (pares) intercambian información de red.
  • Los pares intercambian datos sobre el contenido multimedia, como el formato y la resolución de video.
  • Las apps cliente de WebRTC atraviesan puertas de enlace NAT y firewalls.

En otras palabras, WebRTC necesita cuatro tipos de funciones del servidor:

  • Comunicación y descubrimiento de usuarios
  • Señalización
  • Recorrido de NAT o firewall
  • Servidores de retransmisión en caso de que falle la comunicación entre pares

La traslación de NAT, las redes punto a punto y los requisitos para compilar una app de servidor para el descubrimiento y la señalización de usuarios exceden el alcance de este artículo. Basta con decir que el framework de ICE usa el protocolo STUN y su extensión, TURN, para permitir que RTCPeerConnection controle la transgresión de NAT y otras irregularidades de red.

ICE es un framework para conectar pares, como dos clientes de videochat. Inicialmente, ICE intenta conectar pares directamente con la latencia más baja posible a través de UDP. En este proceso, los servidores STUN tienen una sola tarea: permitir que un par detrás de una NAT descubra su dirección y puerto públicos. (Para obtener más información sobre STUN y TURN, consulta Cómo compilar los servicios de backend necesarios para una app de WebRTC).

Cómo encontrar candidatos de conexión
Cómo encontrar candidatos para la conexión

Si falla UDP, ICE intenta TCP. Si la conexión directa falla, en particular debido al recorrido de NAT empresarial y a los firewalls, ICE usa un servidor TURN intermediario (de retransmisión). En otras palabras, ICE primero usa STUN con UDP para conectar pares directamente y, si eso falla, recurre a un servidor de retransmisión TURN. La expresión encontrar candidatos se refiere al proceso de encontrar interfaces y puertos de red.

Rutas de datos de WebRTC
Rutas de datos de WebRTC

Justin Uberti, ingeniero de WebRTC, proporciona más información sobre ICE, STUN y TURN en la presentación de WebRTC de Google I/O de 2013. (En las diapositivas de la presentación, se proporcionan ejemplos de implementaciones de servidores TURN y STUN).

Un cliente de chat de video simple

Un buen lugar para probar WebRTC, con señalización y recorrido de NAT/firewall mediante un servidor STUN, es la demostración de videochat en appr.tc. Esta app usa adapter.js, un shim para proteger las apps de los cambios de especificación y las diferencias de prefijos.

El código es deliberadamente detallado en su registro. Consulta la consola para comprender el orden de los eventos. A continuación, se incluye una explicación detallada del código.

Topologías de red

WebRTC, tal como se implementa actualmente, solo admite la comunicación uno a uno, pero se puede usar en situaciones de red más complejas, como con varios pares que se comunican entre sí directamente o a través de una unidad de control multipunto (MCU), un servidor que puede controlar una gran cantidad de participantes y realizar el reenvío de transmisiones de forma selectiva, así como la mezcla o grabación de audio y video.

Diagrama de topología de la unidad de control multipunto
Ejemplo de topología de la unidad de control multipunto

Muchas apps de WebRTC existentes solo demuestran la comunicación entre navegadores web, pero los servidores de puerta de enlace pueden permitir que una app de WebRTC que se ejecuta en un navegador interactúe con dispositivos, como teléfonos (también conocidos como PSTN) y con sistemas de VOIP. En mayo de 2012, Doubango Telecom lanzó el cliente SIP sipml5 de código abierto compilado con WebRTC y WebSocket, que (entre otros usos potenciales) permite realizar videollamadas entre navegadores y apps que se ejecutan en iOS y Android. En Google I/O, Tethr y Tropo demostraron un framework para comunicaciones ante desastres en un maletín con una celda OpenBTS para habilitar las comunicaciones entre teléfonos básicos y computadoras a través de WebRTC. Comunicación telefónica sin operador

Demostración de Tethr/Tropo en Google I/O 2012
Tethr/Tropo: Comunicaciones ante desastres en un maletín

API de RTCDataChannel<

Además del audio y el video, WebRTC admite la comunicación en tiempo real para otros tipos de datos.

La API de RTCDataChannel permite el intercambio de datos arbitrarios entre pares con baja latencia y alta capacidad de procesamiento. Para ver demostraciones de una sola página y aprender a compilar una app de transferencia de archivos simple, consulta los ejemplos de WebRTC y el codelab de WebRTC, respectivamente.

Existen muchos casos de uso potenciales para la API, incluidos los siguientes:

  • Videojuegos
  • Apps de escritorio remoto
  • Chat de texto en tiempo real
  • Transferencia de archivos
  • Redes descentralizadas

La API tiene varias funciones para aprovechar al máximo RTCPeerConnection y permitir una comunicación punto a punto potente y flexible:

  • Aprovechamiento de la configuración de la sesión de RTCPeerConnection
  • Varios canales simultáneos con priorización
  • Semánticas de entrega confiables y poco confiables
  • Seguridad integrada (DTLS) y control de congestión
  • Posibilidad de usarlas con o sin audio o video

La sintaxis es similar a la de WebSocket de forma deliberada, con un método send() y un evento message:

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

La comunicación se produce directamente entre los navegadores, por lo que RTCDataChannel puede ser mucho más rápida que WebSocket, incluso si se requiere un servidor de retransmisión (TURN) cuando falla el orificio para lidiar con firewalls y NAT.

RTCDataChannel está disponible en Chrome, Safari, Firefox, Opera y Samsung Internet. El juego Cube Slam usa la API para comunicar el estado del juego. Juega con un amigo o con el oso. La innovadora plataforma Sharefest habilitó el uso compartido de archivos a través de RTCDataChannel y peerCDN, que ofreció un vistazo de cómo WebRTC podría habilitar la distribución de contenido entre pares.

Para obtener más información sobre RTCDataChannel, consulta el borrador de especificaciones del protocolo de la IETF.

Seguridad

Existen varias formas en que una app o un complemento de comunicación en tiempo real pueden poner en riesgo la seguridad. Por ejemplo:

  • Es posible que se intercepten datos o contenido multimedia no encriptados entre navegadores o entre un navegador y un servidor.
  • Una app podría grabar y distribuir audio o video sin que el usuario lo sepa.
  • Es posible que se instalen software malicioso o virus junto con un complemento o una app aparentemente inocuos.

WebRTC tiene varias funciones para evitar estos problemas:

  • Las implementaciones de WebRTC usan protocolos seguros, como DTLS y SRTP.
  • La encriptación es obligatoria para todos los componentes de WebRTC, incluidos los mecanismos de señalización.
  • WebRTC no es un complemento. Sus componentes se ejecutan en la zona de pruebas del navegador y no en un proceso independiente. Los componentes no requieren una instalación independiente y se actualizan cada vez que se actualiza el navegador.
  • El acceso a la cámara y al micrófono debe otorgarse de forma explícita y, cuando la cámara o el micrófono están en ejecución, la interfaz de usuario lo muestra claramente.

El análisis completo de la seguridad de la transmisión de contenido multimedia está fuera del alcance de este artículo. Para obtener más información, consulta la Propuesta de arquitectura de seguridad de WebRTC que propuso el IETF.

Conclusión

Las APIs y los estándares de WebRTC pueden democratizar y descentralizar las herramientas para la creación de contenido y la comunicación, incluida la telefonía, los juegos, la producción de videos, la creación de música y la recopilación de noticias.

La tecnología no puede ser más revolucionaria que esto.

Como dijo el bloguero Phil Edholm, "En teoría, WebRTC y HTML5 podrían permitir la misma transformación para la comunicación en tiempo real que el navegador original hizo para la información".

Herramientas para desarrolladores

Más información

Estándares y protocolos

Resumen de la compatibilidad con WebRTC

APIs de MediaStream y getUserMedia

  • Chrome para computadoras de escritorio 18.0.1008 y versiones posteriores; Chrome para Android 29 y versiones posteriores
  • Opera 18 y versiones posteriores; Opera para Android 20 y versiones posteriores
  • Opera 12 y Opera Mobile 12 (basados en el motor Presto)
  • Firefox 17 y versiones posteriores
  • Microsoft Edge 16 y versiones posteriores
  • Safari 11.2 y versiones posteriores en iOS, y 11.1 y versiones posteriores en MacOS
  • UC 11.8 y versiones posteriores en Android
  • Samsung Internet 4 y versiones posteriores

API RTCPeerConnection

  • Chrome para computadoras de escritorio 20 y versiones posteriores; Chrome para Android 29 y versiones posteriores (sin marca)
  • Opera 18 y versiones posteriores (activado de forma predeterminada); Opera para Android 20 y versiones posteriores (activado de forma predeterminada)
  • Firefox 22 y versiones posteriores (activado de forma predeterminada)
  • Microsoft Edge 16 y versiones posteriores
  • Safari 11.2 y versiones posteriores en iOS, y 11.1 y versiones posteriores en MacOS
  • Samsung Internet 4 y versiones posteriores

API RTCDataChannel

  • Versión experimental en Chrome 25, pero más estable (y con interoperabilidad con Firefox) en Chrome 26 y versiones posteriores; Chrome para Android 29 y versiones posteriores
  • Versión estable (y con interoperabilidad con Firefox) en Opera 18 y versiones posteriores; Opera para Android 20 y versiones posteriores
  • Firefox 22 y versiones posteriores (activado de forma predeterminada)

Para obtener información más detallada sobre la compatibilidad multiplataforma de las APIs, como getUserMedia y RTCPeerConnection, consulta caniuse.com y el Estado de la plataforma de Chrome.

Las APIs nativas de RTCPeerConnection también están disponibles en la documentación de webrtc.org.