Back

Gravando Áudio no Navegador com a Web Audio API

Gravando Áudio no Navegador com a Web Audio API

A maioria dos desenvolvedores assume que a Web Audio API faz a gravação. Não faz — pelo menos não diretamente. A Web Audio API é um motor de processamento e roteamento. O trabalho de gravação propriamente dito pertence à MediaRecorder API. Compreender essa distinção é a forma mais rápida de parar de construir a coisa errada.

Este artigo apresenta a arquitetura atualmente recomendada para gravação de áudio no navegador: capturar a entrada do microfone com getUserMedia(), opcionalmente rotear o áudio através de um grafo da Web Audio e codificá-lo com MediaRecorder.

Pontos-Chave

  • A Web Audio API processa e roteia áudio, mas é o MediaRecorder que de fato grava em arquivo.
  • Um pipeline completo de gravação possui três etapas: captura com getUserMedia(), processamento opcional com nós da Web Audio e codificação com MediaRecorder.
  • getUserMedia() requer um contexto seguro (HTTPS ou localhost) e permissão explícita do usuário para o microfone.
  • Use AudioWorklet para trabalho de DSP customizado; o ScriptProcessorNode está obsoleto e causa falhas sob carga.
  • Sempre verifique o suporte ao tipo MIME com MediaRecorder.isTypeSupported() antes de gravar, já que Safari e Chrome divergem nos formatos suportados.

Como a Gravação de Áudio no Navegador Realmente Funciona

O pipeline moderno de gravação possui três etapas distintas:

  1. CapturagetUserMedia() solicita acesso ao microfone e retorna um MediaStream.
  2. Processamento (opcional) — A Web Audio API inspeciona ou transforma o stream através de nós de áudio.
  3. GravaçãoMediaRecorder codifica o stream em um arquivo.

Você não precisa da Web Audio API para uma gravação básica. Mas se desejar filtragem de ruído, controle de ganho, visualização ou efeitos customizados via AudioWorklet, ela se encaixa perfeitamente no meio dessa cadeia.

Um detalhe sutil, porém importante: o MediaRecorder grava um MediaStream diretamente. Se você quiser gravar a saída processada de um grafo da Web Audio, precisará rotear o grafo de volta para um stream usando audioContext.createMediaStreamDestination() e passar a propriedade .stream desse nó para o MediaRecorder.

Etapa 1: Solicitar Acesso ao Microfone com getUserMedia

getUserMedia() requer um contexto seguro (HTTPS ou localhost) e permissão explícita do usuário antes que o navegador conceda acesso ao microfone.

try {
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: {
      echoCancellation: true,
      noiseSuppression: true,
      sampleRate: 44100
    }
  });
} catch (err) {
  console.error('Microphone access failed:', err.name, err.message);
}

Sempre envolva isso em um try/catch. Os usuários podem negar a permissão, e alguns ambientes (como páginas HTTP) rejeitarão a chamada de imediato com um NotAllowedError ou SecurityError. Note que restrições como sampleRate são apenas sugestões — os navegadores podem ignorá-las dependendo do hardware subjacente.

Etapa 2: Rotear Através da Web Audio API (Opcional)

Se você precisar analisar ou processar áudio antes de gravar, crie um AudioContext e canalize o stream através dele:

const audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(stream);

// Example: connect to an AnalyserNode for visualization
const analyser = audioContext.createAnalyser();
source.connect(analyser);

// To record the processed output, route to a MediaStreamDestination
const destination = audioContext.createMediaStreamDestination();
analyser.connect(destination);
// destination.stream is what you pass to MediaRecorder

Para processamento customizado — como um noise gate ou um medidor de nível em tempo real — use AudioWorklet em vez do obsoleto ScriptProcessorNode. O AudioWorklet roda fora da thread principal, o que significa que não bloqueará sua UI nem perderá amostras de áudio sob carga.

Nota: No Safari iOS, o AudioContext inicia em estado suspenso até ser disparado por uma interação direta do usuário. Crie-o (ou chame audioContext.resume()) dentro de um handler de clique de botão, não no carregamento da página.

