
Olá, comunidade!
Há um tempo eu publiquei aqui no DEV um artigo apresentando o SpechPhone, um softphone SIP web open-source feito com PHP, Swoole e WebSockets, com uma proposta meio fora da curva:
criar um softphone web sem depender de WebRTC.
Na primeira versão, o foco estava em provar que era possível fazer chamadas SIP pelo navegador usando um backend PHP assíncrono, controlando sinalização SIP, áudio PCM e transporte em tempo real com Swoole.
Agora o projeto deu um salto importante.
O SpechPhone deixou de ser apenas uma demonstração de discagem web e passou a caminhar para uma arquitetura mais completa de softphone SIP, com:
- recebimento de chamadas inbound;
- controle de estado em tempo real;
- bridge de mídia RTP ↔ PCM;
- suporte a SIP MESSAGE;
- interface de chat integrada;
- melhorias no áudio via WebSocket;
- controle de volume dinâmico;
- arquitetura mais limpa para chamadas ativas.
E o mais importante: ainda sem WebRTC no caminho da mídia.
Repositório:
https://github.com/spechshop/spechphone
O que mudou nesta nova fase?
A primeira versão do SpechPhone já conseguia iniciar chamadas, registrar conta SIP, configurar codec e transportar áudio entre o navegador e o backend.
Mas ainda faltava uma parte essencial para um softphone de verdade:
receber chamadas.
Nesta atualização, a branch inbound introduz um fluxo mais completo para chamadas recebidas, incluindo tratamento de INVITE, ACK, CANCEL e BYE.
Isso muda bastante a natureza do projeto.
Antes ele era um discador web experimental.
Agora ele começa a se comportar como um endpoint SIP real.
Recebimento de chamadas inbound
O fluxo inbound funciona mais ou menos assim:
- O usuário configura e registra sua conta SIP no SpechPhone.
- O
server.phpescuta SIP via UDP na porta4000. - Quando chega um
INVITE, o backend identifica o usuário de destino. - O navegador recebe um evento em tempo real informando a chamada recebida.
- Ao aceitar, o servidor responde com
200 OKcontendo SDP local. - A mídia RTP é ligada à ponte interna RTP ↔ PCM.
- O áudio chega ao navegador via WebSocket.
- Ao desligar,
BYE/CANCELlimpam o estado da chamada.
Em termos práticos, o SpechPhone agora consegue tocar no navegador quando uma chamada SIP chega.
Pequeno detalhe técnico: isso parece simples escrito em oito linhas, mas no mundo SIP cada header tem autoestima própria. Se errar To-tag, Call-ID, CSeq ou rota reversa, o softphone vira decoração digital.
CallState: estado compartilhado com Swoole Table
Uma das mudanças importantes foi a introdução de um gerenciador de estado para chamadas.
O SpechPhone agora usa estruturas em memória com Swoole Table para rastrear:
- chamadas recebidas;
- chamadas ativas;
- bindings SIP;
- usuário SIP associado ao navegador;
- IP/porta RTP remoto;
- codec negociado;
- worker dono da chamada;
- status da sessão.
A ideia é simples: em um servidor assíncrono, principalmente com múltiplos workers, não dá para depender só de variável local solta no vento.
O CallState vira uma espécie de “quadro branco compartilhado” do runtime.
Ele mantém informações como:
CallState::$incomingCalls;
CallState::$activeCalls;
CallState::$sipBindings;
Isso permite que handlers diferentes saibam se existe uma chamada tocando, se ela já foi aceita, qual usuário pertence àquela chamada e como encerrar tudo corretamente.
Esse tipo de controle é essencial para eventos como:
- aceitar chamada;
- rejeitar chamada;
- desligar;
- receber
BYE; - lidar com timeout RTP;
- sincronizar múltiplas abas abertas no navegador.
Bridge RTP ↔ PCM: o coração da mídia
A parte mais interessante continua sendo a mídia.
O SpechPhone não envia RTP diretamente para o navegador e não depende do WebRTC para negociar ICE, STUN, TURN ou DTLS-SRTP.
A arquitetura segue outro caminho:
SIP/RTP peer
↓
RTP UDP
↓
PHP + Swoole + libspech
↓
PCM interno
↓
WebSocket de áudio
↓
Browser
E o caminho inverso também existe:
Microfone do navegador
↓
PCM via WebSocket
↓
audio.php
↓
UDP interno
↓
encode para codec SIP
↓
RTP para o peer remoto
A classe CallMediaBridge centraliza boa parte desse fluxo.
Ela cria um socket UDP local para conversar com o audio.php, registra callbacks para receber PCM decodificado e inicia corrotinas para o caminho:
- RTP → decode → PCM → navegador;
- navegador → PCM → encode → RTP.
Essa separação deixa a arquitetura mais clara: o plano SIP não precisa carregar toda a responsabilidade da mídia nas costas.
audio.php como servidor dedicado de áudio
Outra decisão arquitetural importante foi manter o audio.php como servidor dedicado para a ponte de áudio.
Ele atua como ponto intermediário entre:
- WebSocket do navegador;
- UDP interno;
- chamadas ativas;
- buffers PCM;
- frequência de áudio;
- controle de reconexão.
Na prática, isso ajuda a isolar a mídia da sinalização.
O server.php cuida do HTTP/WSS/SIP/control plane.
O audio.php cuida da parte mais ingrata: áudio em tempo real.
É aquela divisão saudável: um cuida do drama SIP, o outro cuida do chiado existencial do PCM.
Codecs suportados
O SpechPhone continua com foco em controle direto dos codecs.
A depender do ambiente e das extensões disponíveis, o projeto trabalha com:
- PCMA;
- PCMU;
- G.729;
- L16;
- Opus;
- telephone-event / DTMF RFC2833.
A negociação usa SDP remoto para escolher o codec compatível e gerar uma resposta local.
A vantagem dessa abordagem é ter controle total do pipeline.
O navegador não precisa suportar o codec SIP do tronco. Ele pode trabalhar com PCM, enquanto o backend faz a conversão necessária para o mundo VoIP.
Isso abre espaço para integrações mais avançadas no futuro, como:
- gravação;
- transcrição;
- VAD;
- agente de voz;
- análise de áudio;
- filtros;
- mixagem;
- monitoramento de volume;
- detecção de fala.
SIP MESSAGE e chat integrado
Outra novidade forte é o suporte a mensagens SIP.
O SpechPhone agora tem um caminho integrado para envio e recebimento de mensagens de texto usando MESSAGE.
No lado do backend, existe um armazenamento simples em:
/data/spechphone/messages.json
Ele mantém:
- conversas;
- histórico;
- mensagens não lidas;
- participantes;
- última mensagem;
- eventos em tempo real.
Quando uma nova mensagem chega, o backend pode empurrar um evento WebSocket para o cliente conectado.
Isso transforma o SpechPhone em algo além de um discador.
Ele começa a virar uma interface SIP web completa: chamada + mensagem + presença futura + controle de conta.
A interface de mensagens ainda é simples, mas já cria uma base interessante para comunicação em tempo real dentro do próprio navegador.
Interface mais modular
A UI também evoluiu.
Agora o projeto organiza melhor as áreas principais:
- discador;
- chamadas;
- mensagens;
- configurações de áudio;
- configuração SIP;
- notificações;
- timers;
- medidores de sinal;
- barra de chamada ativa.
Algumas capturas da nova fase:
Melhorias recentes no áudio
As versões recentes também trouxeram melhorias práticas no áudio e na experiência da chamada:
- controle de volume dinâmico com
GainNode; - sliders visuais para microfone e retorno;
- persistência de configurações em
localStorage; - melhorias no buffer PCM;
- validação de codec/frequência;
- controle de reconexão;
- logs mais ricos no client e no server;
- limpeza de conexões antigas;
- redução de inconsistências em chamadas WebSocket.
Essas mudanças são menos chamativas que “agora recebe chamada”, mas são justamente o tipo de ajuste que separa demo bonita de ferramenta utilizável.
Áudio em tempo real é cruel: um buffer mal-humorado e o usuário já acha que está falando de dentro de uma lata de sardinha.
Por que não WebRTC?
Essa pergunta sempre aparece.
O SpechPhone não é uma tentativa de dizer que WebRTC é ruim.
WebRTC é excelente.
Mas ele também traz uma pilha grande:
- ICE;
- STUN;
- TURN;
- SDP próprio;
- codecs controlados pelo browser;
- políticas de mídia;
- NAT traversal;
- comportamento diferente entre navegadores;
- dependências que nem sempre fazem sentido em uma infraestrutura SIP já existente.
O SpechPhone segue outra filosofia:
se o servidor já fala SIP e RTP, então o navegador pode ser apenas a interface, e o backend controla a mídia.
Isso dá mais trabalho?
Sim.
Dá mais controle?
Muito.
É uma abordagem para quem quer entender e controlar a pilha inteira, do INVITE ao pacote RTP.
Arquitetura resumida
Browser
├── Interface Web
├── WebSocket de controle
└── WebSocket de áudio PCM
│
▼
server.php
├── HTTPS/WSS
├── SIP UDP :4000
├── roteamento de eventos
├── controle de chamadas
├── CallState / Swoole Tables
└── integração com libspech
│
▼
audio.php
├── WebSocket de áudio
├── UDP interno :9600
├── buffers PCM
├── relay de áudio
└── ponte com chamadas ativas
│
▼
SIP/RTP peer
├── Asterisk
├── FreeSWITCH
├── OpenSIPS
├── trunk SIP
└── provedor VoIP
Instalação básica
git clone https://github.com/spechshop/spechphone
cd spechphone
git clone https://github.com/spechshop/libspech
wget https://github.com/spechshop/pcg729/releases/download/PCG729/php
sudo mv php /usr/local/bin/php
sudo chmod +x /usr/local/bin/php
git submodule update --init --recursive
cp .env.example .env
Depois configure sua chave:
SPECH_VAULT_KEY_HEX=sua_chave_aqui
E rode os servidores:
php server.php
Em outro terminal:
php audio.php
Status do projeto
O SpechPhone ainda está em desenvolvimento ativo.
A branch inbound já é altamente funcional, mas ainda deve ser tratada como experimental para produção.
O foco agora é endurecer a base:
- melhorar estabilidade inbound;
- refinar tratamento de NAT;
- lapidar encerramento de chamadas;
- melhorar compatibilidade com PBXs;
- evoluir o chat SIP;
- preparar o terreno para recursos de mídia mais avançados.
Contribuições
O projeto é open-source e qualquer contribuição é bem-vinda.
Você pode ajudar com:
- testes com Asterisk, FreeSWITCH, OpenSIPS e provedores SIP;
- issues com logs reais;
- melhorias na UI;
- ajustes de compatibilidade SIP;
- melhorias no buffer de áudio;
- documentação;
- exemplos de configuração;
- testes de codecs.
Repositório:
https://github.com/spechshop/spechphone
Se o projeto te interessar, uma estrela no GitHub também ajuda bastante.
Open-source vive de código, café e pequenas doses de validação social. Principalmente café.
Conclusão
O SpechPhone começou como uma provocação técnica:
será que dá para fazer um softphone SIP web em PHP, com Swoole, sem WebRTC?
A resposta inicial foi: sim, dá.
Agora a nova pergunta é outra:
dá para transformar isso em um softphone web SIP realmente utilizável?
Com chamadas inbound, bridge RTP ↔ PCM, controle de estado, áudio em tempo real e SIP MESSAGE integrado, o projeto chegou em uma fase muito mais interessante.
Ainda tem chão pela frente, mas a base ficou mais séria.
E, sinceramente, ver PHP segurando SIP, RTP, PCM, WebSocket e chat em tempo real no mesmo ecossistema é aquele tipo de insanidade técnica que dá gosto de construir.
Até a próxima atualização.
United States
NORTH AMERICA
Related News
UCP Variant Data: The #1 Reason Agent Checkouts Fail
7h ago
Amazon Employees Are 'Tokenmaxxing' Due To Pressure To Use AI Tools
21h ago
How Braze’s CTO is rethinking engineering for the agentic area
10h ago

Décryptage technique : Comment builder un téléchargeur de vidéos Reddit performant (DASH, HLS & WebAssembly)
17h ago
How AI Reduced Manual Driver Verification by 75% — Operations Case Study. Part 2
4h ago


