Reproduzindo Sons com a Web Audio API
Você deseja reproduzir áudio no navegador com controle preciso—agendamento, efeitos, síntese—mas o elemento <audio> não atende às necessidades. A Web Audio API resolve isso, porém sua documentação mistura padrões obsoletos com as melhores práticas atuais. Este artigo esclarece a abordagem moderna para reprodução de som com a Web Audio API, abordando os fundamentos do AudioContext, nós de origem e o modelo de grafo de áudio sem o peso do legado.
Pontos-Chave
- Crie um
AudioContextpor aplicação e sempre trate o estado suspenso comresume()após interação do usuário - Use
AudioBufferSourceNodepara arquivos de áudio pré-carregados eOscillatorNodepara tons sintetizados—ambos são nós de uso único - Evite o obsoleto
ScriptProcessorNode; useAudioWorkletpara processamento de áudio personalizado - Trate o roteamento de dispositivo de saída via
setSinkId()como experimental com suporte incompleto nos navegadores
Entendendo os Fundamentos do AudioContext
Toda aplicação Web Audio começa com um AudioContext. Este objeto gerencia todas as operações de áudio e fornece o relógio para agendamento. Pense nele como o ambiente de execução para seu grafo de áudio.
const audioContext = new AudioContext()
Uma restrição crítica: os navegadores suspendem novos contextos até que ocorra um gesto do usuário. Sempre verifique audioContext.state e chame resume() a partir de um manipulador de clique ou pressionamento de tecla:
button.addEventListener('click', async () => {
if (audioContext.state === 'suspended') {
await audioContext.resume()
}
// Agora é seguro reproduzir áudio
})
Na maioria das aplicações, um único AudioContext é suficiente e recomendado. Criar múltiplos contextos aumenta o uso de recursos e torna o gerenciamento de tempo e sincronização mais difícil. (Veja: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext)
O Modelo de Grafo de Áudio
A Web Audio usa um grafo direcionado de nós. O áudio flui dos nós de origem, através de nós de processamento, até um destino. O audioContext.destination representa a saída padrão—tipicamente os alto-falantes do usuário.
Os nós se conectam através do método connect():
sourceNode.connect(gainNode)
gainNode.connect(audioContext.destination)
Este design modular permite que você insira filtros, controles de ganho ou analisadores em qualquer lugar da cadeia. Desconecte nós com disconnect() ao reconfigurar o grafo.
Nós de Origem para Reprodução de Som
Dois tipos de origem atendem à maioria dos cenários de reprodução.
AudioBufferSourceNode
Para arquivos de áudio pré-carregados, decodifique os dados em um AudioBuffer, depois reproduza-o através de um AudioBufferSourceNode:
const response = await fetch('sound.mp3')
const arrayBuffer = await response.arrayBuffer()
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
const source = audioContext.createBufferSource()
source.buffer = audioBuffer
source.connect(audioContext.destination)
source.start()
Cada AudioBufferSourceNode reproduz uma vez. Crie um novo nó de origem para cada reprodução—eles são leves. O AudioBuffer subjacente é reutilizável.
Note que embora decodeAudioData() suporte promises em navegadores modernos, versões antigas do Safari exigiam a forma de callback. Isso é principalmente uma preocupação de legado, mas ainda relevante para compatibilidade de longo prazo.
OscillatorNode
Para tons sintetizados, use OscillatorNode:
const oscillator = audioContext.createOscillator()
oscillator.type = 'sine'
oscillator.frequency.setValueAtTime(440, audioContext.currentTime)
oscillator.connect(audioContext.destination)
oscillator.start()
oscillator.stop(audioContext.currentTime + 1)
Osciladores também reproduzem uma vez. Agende os tempos de start() e stop() usando audioContext.currentTime para reprodução precisa em nível de amostra.
Discover how at OpenReplay.com.
AudioWorklet vs ScriptProcessor
Para processamento de áudio personalizado, evite ScriptProcessorNode. Ele está obsoleto, executa na thread principal e causa falhas de áudio sob carga.
AudioWorklet é o substituto moderno. Ele executa em uma thread dedicada de renderização de áudio com temporização determinística:
// processor.js
class MyProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
// Processe o áudio aqui
return true
}
}
registerProcessor('my-processor', MyProcessor)
// main.js
await audioContext.audioWorklet.addModule('processor.js')
const workletNode = new AudioWorkletNode(audioContext, 'my-processor')
workletNode.connect(audioContext.destination)
AudioWorklet é suportado em todos os navegadores modernos evergreen. As principais restrições tendem a ser relacionadas ao ambiente (contexto seguro, empacotamento, configuração cross-origin) em vez de falta de suporte à API.
Restrições de Roteamento de Saída da Web Audio
As capacidades de roteamento de saída da API são limitadas e dependem do navegador. Por padrão, o áudio é roteado para audioContext.destination, que mapeia para o dispositivo de saída padrão do sistema.
AudioContext.setSinkId() permite selecionar dispositivos de saída específicos, mas trate isso como experimental e altamente restrito. Requer um contexto seguro (HTTPS), permissão do usuário e cabeçalhos de política de permissões apropriados. Na prática, não está disponível no Safari ou iOS e não deve ser usado como base para troca de alto-falantes multiplataforma.
Para aplicações que requerem seleção de dispositivo de saída, detecte o suporte explicitamente:
if (typeof audioContext.setSinkId === 'function') {
// A presença não garante usabilidade; permissões e políticas ainda podem bloqueá-lo
}
Mesmo quando o método existe, as chamadas podem falhar devido a políticas ou limitações da plataforma. Construa alternativas e comunique essas restrições claramente aos usuários.
Considerações Práticas
Políticas de autoplay bloqueiam áudio até a interação do usuário. Projete sua interface para exigir um clique antes de inicializar a reprodução.
Restrições CORS se aplicam ao buscar arquivos de áudio cross-origin. Garanta cabeçalhos apropriados ou hospede arquivos na mesma origem.
Gerenciamento de memória importa para aplicações pesadas em buffers. Desreferencie objetos AudioBuffer não utilizados e desconecte nós que você terminou de usar.
Navegadores móveis impõem restrições adicionais—iOS Safari em particular. Teste em dispositivos reais, não apenas em simuladores.
Conclusão
A Web Audio API fornece controle de áudio poderoso e de baixo nível através de um modelo baseado em grafo. Comece com um único AudioContext, respeite as políticas de autoplay e use padrões modernos: AudioBufferSourceNode para amostras, OscillatorNode para síntese e AudioWorklet para processamento personalizado. Trate o roteamento de dispositivo de saída como altamente restrito e dependente da plataforma. Detecte recursos em tudo e construa para as restrições que os navegadores realmente impõem.
Perguntas Frequentes
Os navegadores bloqueiam a criação de AudioContext até que ocorra interação do usuário. Seu ambiente de desenvolvimento pode ter configurações mais permissivas. Sempre verifique audioContext.state e chame resume() dentro de um manipulador de clique ou pressionamento de tecla antes de tentar a reprodução. Esta política de autoplay se aplica universalmente em navegadores modernos.
Não. Instâncias de AudioBufferSourceNode são de uso único por design. Após chamar start(), o nó não pode ser reiniciado. Crie um novo nó de origem para cada reprodução enquanto reutiliza o AudioBuffer subjacente. Nós de origem são leves, então este padrão tem impacto mínimo no desempenho.
Use AudioContext.setSinkId(), mas trate-o como altamente restrito. Requer HTTPS, permissão do usuário e políticas permissivas, e não é suportado no Safari ou iOS. Sempre detecte recursos, trate falhas graciosamente e informe os usuários quando a seleção de dispositivo não estiver disponível.
ScriptProcessorNode está obsoleto e executa na thread principal, causando falhas de áudio durante processamento pesado. AudioWorklet executa em uma thread dedicada de renderização de áudio com temporização determinística, tornando-o adequado para manipulação de áudio em tempo real. Sempre use AudioWorklet para processamento personalizado em novos projetos.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.