Monday, February 14, 2011

Receta para PulseAudio en openSUSE

Falta menos de un mes para la publicación de openSUSE 11.4, y probablemente esta nueva versión seguirá arrastrando los mismos problemas de sonido que las versiones anteriores. Mucha gente prefiere eliminar o desactivar PulseAudio a intentar arreglarlo, pero lo cierto es que otras distribuciones (Ubuntu, Fedora, Mandriva, ...) incluyen PulseAudio activado por defecto, y los usuarios no padecen los mismos problemas. Aparte de que al desactivar PulseAudio también se pierden algunas funcionalidades interesantes. Pero en primer lugar: ¿de que problemas estamos hablando? El sonido básicamente funciona, pero cuando estás reproduciendo sonido en segundo plano y al mismo tiempo ejecutas alguna tarea larga que consume CPU, aparecen ruidos molestos que arruinan el sonido. Esto se debe a un fallo llamado "underrun", que aparece cuando el proceso que quiere reproducir sonido no es capaz de suministrar al driver ALSA del sistema los datos (buffers, fragmentos) necesarios a tiempo.

El tamaño de los fragmentos influye en la probabilidad de que aparezcan los ruidos no deseados. Cuanto más pequeño sea el tamaño de los fragmentos, más veces será necesario que el sistema interrumpa otras tareas para escribir datos en el driver de sonido, y esto también incrementa el consumo de batería en un portátil o un terminal móvil. La ventaja de los fragmentos pequeños es que se reduce la latencia de audio, es decir, el tiempo de respuesta entre la producción y la audición del sonido, lo cual puede ser importante para los juegos o los programas musicales que usan MIDI. El tamaño por defecto de los fragmentos en PulseAudio es bastante pequeño, de tan solo 25 milisegundos, y se puede configurar editando  /etc/pulse/daemon.conf

Para mantener reducido el tamaño de los fragmentos y asegurar la puntualidad y cadencia de alimentación de datos al driver de audio, una posible solución es incrementar ligeramente la prioridad del proceso que gestiona el sonido, en este caso PulseAudio. Para ello hay dos paquetes de software implicados: RealtimeKit y PolicyKit. El problema es que RealtimeKit en openSUSE está de adorno, se instala por defecto y se activa automáticamente, pero es incapaz de hacer nada por culpa de la configuración de PolicyKit, así que no solo no cumple su función, sino que malgasta recursos. El primer paso será actualizar la versión instalada del paquete "rtkit". En openSUSE 11.3 se proporcionaba la versión 0.5, y en openSUSE 11.4, la versión disponible es la... 0.5 también. Esto es inexplicable, porque la última versión publicada es la 0.9, que incorpora algunas funcionalidades necesarias no solamente para PulseAudio, sino también para otros programas como FluidSynth, Drumstick, KMid, etc...

Hay RPM de rtkit-0.9 en los repositorios de OBS
http://software.opensuse.org/search?q=rtkit&baseproject=openSUSE%3AFactory

Para comprobar que RealtimeKit funciona como debe, es conveniente   poder inspeccionar la prioridad de los hilos (threads) individuales de cada programa. Esto se puede hacer con top(1) o con ps(1). Para mayor comodidad, te propongo usar un sencillo script, que puedes guardar en ~/bin/threads:

#!/bin/bash
P=$(pidof $1)
if [ $? == 0 ]; then
    ps -O policy,rtprio,lwp -m -p $P
fi

Usando este script, es posible ver los hilos de cualquier programa en funcionamiento mediante un comando sencillo:

$ threads rtkit-daemon
  PID POL RTPRIO   LWP S TTY          TIME COMMAND
 4116 -        -     - - ?        00:00:00 /usr/lib/rtkit/rtkit-daemon
    - TS       -  4116 S -        00:00:00 -
    - TS       -  4120 S -        00:00:00 -
    - RR      99  4121 S -        00:00:00 -

La columna POL indica la política de planificación, donde TS es "time sharing", y  RR significa "round robin". La columna RTPRIO indica la prioridad del hilo. Como puedes ver, rtkit tiene un hilo con la máxima prioridad. El mismo comando contra PulseAudio cuando está correctamente configurado da el siguiente resultado:

$ threads pulseaudio
  PID POL RTPRIO   LWP S TTY          TIME COMMAND
 4114 -        -     - - ?        00:04:35 /usr/bin/pulseaudio --start
    - TS       -  4114 S -        00:00:51 -
    - RR       5  4149 S -        00:03:43 -
    - RR       5  4152 S -        00:00:00 -

En la configuración por defecto de openSUSE, los dos últimos hilos usan la política TS por defecto, y no tienen prioridad especial. Para resolverlo, hay que hacer un cambio de política sobre RealtimeKit en la configuración de PolicyKit. Para ello, añade un archivo con el siguiente contenido:

[org.freedesktop.RealtimeKit1]
Identity=unix-user:*
Action=org.freedesktop.RealtimeKit1.*
ResultAny=no
ResultInactive=yes
ResultActive=yes

Sitúa el archivo en la siguiente ubicación y nombre:
/etc/polkit-1/localauthority/50-local.d/org.freedesktop.RealtimeKit1.pkla

Para aplicar los cambios anteriores es necesario reiniciar. Nota: esta receta se aplica tanto a openSUSE 11.4rc1 como a la anterior versión publicada 11.3