6 pontos por GN⁺ 2025-02-17 | 1 comentários | Compartilhar no WhatsApp
  • Ao investigar o ruído branco em um notebook Linux, foi descoberto que uma aba do Firefox mantinha o sink de áudio do PulseAudio ativo continuamente, mesmo sem som real
  • module-suspend-on-idle estava configurado para suspender o dispositivo de áudio após 10 segundos, mas quando um site cria um AudioContext, o sink não desce para IDLE/SUSPENDED
  • O mesmo fenômeno apareceu em notificações web do Outlook, cliques no x.com, reprodução de voz no Google Translate e no app web do Discord; apenas new AudioContext() já fazia o ruído começar
  • Nas medições, sem ruído, o uso de CPU do pulseaudio era 0,0%, mas, com ruído, era 4,7%, e o consumo do sistema aumentava cerca de 1,5 W
  • AudioContext.suspend() pode interromper o acesso ao hardware de áudio e reduzir o uso de CPU/bateria, mas o Firefox não interrompe automaticamente esse desperdício após algum tempo, como o Chrome faz

O problema do sink de áudio que não dorme

  • Em um notebook novo, mesmo quando nenhuma música ou áudio estava sendo reproduzido, saía dos alto-falantes um ruído branco fraco, mas incômodo
  • Para verificar o estado do PulseAudio no Linux, foi usado pactl list sinks short
    • O estado do sink de áudio aparece como um entre IDLE, SUSPENDED e RUNNING
    • Quando o sink estava em SUSPENDED, os alto-falantes ficavam silenciosos
    • Quando estava em IDLE ou RUNNING, podia haver ruído branco mesmo sem som real sendo reproduzido
  • Em /etc/pulse/default.pa e /etc/pulse/system.pa, module-suspend-on-idle estava carregado
    • Pela configuração, o sink de áudio deveria ser suspenso automaticamente após 10 segundos de inatividade
    • Mas, em algumas situações, o sink não ia para IDLE, portanto também não chegava a SUSPENDED

Por que áudio ocioso consome energia

  • module-suspend-on-idle desconecta do backend sinks e sources que não estejam ligados a streams por um certo período
  • O principal efeito é economia de energia
    • Se o PulseAudio envia dados vazios para a placa de som mesmo em ociosidade, o ALSA usa mais ciclos de CPU
    • Se não houver plano de manter sempre um stream ativo, configurar o timer com um valor baixo ajuda a economizar energia

A causa foi reduzida a abas do Firefox e sites

  • Sempre que o ruído branco aparecia, pactl list sink-inputs era usado para verificar qual programa estava usando o sink de áudio
  • A causa era sempre o Firefox
    • Nenhuma das abas abertas deveria estar reproduzindo som de fato
    • Também não havia vídeo silenciado
  • Um pequeno script foi adicionado à barra de status do i3 para mostrar um indicador vermelho quando o sink de áudio ficasse RUNNING
  • No início, o som de notificação de outlook.office.com, aberto como aba fixa, parecia ser a causa
    • Ao receber um e-mail, o ruído branco começava
    • Ele não parava até recarregar a aba ou reiniciar o Firefox
  • Depois, o mesmo fenômeno foi confirmado em outros sites
    • Em x.com, o ruído começava assim que qualquer lugar era clicado
    • Em translate.google.com, o ruído também ocorria ao ouvir a voz da tradução
    • O app web do Discord produzia o mesmo efeito apenas por estar aberto

Resultados de medição de CPU e energia

  • Sem ruído branco, o uso de CPU do pulseaudio aparecia como 0,0%
  • No mesmo ambiente, as medições de energia ficavam em geral na faixa de 4,2 a 5,1 W
  • Com ruído branco, o uso de CPU do pulseaudio subia para 4,7%
  • Nesse momento, as medições de energia ficavam em geral na faixa de 5,8 a 6,7 W
  • A diferença não é “insignificante” e pode ser resumida como um aumento de cerca de 1,5 W

