Introdução ao WebRTC para aplicações peer-to-peer

1. Fundamentos do WebRTC e Comunicação Peer-to-Peer

WebRTC (Web Real-Time Communication) é uma tecnologia open-source que permite comunicação em tempo real diretamente entre navegadores e aplicações mobile sem a necessidade de plugins ou software adicional. Desenvolvido pelo W3C e IETF, o WebRTC revolucionou a forma como aplicações web implementam videoconferência, compartilhamento de arquivos e jogos em tempo real.

A arquitetura peer-to-peer (P2P) difere fundamentalmente do modelo cliente-servidor tradicional. Enquanto no modelo cliente-servidor todo o tráfego passa por um servidor central, no P2P os dados fluem diretamente entre os participantes. As vantagens incluem baixa latência (crítica para aplicações em tempo real), redução de custos de servidor e maior escalabilidade. Os principais desafios envolvem NAT traversal (atravessar firewalls e roteadores) e segurança da comunicação direta.

Os três componentes essenciais do WebRTC são:
- getUserMedia: captura áudio e vídeo do dispositivo local
- RTCPeerConnection: gerencia a conexão peer-to-peer e transmite mídia
- RTCDataChannel: permite comunicação de dados arbitrários entre peers

2. Captura e Manipulação de Mídia Local

O acesso à câmera e microfone é feito através da API getUserMedia. Exemplo básico:

navigator.mediaDevices.getUserMedia({
  video: { width: 1280, height: 720, frameRate: 30 },
  audio: { echoCancellation: true, noiseSuppression: true }
}).then(stream => {
  // Atribuir stream a um elemento <video>
  document.getElementById('localVideo').srcObject = stream;
}).catch(error => {
  console.error('Erro ao acessar mídia:', error);
  // Fallback: exibir mensagem para o usuário
});

Para parar tracks específicas:

const tracks = stream.getTracks();
tracks.forEach(track => track.stop());

Tratamento de erros é crucial. Quando o usuário nega permissão, o erro NotAllowedError é disparado. Uma boa prática é oferecer fallbacks visuais e instruções claras.

3. Estabelecimento da Conexão Peer-to-Peer com Sinalização

A sinalização é o processo de troca de metadados entre peers antes da conexão direta. Ela não faz parte do WebRTC, sendo implementada externamente (WebSocket, SSE ou até mesmo polling). O servidor de sinalização coordena a troca de:

  1. Oferta SDP (Session Description Protocol): descrição das capacidades de mídia do peer que inicia
  2. Resposta SDP: resposta do peer remoto
  3. Candidatos ICE: endereços de rede possíveis para conexão

Exemplo de mensagem JSON para sinalização via WebSocket:

// Enviar oferta
{
  "type": "offer",
  "sdp": "v=0\no=- 123456 2 IN IP4 127.0.0.1\n..."
}

// Receber candidato ICE
{
  "type": "candidate",
  "candidate": "candidate:1 1 UDP 2122252543 192.168.1.10 54321 typ host"
}

4. Mecanismos de NAT Traversal e Conexão Direta

ICE (Interactive Connectivity Establishment) é o framework que descobre o melhor caminho entre peers. Utiliza:

  • STUN (Session Traversal Utilities for NAT): servidores públicos que ajudam o peer a descobrir seu endereço público (candidato srflx)
  • TURN (Traversal Using Relays around NAT): servidor relay usado quando conexão direta falha

Os tipos de candidatos ICE, em ordem de prioridade:
1. host: endereço local (mais rápido)
2. srflx: endereço público refletido via STUN
3. relay: via servidor TURN (mais lento, último recurso)

Gerenciamento de eventos:

peerConnection.onicecandidate = event => {
  if (event.candidate) {
    // Enviar candidato ao peer remoto via sinalização
    signalingChannel.send(JSON.stringify({
      type: 'candidate',
      candidate: event.candidate
    }));
  }
};

peerConnection.oniceconnectionstatechange = () => {
  console.log('Estado ICE:', peerConnection.iceConnectionState);
  // Estados: 'new', 'checking', 'connected', 'completed', 'disconnected', 'failed', 'closed'
};

5. Transmissão de Mídia em Tempo Real

Adicionar streams de mídia à conexão:

// Peer que envia
localStream.getTracks().forEach(track => {
  peerConnection.addTrack(track, localStream);
});

// Peer que recebe
peerConnection.ontrack = event => {
  document.getElementById('remoteVideo').srcObject = event.streams[0];
};

Codecs suportados incluem Opus (áudio), VP8/VP9/H.264 (vídeo). A negociação ocorre automaticamente via SDP. Para controle de qualidade:

// Obter estatísticas
peerConnection.getStats().then(stats => {
  stats.forEach(report => {
    if (report.type === 'outbound-rtp') {
      console.log('Bitrate:', report.bitrateMean);
    }
  });
});

6. Comunicação de Dados com RTCDataChannel

RTCDataChannel permite enviar dados arbitrários (texto, binário) entre peers. Exemplo de criação:

// Criar canal confiável e ordenado
const dataChannel = peerConnection.createDataChannel('chat', {
  ordered: true,
  maxRetransmits: 3  // 0 para confiável, null para ilimitado
});

dataChannel.onopen = () => console.log('Canal aberto');
dataChannel.onmessage = event => console.log('Mensagem:', event.data);
dataChannel.onerror = error => console.error('Erro:', error);

// Enviar mensagem
dataChannel.send('Olá, peer!');

// Enviar dados binários
const buffer = new ArrayBuffer(1024);
dataChannel.send(buffer);

Modos de entrega:
- reliable/ordered: garantia de entrega e ordem (TCP-like)
- unreliable/unordered: sem garantias (UDP-like), ideal para jogos

7. Segurança, Privacidade e Boas Práticas

WebRTC exige criptografia obrigatória:
- DTLS (Datagram Transport Layer Security): protege canais de dados
- SRTP (Secure Real-time Transport Protocol): protege streams de mídia

Privacidade:
- Sempre solicitar consentimento explícito antes de acessar câmera/microfone
- Oferecer opção de mascaramento de mídia (desfoque de fundo, avatar virtual)
- Respeitar políticas de mesma origem (same-origin policy)

Depuração:
- Use chrome://webrtc-internals para diagnóstico detalhado
- Monitore logs de conexão e implemente reconexão automática

peerConnection.onconnectionstatechange = () => {
  if (peerConnection.connectionState === 'failed') {
    // Tentar reconexão
    setTimeout(restartConnection, 3000);
  }
};

Referências