Etapa 3: Gravar e Exportar com MediaRecorder

O MediaRecorder recebe um MediaStream e o codifica. Não defina um tipo MIME fixo no código — verifique o suporte primeiro:

function pickMimeType() {
  const candidates = [
    'audio/webm;codecs=opus',
    'audio/ogg;codecs=opus',
    'audio/mp4'
  ];
  return candidates.find(type => MediaRecorder.isTypeSupported(type)) || '';
}

const mimeType = pickMimeType();
const recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
const chunks = [];

recorder.ondataavailable = (e) => {
  if (e.data.size > 0) chunks.push(e.data);
};

recorder.onstop = () => {
  const blob = new Blob(chunks, {
    type: recorder.mimeType || mimeType || chunks[0]?.type || 'audio/webm'
  });

  const url = URL.createObjectURL(blob);
  document.querySelector('audio').src = url;
};

recorder.start();

WebM/Opus geralmente é o melhor padrão para navegadores modernos — tamanho de arquivo reduzido e excelente qualidade. O Safari frequentemente prefere audio/mp4. Recorrer a uma lista de tipos candidatos e deixar o navegador escolher o primeiro suportado é a estratégia mais confiável. Você pode verificar o suporte atual dos navegadores ao MediaRecorder e formatos relacionados no Can I Use.

MediaRecorder vs Web Audio API: Referência Rápida

NecessidadeUse
Gravação simples de microfonegetUserMedia + MediaRecorder
Efeitos ou filtros em tempo realNós da Web Audio API
Processamento DSP customizadoAudioWorklet
Visualização de áudioAnalyserNode
Codificação para arquivoMediaRecorder

O Que Evitar

  • ScriptProcessorNode — obsoleto, roda na thread principal e causa falhas de áudio sob carga.
  • Tipos MIME fixos no código — falham silenciosamente no Safari e em versões antigas do Firefox.
  • Criar AudioContext no carregamento da página — os navegadores o suspendem até que ocorra um gesto do usuário, portanto retome-o dentro de um event handler.
  • Esquecer de parar o stream — chame stream.getTracks().forEach(t => t.stop()) ao terminar, ou o indicador do microfone permanecerá ativo.

Conclusão

A gravação de áudio no navegador é um trabalho de duas APIs: getUserMedia() e MediaRecorder cuidam da captura e codificação, enquanto a Web Audio API cuida de tudo o que existe entre as duas. Comece com o pipeline mais simples que atenda aos seus requisitos, adicione processamento da Web Audio apenas quando necessário e sempre verifique o suporte ao tipo MIME antes de configurar o MediaRecorder. Essa é a arquitetura inteira em uma frase.

Perguntas Frequentes

Não. Para gravação básica, getUserMedia() e MediaRecorder são suficientes. A Web Audio API só se torna necessária quando você precisa processar, analisar ou transformar o áudio antes da gravação, como aplicar filtros, construir visualizações ou executar DSP customizado através de um AudioWorklet.

Safari e Chrome suportam formatos de gravação diferentes. O Safari frequentemente prefere audio/mp4, enquanto o Chrome geralmente utiliza WebM/Opus. Se você fixar um tipo MIME não suportado, o MediaRecorder pode lançar um erro ou produzir uma saída inutilizável. Sempre use MediaRecorder.isTypeSupported() para detectar um formato compatível em tempo de execução.

Crie um MediaStreamAudioDestinationNode usando audioContext.createMediaStreamDestination(), conecte o nó final do seu grafo de áudio a ele e passe sua propriedade .stream para o MediaRecorder. Isso captura o áudio pós-processado em vez do stream bruto do microfone proveniente do getUserMedia().

O Safari iOS exige que o AudioContext seja criado ou retomado dentro de um gesto direto do usuário, como um evento de clique ou toque. Se você instanciá-lo durante o carregamento da página, ele permanecerá suspenso. Mova a criação do AudioContext para dentro de um handler de botão, ou chame audioContext.resume() dentro de um para desbloquear a reprodução e o processamento.

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.

OpenReplay