martes, 29 de noviembre de 2022

Hace un par de días publicaba por aquí unos scripts para poder mutear el micrófono por defecto en Linux, algo que me es de bastante utilidad y que tengo asignado a una combinación de teclas. El caso es que pensé si se podrían añadir scripts para subir y bajar el volumen del micrófono y, de paso, que las notificaciones se modificasen y no saliesen muchas si cambiábamos varias veces el volumen o el estado del micrófono.

Así que volví a realizar experimentos y me puse a averiguar si era posible encontrar el volumen del micrófono y luego cambiarlo. Empecé igual que antes: ejecutando pacmd list-sources y comprobé que, en efecto, se puede averiguar el volumen, sin más que quedarnos con la línea que contiene la cadena "volume:", pero ignorando la que contiene "base volume:". Así que enganchamos un par de grep y, al igual que en la ocasión anterior, me quedé con las dos líneas que me hacían falta mediante el uso de sed y head.

El comando completo que nos da los datos que buscamos del micrófono por defecto es: MICDATA=$(pacmd list-sources | grep -e 'index:' -e 'volume:' | grep -v 'base volume:' | sed -n -e '/* index:/,$p' | head -n2), que nos crea la variable $MICDATA con el siguiente contenido:

* index: 4
        volume: front-left: 49152 / 75% / -7,50 dB, front-right: 49152 / 75% / -7,50 dB

Es decir, el volumen del micrófono está al 75%, así que ahora hay que obtener el número de source del micrófono (en esta ocasión es el 4) y ese 75, que será el volumen. En el post anterior ya expliqué cómo se obtiene el número de source del micrófono, así que no volveré a repetirlo. Para obtener el volumen, mediante awk me quedo con la segunda columna separando por el carácter "/ y eliminando el carácter "%". El comando completo sería VOLUME=$(echo "$MICDATA" | tail -n1 | awk -F'/' '{print $2}' | awk -F '%' '{print $1}').

Ahora va a depender de si queremos incrementar el volumen o decrementarlo, por ejemplo en un 5%. En el primer caso ejecutaríamos VOLUME=$((VOLUME-5)), mientras que en el segundo VOLUME=$((VOLUME+5)). Lógicamente tampoco queremos que el volumen baje de 0 ni suba de 100 (aunque es posible hacerlo), así que podemos incluir unos if de forma que si bajamos de 0, ponga el volumen a 0 (y si es 0, que, de paso, cambie el icono mostrado por el del micrófono silenciado) y si subimos de 100 lo ponga a 100. Ya sólo nos falta ejecutar el comando pactl set-source-volume $MIC $VOLUME'%' que fijará el volumen del micrófono por defecto al nuevo volumen (nótese el "%" que hay tras la variable $VOLUME).

Y luego habría que, simplemente, notificar el nuevo volumen mediante el uso de notify-send... pero aquí tenemos un problemilla, ya que este comando no permite actualizar una notificación ya mostrada, sino que nos va a mostrar diferentes notificaciones y eso no es lo que queremos.

Buscando información, me topé con esta página, donde explican que se puede realizar una llamada directamente al método adecuado de la biblioteca libnotify mediante el uso del comando gdbus. Para que nos entendamos (y simplificando mucho), sería similar a utilizar USR en MSX para llamar a una rutina en código máquina que nos permite más funcionalidades que el comando equivalente en MSX-Basic.

¡Y funciona! Pero los scripts con la llamada directa de gdbus quedaban feísimos, por lo que seguí buscando y me encontré con este script en GitHub, que es una versión compatible con notify-send, pero que además permite obtener el identificador de la notificación y, gracias a eso, modificar o borrar una notificación existente. Incluso tiene una opción que nos permite definir el fichero en el cual se almacena el número de notificación (y si no existe, lo crea). ¡Justo lo que necesitábamos! No obstante, encontré este otro script en GitHub que sigue siendo compatible pero ofrece incluso más opciones y está actualizado más recientemente, así que es el que finalmente he utilizado.

Empezando nuevamente por el final, ¿dónde situar el fichero con el número de notificación? Si lo ponemos en el disco, estaremos escribiendo muchas veces cuando modifiquemos el volumen y eso puede no ser bueno, por lo que lo mejor es meterlo en RAM, haciendo uso de la variable $XDG_RUNTIME_DIR que contiene la ruta de un directorio (almacenado en memoria) donde se pueden guardar pequeños ficheros, que es exactamente lo que buscamos. Así que a partir de ahora, los índices de todas las notificaciones de nuestros scripts van a almacenarse en el fichero $XDG_RUNTIME_DIR/.micVolume, el cual pasaremos con la opción -R al script que sustituye a notify-send, el cual he descargado y renombrado como notify-send.sh.

Sólo falta mostrar una barra de progreso en la notificación, lo cual se consigue mediante los hints -h int:value:$VOLUME -h string:synchronous:volume, siendo $VOLUME la variable que contiene el nuevo volumen (de 0 a 100) que ya habíamos obtenido antes.

Con esto ya tenemos todas las piezas para construir nuestros nuevos scripts e incluso adaptar el script micStatus del post anterior para que sus notificaciones puedan también modificarse. He actualizado el fichero de descarga con una nueva versión del script micStatus refactorizada y adaptada a las nuevas funcionalidades, además de incluir los scripts micVolDown, micVolUp y el notify-send.sh más actualizado descargado de GitHub. Yo he asociado los scripts micVolDown, micVolUp y micToggle a las combinaciones de teclas shift+vol down, shift+vol up y shift+vol mute, con lo que puedo controlar directamente el volumen del micrófono con las mismas teclas que el volumen de los altavoces, pero pulsando shift.