WebAudio API e AudioContext

  • Em HTML/JavaScript, as formas de reproduzir áudio se dividem em duas: a tag <audio> e a WebAudio API
  • Em casos de reprodução dinâmica de som, como no Outlook, usa-se a WebAudio API, e para fazer operações de áudio é preciso primeiro criar um AudioContext
  • O problema é que apenas executar const audioCtx = new AudioContext(); já faz surgir ruído branco nos alto-falantes
  • A página de teste fornecida é https://editor.43z.one/sqare/i
  • AudioContext.suspend() interrompe o avanço do tempo do contexto de áudio e suspende temporariamente o acesso ao hardware de áudio, reduzindo o uso de CPU/bateria
  • AudioContext.resume() reinicia o avanço do tempo de um contexto de áudio suspenso

Diferença entre Firefox e Chrome

  • Muitos sites criam um AudioContext mesmo sem precisar emitir som imediatamente e depois não o colocam em suspend
  • O Chrome interrompe automaticamente o desperdício de CPU/bateria depois de algum tempo
  • O Firefox não interrompe automaticamente e mantém o estado em que o ruído branco continua sendo emitido
  • Embora o site seja a causa direta, permanece a insatisfação de que o Firefox não protege o usuário desse desperdício de recursos
  • Suspeita-se que, mesmo com fones Bluetooth conectados, clicar no x.com possa iniciar a transmissão de ruído branco e desperdiçar bateria dos fones

Solução temporária: AudioContext Suspender

