O Google tem o compromisso de promover a igualdade racial para as comunidades negras. Saiba como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

Introdução às conexões de pares

As conexões ponto a ponto são a parte das especificações WebRTC que trata da conexão de dois aplicativos em computadores diferentes para se comunicarem usando um protocolo ponto a ponto. A comunicação entre pares pode ser de vídeo, áudio ou dados binários arbitrários (para clientes que suportam a API RTCDataChannel ). Para descobrir como dois pares podem se conectar, ambos os clientes precisam fornecer uma configuração do ICE Server. Este é um servidor STUN ou TURN, e sua função é fornecer candidatos ICE a cada cliente, que é então transferido para o par remoto. Essa transferência de candidatos ICE é comumente chamada de sinalização.

Sinalização

A especificação WebRTC inclui APIs para comunicação com um servidor ICE (Internet Connectivity Establishment), mas o componente de sinalização não faz parte dele. A sinalização é necessária para que dois pontos compartilhem como devem se conectar. Normalmente, isso é resolvido por meio de uma API da Web baseada em HTTP regular (ou seja, um serviço REST ou outro mecanismo RPC) onde os aplicativos da Web podem retransmitir as informações necessárias antes que a conexão de mesmo nível seja iniciada.

O fragmento de código a seguir mostra como esse serviço de sinalização fictício pode ser usado para enviar e receber mensagens de forma assíncrona. Isso será usado nos exemplos restantes neste guia, quando necessário.

// 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!');

A sinalização pode ser implementada de muitas maneiras diferentes e a especificação WebRTC não dá preferência a nenhuma solução específica.

Iniciando conexões de pares

Cada conexão de mesmo nível é controlada por um objeto RTCPeerConnection . O construtor dessa classe usa um único objeto RTCConfiguration como parâmetro. Este objeto define como a conexão de mesmo nível é configurada e deve conter informações sobre os servidores ICE a serem usados.

Uma vez que o RTCPeerConnection é criado, precisamos criar uma oferta ou resposta SDP, dependendo se somos o ponto de chamada ou o ponto de recebimento. Depois que a oferta ou resposta SDP é criada, ela deve ser enviada ao peer remoto por meio de um canal diferente. A passagem de objetos SDP para pontos remotos é chamada de sinalização e não é coberta pela especificação WebRTC.

Para iniciar a configuração da conexão de mesmo nível do lado da chamada, criamos um objeto RTCPeerConnection e, em seguida, chamamos createOffer() para criar um objeto RTCSessionDescription . Esta descrição de sessão é definida como a descrição local usando setLocalDescription() e é então enviada pelo nosso canal de sinalização para o lado receptor. Também configuramos um ouvinte para nosso canal de sinalização para quando uma resposta à nossa descrição de sessão oferecida for recebida do 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});
}

No lado do recebimento, esperamos por uma oferta recebida antes de criar nossa instância RTCPeerConnection . Feito isso, definimos a oferta recebida usando setRemoteDescription() . Em seguida, chamamos createAnswer() para criar uma resposta à oferta recebida. Essa resposta é definida como a descrição local usando setLocalDescription() e, em seguida, enviada para o lado da chamada por nosso servidor de sinalização.

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});
    }
});

Depois que os dois pares tiverem definido as descrições da sessão local e remota, eles conhecerão os recursos do par remoto. Isso não significa que a conexão entre os pares esteja pronta. Para que isso funcione, precisamos coletar os candidatos ICE em cada par e transferir (pelo canal de sinalização) para o outro par.

Candidatos ICE

Antes que dois pares possam se comunicar usando WebRTC, eles precisam trocar informações de conectividade. Como as condições da rede podem variar dependendo de vários fatores, um serviço externo geralmente é usado para descobrir os possíveis candidatos para se conectar a um par. Este serviço é denominado ICE e está usando um servidor STUN ou TURN. STUN significa Session Traversal Utilities for NAT e geralmente é usado indiretamente na maioria dos aplicativos WebRTC.

TURN (Traversal Using Relay NAT) é a solução mais avançada que incorpora os protocolos STUN e a maioria dos serviços comerciais baseados em WebRTC usam um servidor TURN para estabelecer conexões entre pares. A API WebRTC suporta STUN e TURN diretamente e é reunida sob o termo mais completo Estabelecimento de Conectividade com a Internet. Ao criar uma conexão WebRTC, geralmente fornecemos um ou vários servidores ICE na configuração para o objeto RTCPeerConnection .

Trickle ICE

Depois que um objeto RTCPeerConnection é criado, a estrutura subjacente usa os servidores ICE fornecidos para reunir candidatos para o estabelecimento de conectividade (candidatos ICE). O evento icegatheringstatechange on RTCPeerConnection sinaliza em qual estado a coleta de ICE está ( new , gathering ou complete ).

Embora seja possível para um par esperar até que a coleta de ICE seja concluída, geralmente é muito mais eficiente usar uma técnica de "gelo gotejante" e transmitir cada candidato ICE ao par remoto à medida que é descoberto. Isso reduzirá significativamente o tempo de configuração para a conectividade de pares e permitirá que uma chamada de vídeo seja iniciada com menos atrasos.

Para reunir candidatos ICE, basta adicionar um ouvinte para o evento icecandidate . O RTCPeerConnectionIceEvent emitido nesse ouvinte conterá a propriedade do candidate que representa um novo candidato que deve ser enviado ao par remoto (consulte Sinalização).

// 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);
        }
    }
});

Conexão estabelecida

Assim que os candidatos ICE estiverem sendo recebidos, devemos esperar que o estado de nossa conexão de mesmo nível mude para um estado conectado. Para detectar isso, adicionamos um ouvinte ao nosso RTCPeerConnection onde ouvimos os eventos connectionstatechange .

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

Documentação da API RTCPeerConnection