Configurando Deckboard descubrí que Pipewire puede alterar los IDs al reiniciar o suspender el dispositivo.
Motivación
Se me ocurrió una idea, utilizar una tabla Amazon Fire 8 como un "StreamDeck" . Configuraba Deckboard para multiples usos, uno de ellos es para cambiar entre dispositivos de audio. Estoy corriendo NixOS y usando de sound server Pipewire.
Cambiando de dispositivo por defecto
Miremos el uso básico de WirePlumber CLI:
- $ wpctl
- Usage:
- wpctl [OPTION…] COMMAND [COMMAND_OPTIONS] - WirePlumber Control CLI
- Commands:
- status
- get-volume ID
- inspect ID
- set-default ID
- set-volume ID VOL[%][-/+]
- set-mute ID 1|0|toggle
- set-profile ID INDEX
- clear-default [ID]
- Help Options:
- -h, --help Show help options
- Pass -h after a command to see command-specific options
En mi caso de uso el comando set-default
para cambiar el dispositivo por defecto, pero también necesito saber
cual es el ID.
Para obtener el ID necesitamos usar el comando status
, status va a dar un montón de información, pero hay que hacer
foco en Audio > Sinks.
- $ wpctl status
- [...]
- Audio
- ├─ Devices:
- │ 46. Renoir Radeon High Definition Audio Controller [alsa]
- │ 48. Family 17h/19h HD Audio Controller [alsa]
- │ 80. Ditoo-audio [bluez5]
- │ 132. GSP 370 [alsa]
- │
- ├─ Sinks:
- │ * 58. Family 17h/19h HD Audio Controller Analog Stereo [vol: 0.50]
- │ 68. Renoir Radeon High Definition Audio Controller Digital Stereo (HDMI) [vol: 0.40]
- │ 81. Ditoo-audio [vol: 0.70]
- │ 103. GSP 370 Analog Stereo [vol: 0.55]
- [...]
El dispositivo actual marcado por defecto tiene un asterisco *
, usando esos IDs se puede cambiar el dispositivo
por defecto, por ejemplo, si necesito por defecto GSP 370:
El problema: Los IDs dinámicos
Después de reiniciar o salir de suspensión los IDs potencialmente puede cambiar, para evitar esto vamos a procesar
el texto de salida wpctl status
de esta manera sabemos cuál es el ID necesario.
El nombre con el que el dispositivo se muestra puede cambiar por muchas razones, por eso es preferible utilizar el
comando status con --names
, de esta manera la lista se va a mostrar con los nombres internos y quitan la posibilidad
de tener dos valores iguales.
- $ wpctl status --name
- [...]
- Audio
- ├─ Devices:
- │ 46. alsa_card.pci-0000_06_00.1 [alsa]
- │ 48. alsa_card.pci-0000_06_00.6 [alsa]
- │ 80. bluez_card.XX_XX_XX_XX_XX_XX [bluez5]
- │ 132. alsa_card.usb-Sennheiser_GSP_370-00 [alsa]
- │
- ├─ Sinks:
- │ * 58. alsa_output.pci-0000_06_00.6.analog-stereo [vol: 0.50]
- │ 68. alsa_output.pci-0000_06_00.1.hdmi-stereo [vol: 0.40]
- │ 81. bluez_output.XX_XX_XX_XX_XX_XX.1 [vol: 0.70]
- │ 103. alsa_output.usb-Sennheiser_GSP_370-00.analog-stereo [vol: 0.55]
- [...]
Basándose en esta lista, es necesario los valores 58
and 103
para cambiar entre dispositivos, y obtendremos
esos números via regex. Hay muchas maneras de lograr el objetivo, pero mi preferencia es usar el comando sed
.
Obteniendo el valor
Ahora voy a mostrar los comandos por separado, para dar una explicación breve
1. Status
wpctl status --name
Devolverà el mismo output que tenemos más arriba, con todos los audio sinks.
2. Grep
Usando el output del comando anterior le aplicamos grep usando sinkname
.
grep 'sinkname'
Por ejemplo sinkname
sería:
grep 'alsa_output.pci-0000_06_00.6.analog-stereo'
Este comando devolverà la línea exácta donde se encuentra el valor:
│ 58. alsa_output.pci-0000_06_00.6.analog-stereo [vol: 0.50]
3. Sed
Usando el output del comando anterior se extrae el valor que se necesita,
el comando sed tiene una estructura básica s/<input>/<output>/
. El comando a ejecutar es
sed 's/^[^0-9]*\([0-9]\+\)\..*/\1/'
, lo explico por partes:
- En el input buscamos desde el inicio
^
- Cualquier caracter
[^0-9]*
que no sean números del 0 al 9*
quiere decir indeterminada cantidad de veces. En este caso^
indica negado. ()
indican captura, todo lo que está dentro del paréntesis es capturado y se utiliza el output usando\1
, los paréntesis deben ser escapados\(\)
.- Dentro de la captura se requieren números
[0-9]+
, el signo+
indica uno o más veces, seguido de un punto\.
escapado. - El resto no importa, ya se tiene el número objetivo, entonces
.*
es cualquier caracter 0 o intederminadas veces. - Y por último en el output se utiliza el valor capturado
\1
.
El comando completo
wpctl status --name $(echo "$(wpctl status --name | grep 'alsa_output.pci-0000_06_00.6.analog-stereo')" | sed 's/^[^0-9]*\([0-9]\+\)\..*/\1/')
wpctl status --name $(echo "$(wpctl status --name | grep 'alsa_output.usb-Sennheiser_GSP_370-00.analog-stereo')" | sed 's/^[^0-9]*\([0-9]\+\)\..*/\1/')
Solo hay que adaptar el valor del dispositivo después de grep
para adaptarlo a tus necesidades.
Gracias por leer!
Namaste.