El sonido en Linux es confuso: Clarificando Parte 2: PulseAudio

Lo que sigue es una traducción “quick and dirty” del segundo de dos excelentes artículos escritos por Colin Guthrie. Todo comenzó por mi intento de desentrañar la manera en que Linux maneja el audio por estos días. Luego dí con Colin Guthrie el encargado de la parte de sonido en Mandriva, el cual tuvo la amabilidad de responder varias preguntas, y al parecer todo esto fue un disparador para que él escribiera estos dos posts altamente recomendables, aquí va el primero (el original en inglés del segundo artículo se puede leer haciendo clic aquí):

En un artículo anterior, describí como la configuración de bajo nivel de ALSA nos permitía encaminar todas las aplicaciones usando el API ALSA via PulseAudio. En este artículo echaremos una mirada a los distintos archivos de configuracion y a las variables que controlan este lado del camino de audio. Recorreremos por lo que pasa cuando una aplicación intenta reproducir sonido.

Aplicación ALSA

En primer lugar, una aplicación usando el API ALSA intenta abrir el dispositivo “predeterminado”. Asumiendo que hemos configurado el dispositivo predeterminado para que sea el plugin de PulseAudio para ALSA, básicamente actuará como cada aplicación PulseAudio cliente. Ahora estamos dentro de la tierra de la configuración de PulseAudio.

Cliente PulseAudio

PulseAudio adopta un modelo cliente/servidor que es muy similar en principio al del sistema X11. Es el servidor que realmente hace salir el audio y la aplicación cliente que le dice al servidor que reproducir. Si bien este enfoque puede ser ineficiente, resultando en la copia de datos por todos lados, PulseAudio hace lo más que puede para asegurar que los datos que se copian y otras operaciones sujetos a latencia se mantengan a un mínimo. En el uso comón tanto de cliente y servidor corriendo en la misma máquina, PulseAudio usa SHM (Shared Memory) para asegurar que los datos enviados desde el cliente al servidor no se copian a través del cable. El núcleo del servidor PulseAudio mismo es “copia cero” que quiere decir que las referencias a los datos se difundan sin copiar los datos mismos realmente.

Lo primero que un cliente PulseAudio tiene que hacer es conectarse  a un servidor. Para hacer esto, verifica que distintas variables y archivos de configuración para determinar precisamente a cual servidor se conectará!

Inicialmente, la librería del cliente PulseAudio busca una variable de entorno PULSE_SERVER. Si la encuentra, esta variable puede definir una lista de servidores a los que el cliente debería conectarse. Estos servidores se pueden especificar como sockets UNIX locales o direcciones de nombres/IP para una conexión TCP.

Si esta variable no existe o está vacía, PulseAudio entonces verifica las propiedades X11 en la ventana raíz. Estas propiedades son bastante parecidas a variables de entorno, pero estarán disponibles remotamente si hacés SSH a otra máquina sin redireccionamiento de X11. Hablaré de esto más tarde. Podés ver una lista de PulseAudio relacionada haciendo:

xprop -root | grep PULSE

Los nombres de las variables usadas son las mismas que aquellas usadas en el entorno, de manera que PulseAudio buscará una propiedad llamada PULSE_SERVER.

