Signaling Server — é um componente servidor da infraestrutura WebRTC que facilita a troca de metadados entre pares para estabelecer e encerrar uma conexão. Ao contrário do tráfego de mídia, a sinalização pode ser transmitida por qualquer protocolo — WebSocket, HTTP, XMPP ou SIP. De acordo com MDN Web Docs, 2024, a sinalização é um componente obrigatório de qualquer aplicação WebRTC, pois o protocolo não define um método específico para troca de mensagens de sinalização.
Principais conclusões
Signaling Server — é um serviço de rede responsável por coordenar o processo de estabelecimento de uma conexão WebRTC entre dois ou mais pares. Ele não transmite dados de mídia (áudio, vídeo, dados do DataChannel), apenas as informações de controle necessárias para descoberta de pares e negociação de parâmetros de conexão. Após o estabelecimento bem-sucedido de um canal P2P, o Signaling Server pode não ser mais necessário, mas em algumas arquiteturas ele permanece para a troca subsequente de sinais (por exemplo, encerramento de chamada, adição de participantes).
A arquitetura de sinalização inclui três componentes: Signaling Server, Signal Channel (protocolo de transporte entre cliente e servidor) e API do cliente (geralmente integrada na pilha WebRTC do navegador). A especificação WebRTC (W3C, 2024) intencionalmente não padroniza o protocolo de sinalização — os desenvolvedores podem escolher qualquer transporte adequado para sua aplicação. Esta abordagem flexível permite usar WebSocket para aplicações web, XMPP para sistemas de chat ou SIP para integração com infraestrutura de telecomunicações.
Antes de estabelecer uma conexão WebRTC, os pares devem trocar três tipos de mensagens: descrições de sessão (offer e answer), candidatos ICE e informações de término/modificação de sessão. O Signaling Server roteia essas mensagens entre os pares usando identificadores de sala ou usuário para endereçamento. O padrão típico é criar uma “sala” onde dois participantes se conectam, e o servidor retransmite as mensagens de cada participante apenas para seu interlocutor.
Signaling Server implementa o seguinte protocolo típico de estabelecimento de conexão WebRTC. Os pares se conectam ao servidor via WebSocket (ou outro transporte) e se registram em uma sala. O Par A (iniciador) cria uma oferta (descrição SDP do fluxo de mídia de saída) através de RTCPeerConnection.createOffer(), define-a como descrição local e a envia para o Signaling Server. O servidor retransmite a oferta ao Par B. O Par B recebe a oferta, define-a como descrição remota, cria uma resposta através de createAnswer(), define-a como descrição local e a envia de volta através do servidor. Este processo é chamado de SDP Offer/Answer.
Em paralelo com a troca SDP, cada par coleta candidatos ICE (host, srflx, relay) e os envia através do Signaling Server para o outro par. O par remoto adiciona os candidatos recebidos através de RTCPeerConnection.addIceCandidate(). O processo ICE testa todas as combinações de candidatos para encontrar um caminho funcional. Assim que um caminho funcional é encontrado (geralmente em 1–5 segundos), o tráfego de mídia começa a fluir diretamente entre os pares, e o Signaling Server não participa mais da transmissão de dados — seu papel termina até o próximo evento de controle (encerramento de chamada, mudança de qualidade de fluxo).
Para endereçamento de mensagens, o Signaling Server utiliza um mecanismo de salas (rooms) ou canais. Cada nova sessão WebRTC cria uma sala única com um identificador (geralmente UUID). O iniciador cria a sala e aguarda a conexão do segundo par. O segundo par entra na sala usando o ID recebido através de um canal externo (por exemplo, um link de convite). O servidor mantém um mapa de salas, onde cada ID corresponde a uma lista de clientes conectados. Quando o número de participantes atinge dois, o servidor começa a retransmitir mensagens de sinalização entre eles.
Signaling Server pode usar diferentes protocolos de transporte, cada um com suas próprias vantagens e desvantagens. A escolha do protocolo depende do tipo de aplicação, restrições de infraestrutura e requisitos de compatibilidade. Abaixo estão os protocolos mais comuns e suas características.
| Protocolo | Transporte | Vantagens | Desvantagens |
|---|---|---|---|
| WebSocket | TCP | Full-duplex, baixa latência, embutido em navegadores | Complexidade de escalabilidade, bloqueio de proxy |
| HTTP/SSE | TCP | Compatível com qualquer infraestrutura, simples de implementar | Apenas unidirecional (servidor-cliente), requer Polling |
| XMPP | TCP | Padronizado, suporte a autenticação, extensível | Excessivo para cenários simples, sobrecarga XML |
| SIP | UDP/TCP | Integração com infraestrutura VoIP e telefônica | Complexo, não nativo para navegadores |
| MQTT | TCP | Leve, funciona em ambientes IoT, publish/subscribe | Requer um broker, latência adicional |
WebSocket é o protocolo mais popular para Signaling Server em aplicações web. Ele fornece comunicação full-duplex, importante para a troca assíncrona de candidatos SDP e ICE, e é nativamente suportado por todos os navegadores modernos através da API WebSocket. Implementações de servidor WebSocket estão disponíveis em todas as plataformas populares (Node.js, Python, Java, Go). Para aplicações com milhões de usuários, soluções WebSocket escaláveis baseadas em Redis Pub/Sub ou Kafka são usadas para sincronizar entre instâncias do Signaling Server.
Vamos ver uma implementação simples de Signaling Server em Node.js usando a biblioteca ws (WebSocket) e o servidor HTTP integrado. O servidor suporta registro de usuários, criação de salas e retransmissão de mensagens entre participantes.
const WebSocket = require("ws");
const server = new WebSocket.Server({ port: 8080 });
const rooms = new Map();
server.on("connection", (ws) => {
ws.roomId = null;
ws.on("message", (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "join":
handleJoin(ws, msg.roomId);
break;
case "offer":
case "answer":
case "ice-candidate":
relayToPeer(ws, msg);
break;
case "leave":
handleLeave(ws);
break;
}
});
ws.on("close", () => handleLeave(ws));
});
function handleJoin(ws, roomId) {
if (!rooms.has(roomId)) {
rooms.set(roomId, []);
}
const room = rooms.get(roomId);
room.push(ws);
ws.roomId = roomId;
if (room.length === 2) {
room[0].send(JSON.stringify({ type: "peer-joined" }));
room[1].send(JSON.stringify({ type: "peer-joined" }));
}
}
function relayToPeer(sender, msg) {
const room = rooms.get(sender.roomId);
if (!room) return;
room.forEach(peer => {
if (peer !== sender && peer.readyState === WebSocket.OPEN) {
peer.send(JSON.stringify(msg));
}
});
}
function handleLeave(ws) {
if (!ws.roomId) return;
const room = rooms.get(ws.roomId);
if (!room) return;
const idx = room.indexOf(ws);
if (idx !== -1) room.splice(idx, 1);
if (room.length === 0) rooms.delete(ws.roomId);
}
Este Signaling Server implementa a funcionalidade básica: conexão a uma sala, retransmissão de mensagens WebRTC (offer, answer, ice-candidate) entre dois pares e gerenciamento de desconexões. O servidor usa um Map para armazenar salas com clientes WebSocket conectados. A função relayToPeer envia uma mensagem a todos os participantes da sala, exceto o remetente. Para produção, será necessário adicionar validação de tipos de mensagem, tratamento de erros de análise JSON e um mecanismo heartbeat para detectar conexões interrompidas.
No lado do cliente, o Signaling Server é integrado através da API WebSocket do navegador. O cliente estabelece uma conexão com o servidor, envia uma solicitação para entrar em uma sala e depois processa as mensagens WebRTC recebidas, passando-as para o RTCPeerConnection através de setRemoteDescription() e addIceCandidate(). O código do cliente também envia seus próprios candidatos SDP e ICE ao servidor, obtidos do RTCPeerConnection através do evento onicecandidate e após criar a oferta/resposta.
Signaling Server transmite dois tipos principais de metadados: SDP (Session Description Protocol) e candidatos ICE. O SDP descreve os parâmetros do fluxo de mídia — codecs, taxa de amostragem, número de canais, direção de transmissão (sendrecv, sendonly, recvonly, inactive). Os candidatos ICE contêm endereços de rede (locais, obtidos de STUN, relay do TURN) pelos quais um par pode ser alcançado para conexão.
O SDP é apresentado em formato de texto contendo seções de sessão e mídia. A parte da sessão descreve parâmetros gerais (ID da sessão, versão, nome), enquanto as seções de mídia descrevem cada fluxo de mídia (áudio, vídeo, DataChannel) com seu codec, porta e protocolo. Os candidatos ICE contêm foundation (identificador de agrupamento), prioridade, endereço IP, porta, tipo (host, srflx, relay) e protocolo (UDP, TCP). Cada candidato também inclui um atributo ufrag (fragmento de nome de usuário) que o vincula a um processo ICE específico.
Trickle ICE acelera significativamente o estabelecimento da conexão WebRTC. Em vez de aguardar a coleta completa de todos os candidatos ICE (que pode levar 2–10 segundos em redes complexas), cada candidato é enviado ao Signaling Server imediatamente após a descoberta. O par remoto recebe o candidato e imediatamente começa o teste de conexão através do framework ICE. Isso reduz o tempo de estabelecimento da conexão para 500–1500 ms na maioria dos casos.
Perguntas frequentes
Signaling Server — é o “coordenador” antes de uma chamada. Ele ajuda dois dispositivos a se encontrarem e concordarem sobre como irão se comunicar. Depois que os dispositivos se “conhecem” e concordam, o servidor não é mais necessário — eles se comunicam diretamente.
WebRTC não define um protocolo de sinalização para que os desenvolvedores possam escolher o transporte mais adequado. O navegador não possui um mecanismo embutido para descobrir outros usuários — esta tarefa é realizada pelo Signaling Server. Ele atua como um “carteiro”, entregando convites e configurações de conexão entre os participantes da chamada.
WebSocket — é a escolha ótima para a maioria das aplicações web: full-duplex, suportado nativamente por navegadores e simples de implementar. Para integração com infraestrutura VoIP existente, escolha SIP. Para aplicativos de chat com recursos avançados, use XMPP. Para cenários IoT, use MQTT.
Para escalar um Signaling Server, use escala horizontal com sincronização via Redis Pub/Sub ou Kafka. Cada instância do servidor lida com sua parte das conexões WebSocket, e um barramento de dados comum é usado para roteamento de mensagens entre servidores. Esta abordagem permite lidar com milhões de sessões de sinalização simultâneas.
O Signaling Server é crítico apenas durante a fase de estabelecimento da conexão. Se o servidor ficar temporariamente indisponível, as chamadas WebRTC ativas continuam — o tráfego de mídia flui diretamente entre os pares. O problema surge apenas ao tentar estabelecer uma nova conexão. Para confiabilidade, use clusterização de servidores e canais de sinalização de backup.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também