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.

El sonido en Linux es confuso: Clarificando Parte 1: ALSA

Lo que sigue es una traducción “quick and dirty” del primero 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 de mis 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 primer artículo se puede leer haciendo clic aquí):

Ya que oigo la frase: “El sonido en Linux es confuso”. Si bien no discrepo totamente con ese comentario, como con todo en Linux el sistema de sonido es bastante lógico y si seguís bien los pasos podés desmitificar  cosas bastante rápido. Así que este artículo explica como funcionan las cosas en Mandriva y debería asegurar a los usuarios para que estén más cómodos con “como funcionan las cosas”.

Primero de todo deberíamos probablemente explicar un poquito como funciona esto. ALSA es la Arquitectura Avanzada de Sonido de Linux. Es un reemplazo para OSS (Open Sound System) que tenía varios problemas en Linux y que últimamente ha sido suplantado por ALSA como el único sistema de sonido en el Kernel. A pesar de una distensión de los términos de la licencia y últimos desarrollos de OSSv4, es improbable que OSS reemplace a ALSA en la línea principal del kernel.

ALSA tiene un componente en espacio de usuario, libasound, que actúa como la primera interfaz para la capa en nivel driver. La mayoría de las quejas acerca de la complejidad del API ALSA se relacionan en realidad a este componente en espacio de usuario, no con la capa en el nivel del kernel, que como podrías esperar, está controlada mucho más rigurosamente. No sufre de la misma necesidad de permanecer retrocompatible con las distintas aplicaciones en espacio de usuario (los drivers del kernel de ALSA solamente necesitan funcionar on libasound que puede obviamente desarrollarse en paralelo) llevando así a un diseño más limpio que la capa de espacio de usuario mismo que tiene que permanecer retrocompatible.

Además de servir de interfaz con la capa en el nivel del kernel e interactuar con el hardware físicamente instalado, ALSA también tiene una arquitectura de plugins. Este sistema de plugins permite a los dispositivos ser simulados/emulados, de distintas interesantes maneras. Permite, por ejemplo crear un dispositivo nulo que envia todo el audio a  /dev/null, permite a los auriculares bluetooth ser usados (notar que esto se considera una manera obsoleta en estos días), y permite que todo el audio sea encaminado a través de PulseAudio el cual discutiré más tarde en un subsiguiente artículo.

Así que, hablemos acerca de los archivos de configuración de ALSA. Ahora la mayoría de los archivos de configuración de ALSA viven en:

/usr/share/alsa/

Se puede afirmar que no son realmente archivos de “configuración” en el sentido clásico, i. e. no significa que tengas que cambiarlos como un usuario de acuerdo a tus propias preferencias y caprichos — son realmente más bien como archivos de código fuente y definen la estructura de los distintos plugins de ALSA y  configuraciones multicanal. A menos que estés desarrollando/hackeando en ALSA, probablemente no deberías modificar la gran mayoría de los archivos en esta carpeta.

El principal archivo

/usr/share/alsa/alsa.conf

define una lista de archivos adicionales para procesar y el orden en el cual procesarlos. Para incorporar PulseAudio de una elegante y configurable manera, hacemos algunos cambios a la lista de archivos adicionales:

--- alsa-lib-1.0.15rc3.lennart/src/conf/alsa.conf	2007-10-17 18:28:03.000000000 -0400
+++ alsa-lib-1.0.15rc3/src/conf/alsa.conf	2007-10-17 18:33:10.000000000 -0400
@@ -8,6 +8,8 @@
 	{
 		func load
 		files [
+			"/usr/share/alsa/pcm/pulseaudio.conf"
+			"/etc/alsa/pulse-default.conf"
 			"/etc/asound.conf"
 			"~/.asoundrc"
 		]

El primer archivo nos permite definir un “dispositivo” para ALSA llamado “pulse”. Esto está siempre presente aun si el usuario decide finalmente no usar PulseAudio de manera predeterminada en su máquina. Esto les permitiría e.g. definir un servidor PulseAudio remoto (vía variables de entorno o configuracion de client.conf – ver el próximo artículo en esta serie, enlazado debajo) y les dice a las aplicaciones de ALSA que usen este “dispositivo” específicamente. Se puede afirmar que este es un caso extremo, pero no hay razón para no sostener esto sin embargo :)

El segundo archivo nos permite activar PulseAudio de manera predeterminada. Esto es bastante importante ya que ofrece a los usuarios una manera sencilla de habilitar/deshabilitar PulseAudio es altamente deseable. La implementación de PulseAudio no está completamente libre de problemas y darles a los usuarios la capacidad de deshabilitar rápida y fácilmente es esencial. Firmemente creo que todos al final usarán PulseAudio, pero llevará tiempo para cada programa soportarlo completamente (quitando el uso de API ALSA “segura”) y para que los problemas de drivers sean resueltos apropiadamente.

En este segundo archivo, o bien comentamos el archivo completamente para deshabilitar PulseAudio de manera predeterminada, o lo dejamos decomentado para habilitar PulseAudio. Esto es manejado por draksound para que los usuarios solamente vean una interfaz gráfica sencilla que es una simple pero efectiva solución. Dicho esto, probablemente cambiaré este archivo para Mandriva 2010.0, cambiando a un sistema manejado por “Alternatives” ¡aunque esto realmente no importa en el esquema de cosas!

Entonces cuando la aplicación ALSA arranque, procesa todos estos archivos y finalmente resuelve como encaminar tu audio. 99% de las veces, el dispositivo “predeterminado” es usado (y uso “dispositivo” en el sentido menos estricto posible). Para una instalación de Mandriva estándar, el dispositivo de manera predeterminada es realmente PulseAudio (via el plugin PulseAudio para ALSA).

Entonces ¿qué pasa después? En el siguiente artículo, voy a hablar acerca de como una aplicación ALSA (o cualquier cliente PulseAudio) funciona cuando se conecta a PulseAudio.

Sonido en una netbook

Información correspondiente a una Acer Aspire One D250-1599

Placas

cat/proc/asound/cards
 0 [pcsp           ]: PC-Speaker - pcsp
                      Internal PC-Speaker at port 0x61
 1 [Intel          ]: HDA-Intel - HDA Intel
                      HDA Intel at 0x98340000 irq 16

Dispositivos

controlC0: 1er dispositivo de control
controlC1: 2do dispositivo de control
hwC1D0: dispositivo dependiente del hardware que se usa depuración para la
segunda placa, slot 1
pcmC0D0p: Primer Dispositivo de reproducción digital correspondiente a la primer placa.
pcmC1D0c: Primer Dispositivo de reproducción digital correspondiente a la segunda placa.
pcmC1D0p: Primer dispositivo de captura digital correspondiente a la segunda placa.
seq: Dispositvo sequencer.
timer: Dispositivo cronómetro.

Información de dispositivos del directorio /sys

ls -l /sys/module/snd/holders
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_hda_codec -> ../../snd_hda_codec/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_hda_codec_realtek -> ../../snd_hda_codec_realtek/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_hda_intel -> ../../snd_hda_intel/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_hwdep -> ../../snd_hwdep/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_mixer_oss -> ../../snd_mixer_oss/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_pcm -> ../../snd_pcm/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_pcm_oss -> ../../snd_pcm_oss/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_pcsp -> ../../snd_pcsp/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_seq -> ../../snd_seq/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_seq_device -> ../../snd_seq_device/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_seq_dummy -> ../../snd_seq_dummy/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_seq_oss -> ../../snd_seq_oss/
lrwxrwxrwx 1 root root 0 2009-07-27 20:28 snd_timer -> ../../snd_timer/