Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Comenzando con las conexiones entre pares

Las conexiones entre pares son parte de las especificaciones de WebRTC que se ocupan de conectar dos aplicaciones en diferentes computadoras para comunicarse utilizando un protocolo de igual a igual. La comunicación entre pares puede ser video, audio o datos binarios arbitrarios (para clientes que admiten la API RTCDataChannel ). Para descubrir cómo se pueden conectar dos pares, ambos clientes deben proporcionar una configuración de servidor ICE. Se trata de un servidor STUN o TURN, y su función es proporcionar candidatos ICE a cada cliente que luego se transfiere al par remoto. Esta transferencia de candidatos a ICE se denomina comúnmente señalización.

Señalización

La especificación WebRTC incluye API para comunicarse con un servidor ICE (Internet Connectivity Establishment), pero el componente de señalización no forma parte de él. La señalización es necesaria para que dos pares compartan cómo deben conectarse. Por lo general, esto se resuelve a través de una API web regular basada en HTTP (es decir, un servicio REST u otro mecanismo RPC) donde las aplicaciones web pueden transmitir la información necesaria antes de que se inicie la conexión entre pares.

El siguiente fragmento de código muestra cómo se puede utilizar este servicio de señalización ficticia para enviar y recibir mensajes de forma asincrónica. Esto se usará en los ejemplos restantes de esta guía cuando sea necesario.

 // Set up an asynchronous communication channel that will be
// used during the peer connection setup
const signalingChannel = new SignalingChannel(remoteClientId);
signalingChannel.addEventListener('message', message => {
    // New message from remote client received
});

// Send an asynchronous message to the remote client
signalingChannel.send('Hello!');
 

La señalización se puede implementar de muchas maneras diferentes, y la especificación WebRTC no prefiere ninguna solución específica.

Iniciando conexiones entre pares

Cada conexión de igual se maneja mediante un objeto RTCPeerConnection . El constructor para esta clase toma un solo objeto RTCConfiguration como parámetro. Este objeto define cómo se configura la conexión entre pares y debe contener información sobre los servidores ICE que se utilizarán.

Una vez que se crea RTCPeerConnection , necesitamos crear una oferta o respuesta SDP, dependiendo de si somos el interlocutor que llama o el que recibe. Una vez que se crea la oferta o respuesta SDP, debe enviarse al par remoto a través de un canal diferente. Pasar objetos SDP a pares remotos se llama señalización y no está cubierto por la especificación WebRTC.

Para iniciar la configuración de la conexión entre pares desde el lado de la llamada, creamos un objeto RTCPeerConnection y luego llamamos a createOffer() para crear un objeto RTCSessionDescription . Esta descripción de sesión se establece como la descripción local utilizando setLocalDescription() y luego se envía a través de nuestro canal de señalización al lado receptor. También configuramos un oyente para nuestro canal de señalización para cuando se recibe una respuesta a nuestra descripción de sesión ofrecida desde el lado receptor.

 async function makeCall() {
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
    const peerConnection = new RTCPeerConnection(configuration);
    signalingChannel.addEventListener('message', async message => {
        if (message.answer) {
            const remoteDesc = new RTCSessionDescription(message.answer);
            await peerConnection.setRemoteDescription(remoteDesc);
        }
    });
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    signalingChannel.send({'offer': offer});
}
 

En el lado receptor, esperamos una oferta entrante antes de crear nuestra instancia RTCPeerConnection . Una vez hecho esto, configuramos la oferta recibida usando setRemoteDescription() . A continuación, llamamos a createAnswer() para crear una respuesta a la oferta recibida. Esta respuesta se establece como la descripción local usando setLocalDescription() y luego se envía al lado de la llamada a través de nuestro servidor de señalización.

 const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
    if (message.offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        signalingChannel.send({'answer': answer});
    }
});
 

Una vez que los dos pares han establecido las descripciones de sesión local y remota, conocen las capacidades del par remoto. Esto no significa que la conexión entre los compañeros esté lista. Para que esto funcione, debemos recopilar los candidatos de ICE en cada par y transferirlos (a través del canal de señalización) al otro par.

Candidatos ICE

Antes de que dos pares puedan comunicarse mediante WebRTC, deben intercambiar información de conectividad. Dado que las condiciones de la red pueden variar dependiendo de una serie de factores, generalmente se utiliza un servicio externo para descubrir los posibles candidatos para conectarse a un par. Este servicio se llama ICE y está utilizando un servidor STUN o TURN. STUN significa Session Traversal Utilities para NAT, y generalmente se usa indirectamente en la mayoría de las aplicaciones WebRTC.

TURN (Traversal Using Relay NAT) es la solución más avanzada que incorpora los protocolos STUN y la mayoría de los servicios comerciales basados ​​en WebRTC utilizan un servidor TURN para establecer conexiones entre pares. La API de WebRTC admite STUN y TURN directamente, y se recopila bajo el término más completo Establecimiento de conectividad a Internet. Al crear una conexión WebRTC, generalmente proporcionamos uno o varios servidores ICE en la configuración para el objeto RTCPeerConnection .

Hielo goteo

Una vez que se crea un objeto RTCPeerConnection , el marco subyacente utiliza los servidores ICE proporcionados para reunir candidatos para el establecimiento de conectividad (candidatos ICE). El evento icegatheringstatechange en RTCPeerConnection señala en qué estado se encuentra la reunión ICE ( new , gathering o complete ).

Si bien es posible que un compañero espere hasta que se complete la reunión de ICE, generalmente es mucho más eficiente usar una técnica de "hielo de goteo" y transmitir cada candidato de ICE al compañero remoto a medida que se descubre. Esto reducirá significativamente el tiempo de configuración para la conectividad entre pares y permitirá que se inicie una videollamada con menos demoras.

Para reunir candidatos de ICE, simplemente agregue un oyente para el evento icecandidate . El RTCPeerConnectionIceEvent emitido en ese oyente contendrá la propiedad del candidate que representa un nuevo candidato que se debe enviar al par remoto (consulte Señalización).

 // Listen for local ICE candidates on the local RTCPeerConnection
peerConnection.addEventListener('icecandidate', event => {
    if (event.candidate) {
        signalingChannel.send({'new-ice-candidate': event.candidate});
    }
});

// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
    if (message.iceCandidate) {
        try {
            await peerConnection.addIceCandidate(message.iceCandidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    }
});
 

Conexión establecida

Una vez que se reciban los candidatos de ICE, debemos esperar que el estado de nuestra conexión entre pares eventualmente cambie a un estado conectado. Para detectar esto, agregamos un oyente a nuestra RTCPeerConnection donde escuchamos los eventos de cambio de estado de connectionstatechange .

 // Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
    if (peerConnection.connectionState === 'connected') {
        // Peers connected!
    }
});
 

Documentación de la API RTCPeerConnection