Julio
2008
Control de __todas__ las tarjetas de sonido, presentando tmixer
ATENCIÓN: Artículo bastante técnico ("tas avisao")
Una de las cosas en la que más ímpetu (y horas) he dedicado en TCOS es el soporte multimedia. Pero las cosas avanzan que es una barbaridad y llevaba casi 2 años sin tocar esta parte tan importante.
Cuando nos ponemos delante de un terminal ligero debemos tener cierta facilidad para acceder a los canales de la tarjeta de sonido ya que no todo es 'Master' o 'PCM'.
PulseAudio es el milagro que hace que el sonido (que se origina en el servidor) se reproduzca transparentemente en el terminal por medio de la variable de entorno «PULSE_SERVER», pero PulseAudio no es perfecto ya que desde su panel de control sólo controlamos el volumen de un canal (¿PCM?) de la tarjeta de sonido no de todos.
En TCOS desde hace tiempo el control de la tarjeta de sonido era bueno pero algo (bastante) lento. A modo de histórico era es la forma en la que funciona tcos-volume-manager:
1.- Se manda la cookie de las X al servidor XMLRPC del terminal y si nos da acceso se lee el nombre de todos los canales (sólo el nombre) del mezclador.
(BREVE INCISO: El mezclador podía ser ALSA o en el peor de los casos OSS para lo cual se necesitaban dos aplicaciones amixer (ALSA) y aumix (OSS) y bastante librerías enlazadas que no se necesitaban como gpm o ncurses )
2.- Una vez que teníamos la lista de canales ibamos preguntando uno por uno el estado del volumen y del mute y construiamos los deslizadores y casillas de mute.
NUEVA FORMA
Se ha desarrollado juntando las fuentes de amixer y aumix (con bastante pegamento por cierto) una nueva aplicación que he bautizado como tmixer.
Esta aplicación hace autodetección para usar ALSA (si existe /proc/asound/card0/id) o usar OSS (si existe /dev/mixer y /dev/dsp no existiendo ALSA) y llama a cada una de las partes, para usar los mismos comandos (scontrols scontents sget sset) y mostrar una salida similar.
La parte ALSA se ha modificado para que se pueda enviar facilmente en una petición XML, comparando la original de amixer:
$ amixer sget Master
Simple mixer control 'Master',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback 0 - 39
Mono: Playback 35 [90%] [-6.00dB] [on]
y ahora mi invento:
$ /usr/lib/tcos/tmixer sget Master
Master,volume|switch|,90,on
Se pierde algo de información por el camino (diferencia estereo en niveles o dB) pero ganamos mucha más claridad para luego leerlo desde un script o desde el mismo python.
En la parte OSS también hay varios cambios:
$ aumix -q
vol 90, 90
pcm 87, 87
mic 100, 100
pcm2 100, 100
igain 0, 0
dig1 0, 0
Con mi juguete:
$ TMIXER_FORCE=oss /usr/lib/tcos/tmixer sget Master
Master,volume|switch|,90,on
Como se ve la salida es muy similar a la de ALSA, de hecho es como debe de ser para que no importe si usamos OSS o ALSA para acceder al mezclador, en OSS he dado alguna cosa por sentada como por ejemplo que todos los canales tienen botón de mute, aunque realmente el mute consiste en bajar el volumen a 0, en ALSA si hay mute real. También se han renombrado a algo un poco más parecido a los nombres que se usan en ALSA.
Como se puede ver en el código fuente de tmixer, se hacen los test y se llama al main de las otras dos aplicaciones (que aún se pueden compilar por separado). La variable de entorno TMIXER_FORCE sirve para no usar autodetección sino intentarlo directamente con la que se pida.
¿En qué mejora TCOS?
Para empezar y con las modificaciones de la API de sonido de XMLRPC, sólo se hace una petición donde se devuelven todos los canales con sus características:
sh /usr/lib/tcos/soundctl.sh --showcontents
Master,volume|switch|,90,on#Headphone,switch|,on#PCM,volume|,87,#Mic,volume|switch|,100,on#Mic Boost,volume|,0,#IEC958,volume|switch|,0,off#Beep,volume|switch|,100,on#Docking Mic,volume|switch|,0,off#Docking Mic Boost,volume|,0,#Internal Mic,volume|switch|,0,off#Internal Mic Boost,volume|,67,#Speaker,switch|,on#
Esto se parte según el caracter '#' y después cada canal se separa por comas lo que nos da un vector de diccionarios listo para usar en python:
TcosXmlRpc::***NOT CHANNEL*** c=['3D Control Sigmatel - Depth', 'volume|', '']
TcosXmlRpc::***NOT CHANNEL*** c=['Mix', '', '']
TcosXmlRpc::***NOT CHANNEL*** c=['Mix Mono', '', '']
TcosXmlRpc::***NOT CHANNEL*** c=['Sigmatel D']
TcosActions::populate_datatxt() channel=Master ismute=False volume level=100.0 ctype=volume|switch|
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'on', 'type': 'volume|switch|', 'name': 'Master Mono', 'level': '59'}
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'switch|', 'name': '3D Control - Switch', 'level': ''}
TcosActions::populate_datatxt() channel=PCM ismute=False volume level=45.0 ctype=volume|switch|
TcosActions::populate_datatxt() channel=Line ismute=True volume level=0.0 ctype=volume|switch|
TcosActions::populate_datatxt() channel=CD ismute=True volume level=0.0 ctype=volume|switch|
TcosActions::populate_datatxt() channel=Mic ismute=True volume level=0.0 ctype=volume|switch|
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'switch|', 'name': 'Mic Boost (+20dB)', 'level': ''}
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'volume|switch|', 'name': 'Video', 'level': '0'}
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'volume|switch|', 'name': 'Phone', 'level': '0'}
TcosActions::populate_datatxt() channel=PC Speaker ismute=False volume level=80.0 ctype=volume|switch|
TcosActions::populate_datatxt() channel=Aux ismute=True volume level=0.0 ctype=volume|switch|
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'on', 'type': 'switch|', 'name': 'External Amplifier', 'level': ''}
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'switch|', 'name': 'Sigmatel 4-Speaker Stereo', 'level': ''}
TcosActions::populate_datatxt() *** AUDIO CHANNEL HIDDEN*** channel={'mute': 'off', 'type': 'switch|', 'name': 'Sigmatel ADC 6dB Attenuate', 'level': ''}
Tanto la carga de tcos-volume-manager como de la información de sonido de TcosMonitor son casi instantáneas, los cambios en el código no son muchos pero la mejora es impresionante.
Resumiendo, «me lo he pasado pipa» de nuevo hackeando código de otros proyectos para beneficio propio, programar en C puro no es una delicia pero siempre aprendes muchas cosas modificando y personalizando código de otros y es que amixer y aumix tienen formas de programar muy distintas.
(De paso aunque el proyecto TCOS tiene más código para mantener no me preocupo de los bugs de Ubuntu + aumix)
