Cómo los sitios web desperdician CPU y batería
(h.43z.one)- Al rastrear el ruido blanco en una laptop Linux, se descubrió un problema en el que una pestaña de Firefox seguía despertando el sink de audio de PulseAudio incluso sin que hubiera sonido real
module-suspend-on-idleestaba configurado para detener el dispositivo de audio después de 10 segundos, pero si un sitio web crea un AudioContext, el sink no baja aIDLE/SUSPENDED- El mismo fenómeno apareció con notificaciones web de Outlook, clics en x.com, reproducción de voz en Google Translate y la app web de Discord, y el ruido empezaba incluso solo con
new AudioContext() - En las mediciones, cuando no había ruido el uso de CPU de
pulseaudioera 0.0%, pero con ruido era 4.7%, y el consumo del sistema aumentaba aproximadamente 1.5W AudioContext.suspend()puede detener el acceso al hardware de audio para reducir el uso de CPU/batería, pero Firefox no detiene automáticamente ese desperdicio después de un tiempo como sí lo hace Chrome
El problema de que el sink de audio no entra en suspensión
- En una laptop nueva, incluso cuando no se reproducía música ni audio, se escuchaba por los parlantes un ruido blanco tenue pero molesto
- Para revisar el estado de PulseAudio en Linux se usó
pactl list sinks short- El estado del sink de audio aparece como
IDLE,SUSPENDEDoRUNNING - Cuando el sink estaba en
SUSPENDED, los parlantes permanecían en silencio - Cuando estaba en
IDLEoRUNNING, podía haber ruido blanco aunque no se reprodujera sonido real
- El estado del sink de audio aparece como
- En
/etc/pulse/default.pay/etc/pulse/system.paestaba cargadomodule-suspend-on-idle- Según la configuración, el sink de audio debería detenerse automáticamente tras 10 segundos de inactividad
- Pero en algunas situaciones el sink no pasaba a
IDLE, así que tampoco llegaba aSUSPENDED
Por qué el audio inactivo consume energía
module-suspend-on-idledesconecta en el backend los sinks y sources que no están conectados a ningún stream durante cierto tiempo- El efecto principal es el ahorro de energía
- Si PulseAudio sigue enviando datos vacíos a la tarjeta de sonido incluso en reposo, ALSA usa más ciclos de CPU
- Si no se planea mantener un stream siempre activo, conviene usar un temporizador corto para ahorrar energía
La causa se redujo a pestañas de Firefox y sitios web
- Cada vez que se escuchaba ruido blanco, se revisaba con
pactl list sink-inputsqué programa estaba usando el sink de audio - La causa siempre era Firefox
- Entre las pestañas abiertas no había ninguna que debiera estar reproduciendo sonido real
- Tampoco había videos silenciados
- Se añadió un pequeño script a la barra de estado de i3 para que apareciera una marca roja cuando el sink de audio pasara a
RUNNING - Al principio, parecía que la causa eran los sonidos de notificación de outlook.office.com, que estaba abierto como pestaña fijada
- Al recibir un correo, empezaba el ruido blanco
- No se detenía hasta recargar la pestaña o reiniciar Firefox
- Después se confirmó el mismo fenómeno en otros sitios web
- En x.com, el ruido empezaba apenas se hacía clic en cualquier parte
- En translate.google.com, el ruido también aparecía al escuchar la voz de una traducción
- La app web de Discord mostraba el mismo efecto con solo dejarla abierta
Resultados de medición de CPU y consumo eléctrico
- Cuando no había ruido blanco, el uso de CPU de
pulseaudiose mostraba como 0.0% - En el mismo entorno, la medición de consumo solía estar en el rango de 4.2~5.1W
- Cuando había ruido blanco, el uso de CPU de
pulseaudiosubía a 4.7% - En ese momento, la medición de consumo solía estar en el rango de 5.8~6.7W
- La diferencia no era “prácticamente nada”, sino un aumento aproximado de 1.5W
WebAudio API y AudioContext
- En HTML/JavaScript, las formas de reproducir audio se dividen en dos: la etiqueta
<audio>y la WebAudio API - En casos como Outlook, donde el sonido se reproduce de forma dinámica, se usa la WebAudio API, y para trabajar con audio primero hay que crear un
AudioContext - El problema es que incluso con solo ejecutar
const audioCtx = new AudioContext();aparece ruido blanco en los parlantes - Se ofrece como página de prueba https://editor.43z.one/sqare/i
AudioContext.suspend()detiene el avance temporal del contexto de audio y pausa temporalmente el acceso al hardware de audio para reducir el uso de CPU/bateríaAudioContext.resume()vuelve a iniciar el avance temporal de un contexto de audio detenido
Diferencias entre Firefox y Chrome
- Muchos sitios web crean un
AudioContextaunque no necesiten emitir sonido de inmediato, y luego no lo ponen en suspend - Chrome, pasado cierto tiempo, detiene automáticamente el desperdicio de CPU/batería
- Firefox no se detiene automáticamente y mantiene el estado en el que sigue generando ruido blanco
- Aunque la causa directa sea el sitio web, queda la queja de que Firefox no protege al usuario frente a este tipo de desperdicio de recursos
- También existe la sospecha de que, si hay audífonos Bluetooth conectados, después de hacer clic en x.com puede empezar a transmitirse ruido blanco y desperdiciar la batería de los audífonos
Respuesta temporal: AudioContext Suspender
- Para mitigar el problema, se creó una extensión que intenta suspender automáticamente
AudioContexty reanudarlo cuando el sitio web intenta reproducir sonido - La extensión no es perfecta
- Tarda un poco en reanudarse
- Como hay varias rutas para iniciar audio, puede que no siempre se reanude
- Aun así, es suficiente para el propósito de uso
- Enlaces relacionados
- Issues relacionados en Bugzilla
1 comentarios
Opiniones de Hacker News
Como podrán imaginar, es mucho más complejo que pausar el
AudioContextdespués de cierto tiempo de silencio, pero de todos modos creo que se puede corregir. Otros navegadores ya lo hicieron, y también hay concesiones aceptables.Fuente: implementé muchas funciones de esta zona en Firefox y también soy editor del estándar Web Audio API.
La mayoría entiende las circunstancias que se mencionan aquí. Hay mucho por hacer y el tiempo es limitado.
He visto de primera mano que los desarrolladores de Firefox se esfuerzan más de lo esperado para que sitios muy usados funcionen correctamente para los usuarios. Sé hasta dónde llegan cuando un problema afecta a los usuarios, así que espero que sigan adelante.
Como cada motor de navegador y sistema operativo implementa el audio de forma distinta, si se reproduce un sonido completamente inaudible y luego se vuelve a grabar mediante la API, se genera una firma.
Con esa firma se puede comprobar si el navegador está falsificando el user agent, si está en modo headless o si se trata de todo tipo de casos raros que no corresponden a un usuario real comprando un producto.
https://github.com/fingerprintjs/fingerprintjs/blob/3201a7d6...
En la pestaña no aparece el ícono de reproducción, y aunque silencie la pestaña el ruido no se detiene.
Si silencio Firefox en el mezclador de volumen de Windows, el sonido tampoco se detiene.
Edición: para usuarios de escritorio, esta extensión en realidad es bastante mala. Es mucho más molesto que el ruido blanco se esté encendiendo y apagando todo el tiempo.
Por eso hice un programa propio que mantiene la salida abierta sin enviar datos por la línea, para que la salida no entre en estado inactivo.
Sin embargo, en el contexto de una laptop no tiene mucho sentido, así que ahí sí es razonable ahorrar energía.
En el driver de Windows hay una opción para configurar el stream como Always On. Ojalá existiera también en macOS.
play -qn &se iniciara al iniciar sesión.Parece que un sitio de noticias reproducía audio mientras recargaba anuncios nuevos en bucle, y por el audio la pestaña no entraba en modo de ahorro de energía. Terminé teniendo que cambiarme a Chrome porque seguían llegando cargos de datos inesperados.
Es decir, no había ruido blanco, pero sí consumo de energía por audio: https://bugzilla.mozilla.org/show_bug.cgi?id=1821102
Incluso ahora, en mi Mac no se está reproduciendo nada y
coreaudiodusa 20% de CPU. Está arruinando seriamente la duración de la batería, así que estoy pensando en cambiar a otro navegador hasta que se corrija, pero no quiero abandonar Firefox por algo que parece tan menor.Actualización: parece ser un bug relacionado, pero distinto.
https://source.chromium.org/chromium/chromium/src/+/main:med...
Básicamente, cuando detecta unos 30 segundos de silencio, cambia de un sink respaldado por el dispositivo de audio del sistema operativo a un sink nulo.
Como referencia, este enfoque usa un reloj distinto al del dispositivo de audio, por lo que hubo algunos reportes de distorsión en ciertos tonos cuando el contexto se usa realmente más tarde. La solución alternativa es que el sitio use la API suspend/resume mencionada en el artículo.
audioContext, pero parece incluir muchos elementos bastante inteligentes y dinámicos. Reproducir un sonido de notificación se siente parecido a dibujar un SVG con D3 en vez de usarimg href *.svg.Me pregunto si existirá algo como un hook de Service Worker que permita registrar cosas simples y repetibles, como un manejador de notificaciones, en una API eficiente de una capa más baja.
En Firefox 134.0.1 en MacOS no escucho nada.