Asumiendo que aun no tiene un servidor al cual conectarse todavía, PulseAudio comprobará la configuración de un servidor predeterminado en el archivo client.conf. Este archivo está ubicado en /etc/pulse/ o ~/.pulse/. Solamente se procesa un archivo client.conf. De manera que si el usuario tiene el suyo, no se procesará el del sistema en absoluto (esta es un cuestión que traté de hacer vano en PulseAudio bug #606 – llevó un tiempo para que esto se entienda como podés ver!).

Entonces hemos tratado tres maneras de encontrar un servidor. Si todavía no hemos encontrado uno, recurrimos simplemente al predeterminado – i.e. conectándose a un daemon personal y a un daemon del sistema (un daemon del sistema generalmente no se recomienda, pero está soportado para diferentes circunstancias – comúnmente sistemas embebidos). Si todavía no podemos conectarnos, el archivo client.conf puede especificar si intentaremos o no iniciar automáticamente un daemon personal. Desde PulseAudio 0.9.11, este es el comportamiento predeterminado y permite a las aplicaciones de consola funcionar directamente sin iniciar un daemon PulseAudio de antemano.

Entonces, en el improbable caso que todo falle, finalmente no seremos capaces de reproducir sonido, pero hemos hecho casi todo lo que podemos hacer para hacerlo funcionar! Para visualizar mejor esto, miremos algunos de los escenarios comunes y reveamos el proceso de arriba.

Aplicación de consola

Entonces, en una instalación predeterminada, hemos arrancado en nivel de ejecución 3 y logueado en la terminal. No definimos ninguna variable especial e iniciamos una aplicación que reproduce sonido via ALSA. Aquí está lo que pasa.

  1. La aplicación abre un dispositivo predeterminado.
  2. El plugin de PulseAudio para ALSA (como cualquier cliente PulseAudio) comprueba que hay una configuración para un servidor y no encuentra uno.
  3. Intenta conectarse a un servidor local pero falla por que no se está ejecutando.
  4. Entonces arranca un servidor PulseAudio automáticamente y entonces se conecta a él.
  5. La aplicación luego reproduce audio via las funcionaes del API de ALSA y este es finalmente reproducido por el daemon PulseAudio.
  6. La aplicación cliente termina haciendo lo suyo, y luego sale.
  7. El daemon PulseAudio permanece por ahí por un rato en caso de que otra aplicación quiera reproducir sonido en el futuro cercano.
  8. Después de un rato, el daemon PulseAudio se enoja porque nadie lo quiere y se suicida :p

Así que es eso. Es bastante simple. Tomemos otro ejemplo.

Aplicación X11

Bajo X11 las cosas son un poquito diferente, pero se siguen los mismos principios básicos.

  1. Durante la inicialización de X11, los escritorios modernos que soportan Autoinicio XDG finalmente ejecutan el script start-pulseaudio-x11. Este script asegura que el daemon PulseAudio sea reiniciado y que se carguen algunos módulos extra relacionados con X11 se carguen en él. Estos módulos aseguran que, a diferencia de una aplicación de consola, el damon PulseAudio de X11 no salga luego de un tiempo de espera inactivo – en cambio estará dando vueltas por ahí mientras la sesión X11 exista. Esto asegura que las propiedades X11 mencionadas antes se definan – las razones para eso se verán claramente en el próximo ejemplo.
  2. Cuando cualquier cliente PulseAudio (sea una aplicación ALSA via el plugin PulseAudio vía ALSA, o PulseAudio nativo) se inicia pasa por su “rutina de buscar un servidor”. Ahora detendrá este proceso cuando alcanza las propiedades de X11 y usa la información de ella y se conecta al servidor.
  3. La aplicación cliente luego reproduce sonido como antes y finalmente termina y sale.
  4. El daemon PulseAudio no sale/se mata a sí mismo mientras la sesión de X11 está todavía andando.

Entonces de nuevo, las cosas son realmente simples.

La aplicación X11 remota

Una de las cosas más prácticas de X11 es la capacidad de conectarse a otra máquina en tu red y ejecutar aplicaciones con interfaz gráfica y mostrarlas en tu pantalla local. Con PulseAudio, el sonido también se oye en la máquina local. Las conexiones remotas (por razones de seguridad) no se habilitan de manera predeterminada. Para habilitarlas, ejecutá paprefs y habilitá la opción Habilitar el acceso desde la red  a dispositivos de sonido locales. Esta es la única opción que se necesita para este ejemplo. Carga un módulo adicional en el servidor que escucha en el puerto TCP 4713 para conexiones entrantes. Obviamente, no hace falta decir que cualquier firewall en la máquina debe habilitar conexiones a este puerto!

  1. El usuario inicia una sesión X11 normal y el script start-pulseaudio-x11 asegura que las propiedades X11 sean definidas como en el ejemplo anterior.
  2. El usuario entonces se conecta a otra máquina de su red vía ssh e inicia un reproductor de audio (e.g. Rythmbox, Amarok, etc.)
  3. Aun cuando la aplicación se está ejecutando remotamente se mostrará localmente.
  4. Cuando la aplicación comience a reproducir audio, la porción cliente buscará las propiedades X11 que han sido redireccionadas a través de la conexión SSH.
  5. El cliente PulseAudio entonces se conectará por TCP al servidor PulseAudio ejecutándose en la máquina local del usuario.
  6. El usuario disfruta la imagen y el audio local que la aplicación proporciona.

Entonces, como podés ver, el uso de las propiedades nos ha permitido subirnos a caballito del redireccionamiento X11. No es una conexión totalmente limpia ya que bajo SSH los datos de X11 realmente irán por un túnel por un enlace seguro manejado por SSH mismo, en cambio todo lo que estamos haciendo es decirle al cliente PulseAudio donde conectarse directamente, por fuera de cualquier túnel SSH. Esto significa que si bien la visualización puede funcionar sobre un systema NATeado, el sonido no lo hará. Esto es claramente tratado, pero tendríamos que enseñarle a SSH acerca de PulseAudio para que esto funcione. La razón por la que funciona para X11 es porque sabe de aquél, y tiene soporte específico para X11. Simplemente estamos subiéndonos a caballito de SSH. Dicho esto, la configuración actual es “suficientemente buena” para la mayoría de los casos.

Así que espero que este artículo haya desmitificado como interactuán el cliente y el servidor PulseAudio y las distintos archivos/variables de configuración que entran en juego. Si tenés cualquier pregunta, por favor preguntá en los comentarios y me esforzaré en actualizar el artículo.

Leave a Reply

Your email address will not be published. Required fields are marked *