PulseAudio y Xfce

Al final del artículo Instalando PulseAudio en Debian Jessie comentaba que me quedaban unos cuantos molestos detalles por solucionar con PulseAudio:

  • Al pulsar el botón multimedia de "Mute" para hacer un unmute, el sonido permanece en silencio porque sólo se ha reactivado el canal "Master" del mixer de sonido, mientras que el resto de canales (en mi caso "Headphone" y "Front") permanecen silenciados (que correspondería con el bug #654633 del BTS).
  • Los botones multimedia de subir/bajar volumen sólo funcionan para la tarjeta de sonido ALSA configurada. Específicamente no funcionan para ningún otro sink de sonido PulseAudio aunque esté activo (como mi headset bluetooth).

A estos dos bugs del pasado artículo tengo que añadir este otro:

  • Los sonidos que acompañan las ventanas emergentes de pausa de Workrave producen dos molestas notificaciones de cambio de volumen (tiene pinta de ser el mismo que el bug #754155).

Estos "flecos" tienen que ver con la integración de PulseAudio con Xfce1, o mejor dicho con la ausencia de integración de PulseAudio con Xfce.

Xfce tiene 2 componentes relacionados con el sistema de sonido:

  • xfce4-mixer: la típica aplicación de control de volúmenes —mixer— de los distintos dispositivos de entrada y salida de sonido. Es una aplicación independiente aunque también puede funcionar como un plugin de panel de Xfce. xfce4-mixer

  • xfce4-volumed: un demonio que permite controlar el volumen de una tarjeta (la seleccionada en la configuración) mediante las teclas multimedia de volumen. También se encarga de mostrar visualmente los cambios de volumen mediante notificaciones. xfce4-volumed

La cuestión es que ambas aplicaciones interaccionan con el subsistema de sonido a través de GStreamer (0.10) en vez de usar ALSA o PulseAudio directamente, y es GStreamer el que se encarga de usar el backend apropiado. En Debian esto se traduce en que tanto xfce4-mixer como xfce4-volumed tienen una dependencia del paquete gstreamer0.10-alsa o alternativamente del paquete virtual gstreamer0.10-audiosink (que provee entre otros el paquete gstreamer0.10-pulseaudio). Así que dependiendo de si usamos ALSA o PulseAudio debemos tener instalado el paquete del backend de GStreamer que corresponda.

Por desgracia, me temo que los desarrolladores de Xfce se preocupan esencialmente de la integración con ALSA, y por eso la dependencia con gstreamer0.10-alsa es más prioritaria que el resto. Esto hace que casi siempre acabe instalandose gstreamer0.10-alsa (sobre todo si previamente se tenía una instalación con ALSA como es mi caso), lo que a su vez provoca que apt o aptitude no encuentren necesario instalar gstreamer0.10-pulseaudio. En la práctica es fácil encontrarse en la situación de no tener instalado este backend a pesar de tener instalado PulseAudio, y esa como veremos luego es una de las razones de la existencia de estos bugs.

Otra de razones es que simplemente las aplicaciones no están pensadas con la arquitectura de PulseAudio en mente. Están hechas para un tiempo en el que el sistema de sonido consistía en un único dispositivo hardware estático al que mandar el audio, y como mucho del que recibirlo. Escenarios como conectar un headset Bluetooth y que el audio tenga automáticamente que migrar a este nuevo dispositivo no se concebían entonces, pero actualmente se asume que el sistema tiene que soportarlos (es lo que pasa por ejemplo en el bug #677014).

Esto lleva a casos como el del propio mantenedor de xfce4-volumed diciendo que su aplicación no es compatible con PulseAudio. El problema que tiene este desarrollador no es adaptar su aplicación a una nueva API, es que tendría que rediseñarla de arriba a abajo basándose en el nuevo modelo dinámico de PulseAudio. Y la impresión que me da es que no está muy por la labor.

A esto hay que añadir que el mismo autor considera a día de hoy xfce4-volumed como sin mantenimiento:

XVD is no longer maintained It relies on libkeybinder and gst-0.10, both of which are superseded, and it needs to integrate a longstand PulseAudio support patch. I will, eventually, rewrite xvd with libxfce4utils instead of libkeybinder and gst1.0 instead of gst-0.10. If you want to contribute to Xfce by fixing an old but useful piece of code, get in touch with me!

lo que queda corroborado por el hecho de que la última versión que hay —la 0.1.13— en el repositorio git oficial es de marzo de 2011.

El parche de soporte de PulseAudio al que se refiere debe ser xfce4-volumed-pulse. El autor del mismo explica:

The developer of xfce4-volumed said that xfce4-volumed isn't compatible with pulseaudio, but that's not really accurate. The first problem is a default settings issue (preselection of the correct gst card/channel), and the second culprit is gstreamer pulse plugin is one culprit (basically, the bindings suck, let's say it).

[...]

A few months ago, I "forked" xfce4-volumed and ported it locally to pulseaudio. It works fine here (it takes the default pulse card, you can't change it with xfconf-query anymore, but with pactl or the pulseaudio mixer), but it didn't have many testing and I haven't had time to include it in Xubuntu anyway.

La pega es que si se quiere usar xfce4-volumed-pulse hay que compilarlo e instalarlo a mano. No está empaquetado en Debian2 y tampoco he visto ningúna petición o intento de empaquetarlo.

De todas formas xfce4-volumed-pulse es una solución justo para salir del paso. Como dice su desarrollador, xfce4-volumed tiene que reescribirse aunque sólo sea porque hay que migrar la aplicación de GStreamer 0.10 a GStreamer 1.x (ya expliqué hace poco que GStreamer 0.10 está llamado a desaparecer y Debian no lo va a incluir más a partir de Stretch). Y además hay otros cambios pendientes en la infraestructura de bibliotecas de soporte de Xfce que exigen una nueva reimplementación. Puede ser el momento apropiado para empezar desde cero y arreglar todo de una vez.

La situación de xfce4-mixer es muy parecida: puede considerarse en estado "sin mantenimiento". La última versión estable es la 4.10 de octubre de 2012 y hay una primera versión de desarrollo 4.11 de abril de 2014, pero desde entonces el repositorio git no se ha tocado salvo para actualizar traducciones. Y encima cuando abren un bug pidiendo soporte de PulseAudio en xfce4-mixer, la respuesta del mantenedor es cerrarlo WONTFIX diciendo:

I'm not telling you that it's a good situation. I'm telling you that xfce4-mixer is going to get a final 4.12 release and then that it's unmaintained. This bug won't be fixed.

Y como alternativa propone usar xfce4-pulseaudio-plugin, que algunas distros incluyen pero Debian todavía no. El diálogo es de marzo de este año, así que es posible que no haya habido tiempo todavía de empaquetarlo.

Así que nos encontramos en una situación en la que las dos aplicaciones oficiales de Xfce no soportan PulseAudio, y no parece que lo vayan a tener ya (no al menos hasta que se haga una reescritura completa de las mismas). Y las alternativas no están maduras o todavía no han llegado a downstream. Así que es el momento de las soluciones temporales, los hacks guarros y la cinta adhesiva.

Pásame la cinta adhesiva, Otilio

El bug de launchpad "Pulse Audio don't get unmuted when XF86AudioMute is used" es un compendio de este tipo soluciones/hacks para el bug del Unmute. La mayoría de ellas se basan en suplantar la funcionalidad de xfce4-volumed haciendo que el window manager de Xfce ejecute cierto comando o script cuando se pulsa XF86AudioMute (la tecla que envía el servidor X cuando se pulsa "Mute" en un teclado con teclas multimedia). Lo que varía es el comando base utilizado para controlar la función Mute de PulseAudio.

Por ejemplo, se puede usar el comando pactl para decirle directamente a PulseAudio que queremos aplicar un Mute o Unmute a un sink. O mejor todavía, podemos usar "toggle" para cambiar entre Mute y Unmute, que es lo que realmente suele hacer el botón multimedia:

pactl set-sink-mute <sink> toggle

El nombre del sink se puede obtener de la lista de pactl list short sinks.

Basta con añadir este comando a un nuevo atajo de teclado definido en la la opción de configuración "Teclado" de Xfce:

Atajo de la tecla Mute a pactl

Nota: es buena práctica reiniciar la sesión para asegurarse que Xfce ha leído la nueva configuración.

De la misma manera se podría pensar en solucionar el segundo bug haciendo atajos para que las teclas XF86AudioRaiseVolume y XF86AudioLowerVolume invoquen el incremento/decremento de volumen en el sink:

pactl set-sink-volume <sink> +2%
pactl set-sink-volume <sink> "-2%"

El problema de este método es que sólo sirve para un único sink. Si hay varios sinks, como mi caso con ALSA y BlueZ (el headset), necesitaríamos una forma de expresar "el sink que esté ahora activo". Pero esa forma no existe. Hay un nombre especial (@DEFAULT_SINK@) pero es para otra cosa distinta: indica el sink por defecto (aquel seleccionado por el usuario para hacer fallback3). Pero no tenemos uno equivalente para indicar el sink activo (lo cual es una pena porque sería realmente útil para el segundo bug).

Ya que un comando no era suficiente, lo siguiente fue escribir scripts completos que se lanzan al pulsar XF86AudioMute. Por ejemplo hay uno que parsea la salida de pactl list short sinks para saber cuál está activo (RUNNING) y aplicarle el pactl set-sink-mute <sink> toggle. Otro usa un método mucho menos refinado: recorre toda la lista actual de sinks y aplica el toggle a todos y cada uno de ellos. Algunos necesitan guardar cierto estado, y lo hacen leyendo y escribiendo el estado en ficheros entre ejecuciones (¡encima en el directorio .pulse!).

No puedo ni empezar a describir lo problemático que es todo esto. Son soluciones superfrágiles, que si bien funcionan para una ñapa rápida, en cuanto algo se desbarate al que no conozca cómo funcionan le va a dar unos dolores de cabeza indescriptibles y de muy difícil diagnóstico y arreglo (más que nada porque no es algo estándar de lo que pueda buscar una solución o abrir un bug).

En vez de pactl otra gente está usando el comando amixer para hacer el Mute/Unmute de PulseAudio. Esto funciona porque, aunque amixer es para manipular el mixer de ALSA, ellos en realidad lo están aplicando (probablemente sin saberlo) sobre una tarjeta de sonido ALSA virtual especial llamada "pulse", y que en realidad sirve para representar al demonio de PulseAudio. Así que cuando ejecutan:

amixer -D pulse set Master mute
amixer -D pulse set Master unmute
amixer -D pulse set Master toggle

En realidad están diciéndole al mixer de PulseAudio y no al de ALSA que haga el Mute o Unmute (o el "toggle", que sería el apropiado para asociar a la tecla XF86AudioMute).

Este engaño no es más que una forma de proporcionar compatibilidad a viejos programas (normalmente propietarios que no se pueden recompilar para PulseAudio) que sólo sabían usar tarjetas ALSA a través de alsa-libs. En el caso de Debian, la magia reside en el paquete libasound2-plugins, ya que es ahí donde se añade el plugin que crea esta tarjeta de sonido virtual "pulse" que redirige por detrás el audio a PulseAudio.

En la página The Perfect Setup de PulseAudio, en la sección "Third Party Applications" (y también en el hilo del bug) se explica cómo configurar alsa-libs (libasound2) para que la tarjeta de sonido "pulse" sea el dispositivo por defecto, modificando el /etc/asound.conf (afecta a todo el sistema) o el ~/.asoundr (afecta sólo al usuario). Resulta que en Debian Jessie y Stretch no hace falta, ya que ya traen esta configuración de serie si se instala el paquete pulseaudio y su dependencia libasound2-plugins. Por si alguien tiene curiosidad, está en: /usr/share/alsa/alsa.conf.d/50-pulseaudio.conf y en /usr/share/alsa/pulse-alsa.conf.

Lo podemos comprobar con amixer:

$ amixer info
Card default 'pulse'/'PulseAudio'
  Mixer name    : 'PulseAudio'
  Components    : ''
  Controls      : 4
  Simple ctrls  : 2

Si lo tenéis así, el -D pulse de los comandos de arriba en realidad sobra, y el comando de Mute/Unmute se reduce a un simple:

amixer set Master toggle

Un momento, y entonces ¿por qué falla xfce4-volumed? ¿No es este el equivalente a lo que hace internamente el demonio? Pues parece ser que no. En realidad xfce4-volumed no usa el dispositivo ALSA por defecto sino la propiedad "active-card" de la configuración de xfce4-mixer que se guarda en el Editor de Configuraciones general de Xfce:

Propiedades de xfce4-mixer en el Editor de Configuraciones

En mi caso vale HDAIntelPCHAlsamixer y se refiere específicamente al mixer de la tarjeta ALSA física, no al del dispositivo ALSA por defecto, ya que GStreamer conoce esta tarjeta (a través de su backend gstreamer0.10-alsa, que la está usando) y por eso se salta la charada que ha montado PulseAudio para ir a modificar directamente el mixer del dispositivo ALSA.

Y es aquí donde llegamos a este comentario en un bug abierto contra PulseAudio precisamente por este asunto del Unmute:

Ok, then I guess xfce4-volumed is accessing alsa directly, instead of doing the muting through pulseaudio.

Explanation for the inconsistency between muting and unmuting: xfce4-volumed sets the Master switch to muted. PulseAudio notices that something happened in the alsa mixer, and sees that one of the switches is muted, so PulseAudio concludes that the device is muted and sets the internal device state to mute. While setting the internal state, pulseaudio also mutes the rest of the switches marked as "switch = mute", including PCM. When xfce4-volumed unmutes the Master switch, PulseAudio again notices that something happened, but since the PCM switch is still muted, PulseAudio concludes that the device is still muted and does nothing.

xfce4-volumed should be changed to talk to pulseaudio instead of accessing the alsa mixer directly.

Esto está en consonancia con lo que ya sabemos (que funciona si usamos el mixer de PulseAudio) y también explica por qué está pasando (por culpa de PulseAudio, ¡que raro! :-P). Sólo tenemos que conseguir que xfce4-volumed use el mixer adecuado para que los problema se arreglen sin necesidad de andar con atajos de teclado, scripts y demás.

Pues la solución es tan sencilla como instalar el backend de GStreamer para PulseAudio gstreamer0.10-pulseaudio. Una vez instalado, nuevamente nos aseguramos que Xfce detecte los cambios reiniciando la sesión4, y en el desplegable de selección de Mixers de xfce4-mixer elegimos como dispositivo el que corresponde a "PulseAudio Mixer" en vez del "ALSA Mixer".

Seleccionando el Mixer de PulseAudio en xfce4-mixer

¡Y funciona! Bueno, funciona el Mute/Unmute correctamente, pero sólo para el dispositivo ALSA. También he conseguido que se arregle el tercer bug (ya no tengo notificaciones de cambios de sonido fantasmas). Puedo cambiar el Mixer al que corresponde a mi headset si lo enciendo antes de iniciar la sesión (entonces las teclas de Mute y de volumen funcionan, pero sólo para el headset), pero no es práctico tener que reiniciar la sesión cada vez que quiero cambiar de dispositivo PulseAudio. Como ya he comentado, esto sólo se soluciona con una aproximación más dinámica a la detección de dispositivos y eso es algo de lo que carecen actualmente tanto xfce4-mixer como xfce4-volumed.

:wq


  1. El escritorio que uso actualmente. 

  2. Únicamente lo he visto empaquetado en el AUR de Arch Linux. 

  3. Es el que se usa cuando el sink recordado por PulseAudio para la aplicación actual no está presente. 

  4. Si no xfce4-mixer empezará a hacer cosas raras como no dejarnos seleccionar el Mixer de PulseAudio. 

blogroll

social