1 comentários

 
GN⁺ 2025-02-17
Comentários do Hacker News
  • Isso está planejado e é importante, e pretendemos corrigir em breve, se possível. Já foi adiado por muito tempo, e peço desculpas por ainda não ter sido resolvido. É sempre uma disputa de prioridades, então é difícil satisfazer todo mundo no prazo, mas está bem alto na minha lista pessoal de prioridades
    Como dá para imaginar, é bem mais complexo do que pausar o AudioContext depois de um certo período de silêncio, mas de todo modo acho que dá para corrigir. Outros navegadores já fizeram isso, e há trade-offs aceitáveis
    Fonte: implementei muitos recursos nessa área no Firefox e também sou editor do padrão Web Audio API
    • Espero que você não leve esse tipo de crítica para o lado pessoal. Recentemente houve um caso em que um mantenedor de open source recebeu críticas assim como frustração e a situação explodiu
      A maioria entende as circunstâncias mencionadas aqui. Há muito a fazer e o tempo é finito
      Já vi pessoalmente desenvolvedores do Firefox irem além do esperado para fazer sites muito usados funcionarem corretamente para os usuários. Sei até onde vocês vão quando um problema afeta os usuários, então espero que continuem firmes
    • Quero ser um usuário melhor do Firefox, então gostaria de tentar depurar problemas que encontro localmente. Preciso de orientação sobre por onde começar
  • Quando um site abre um contexto de áudio sem reproduzir nada de fato, é bem provável que seja por detecção de bots
    Como cada engine de navegador e sistema operacional implementa áudio de forma diferente, se você reproduzir um som totalmente inaudível e depois gravá-lo de volta via API, surge uma assinatura
    Com essa assinatura dá para verificar se o navegador está falsificando o user agent, se está em modo headless ou se é algum tipo de caso esquisito que não corresponde a um usuário real comprando um produto
    https://github.com/fingerprintjs/fingerprintjs/blob/3201a7d6...
    • Parece que o pessoal de navegadores/padrões web expandiu APIs de forma indiscriminada demais e não pensou o suficiente que o mundo as abusaria desse jeito
    • Já existem plugins para bots em circulação que simulam o Audio Context para enganar a detecção de bots. É uma loucura
    • Mal posso esperar pelo dia em que a Cloudflare adotar isso para atrapalhar ainda mais a liberdade de navegação e desperdiçar ciclos de CPU
  • Esse ruído branco estava me enlouquecendo fazia muito tempo, e eu não conseguia achar a causa de jeito nenhum
    A aba não mostra o ícone de reprodução, e silenciar a aba não faz o ruído parar
    Mesmo silenciando o Firefox no mixer de volume do Windows, o som não para
    Edit: para usuários de desktop, essa extensão na verdade é bem ruim. O ruído branco ficando ligando e desligando o tempo todo incomoda muito mais
    • Se silenciar o Firefox pelo mixer de volume do Windows não para o som, acho que isso é um bug em uma camada mais profunda do que o Firefox
    • Uso essa extensão no desktop sem problemas. Parece depender dos sites que você visita. Em sites que reproduzem/interrompem som com frequência, talvez seja melhor desativar a extensão
  • Quando a saída fica ociosa, o sinal SPDIF digital perde a sincronização. Ressincronizar quando a reprodução começa não é instantâneo, e você acaba perdendo cerca do primeiro segundo de áudio
    Por isso criei um programa próprio que mantém a saída aberta, sem enviar dados pela linha, para impedir que a saída entre em estado ocioso
    Mas no contexto de notebooks isso não faz muito sentido; ali, economizar energia é o correto
    • Isso era infinitamente irritante ao usar um DAC FiiO K3 no MacBook. Sons do sistema, como notificações, na prática nem tocavam por causa do atraso
      No driver do Windows há uma opção para definir o stream como Always On. Queria que existisse algo assim no macOS
    • Antigamente eu fazia a mesma coisa com um DAC USB. Só deixava play -qn & iniciar no login
  • Acho que isso explica um problema que eu tinha no Firefox para Android, em que às vezes o celular gastava 10 GB de dados aleatoriamente em um dia. A conta da operadora vinha absurda
    Parece que um site de notícias reproduzia áudio enquanto carregava novos anúncios repetidamente, e por causa do áudio a aba não entrava em modo de economia. Como eu continuava recebendo cobranças inesperadas de dados, acabei tendo que mudar para o Chrome
  • No macOS, já vi antes o mesmo fenômeno, ou algo muito parecido. Não tenho certeza se o site realmente mantinha um contexto de áudio aberto ou se era um problema interno do Firefox, porque acontecia também em sites como o Youtube, que não usam Web Audio API
    Ou seja, não havia ruído branco, mas havia consumo de energia causado por áudio: https://bugzilla.mozilla.org/show_bug.cgi?id=1821102
    Mesmo agora, no Mac, sem nada tocando, o coreaudiod está usando 20% de CPU. Isso está realmente destruindo a duração da bateria, então penso em mudar para outro navegador até ser corrigido, mas não quero abandonar o Firefox por algo que parece tão pequeno
    Atualização: parece relacionado, mas é outro bug
  • O código que trata essa suspensão no Chromium está aqui:
    https://source.chromium.org/chromium/chromium/src/+/main:med...
    Basicamente, quando detecta cerca de 30 segundos de silêncio, ele troca de um sink apoiado pelo dispositivo de áudio do sistema operacional para um sink nulo
    Vale notar que esse método usa um relógio diferente do dispositivo de áudio, então houve alguns relatos de distorção em certos tons quando o contexto passa a ser usado de verdade mais tarde. A solução alternativa é o site usar a API suspend/resume mencionada no texto
  • Não sei em detalhes como o audioContext é implementado internamente, mas parece ter muitos elementos tentando ser bem inteligentes e dinâmicos. Reproduzir um som de notificação parece algo parecido com desenhar SVG com D3 em vez de usar img href *.svg
    Fico me perguntando se existe algum tipo de hook de Service Worker que permita registrar coisas simples e repetíveis, como handlers de notificação, em uma API eficiente de nível mais baixo
  • Era para realmente ouvir alguma coisa?
    No Firefox 134.0.1 no MacOS, não ouço nada
    • Do meu lado também não sai som, mas quando clico no botão de reproduzir som na página de demonstração do autor, o consumo de energia aumenta cerca de 1 W
    • No Firefox para Android, ouço um pequeno ruído branco
  • Isso corrigiu o problema da página inicial de https://www.dr.dk/.