# pamixer 1.6 — subirle y bajarle el volumen desde la línea de comandos. # # ══ POR QUÉ ENTRA ══════════════════════════════════════════════════════════════════════════════ # `censo-distro.py` marca «audio de escritorio» **5 de 5 ausente**, con el comentario exacto del # problema: «PipeWire suena y no hay con qué subirle el volumen desde una ventana». O sea que la # distro reproduce audio y **no tiene ningún control de volumen**: ni gráfico, ni de consola, ni # atajo de teclado posible — porque un atajo de teclado llama a un comando, y el comando no existía. # # `pamixer` es el más pequeño que cierra eso: un binario que sube, baja, silencia y lista fuentes y # sumideros. Es lo que un compositor engancha a las teclas de volumen. # # ══ ⚠ HABLA EL PROTOCOLO DE PULSEAUDIO, Y ACÁ EL SERVIDOR ES PIPEWIRE ══════════════════════════ # Eso NO es un desajuste: la decisión del repo es PipeWire, y PipeWire expone la capa de # compatibilidad de PulseAudio (`pipewire-pulse`). `pamixer` se conecta por ahí, igual que lo hacen # `mpv` y el resto del corpus que enlaza `libpulse`. # # ⇒ **Pero la dependencia de RUNTIME es esa capa, no sólo la biblioteca**: `pamixer` enlazado y sin # `pipewire-pulse` corriendo arranca y falla al conectar. Es la figura de «el motor sin su driver»; # queda dicho acá porque el síntoma («no se conecta») no nombra la causa. # # Sus únicas deps son `libpulse` —que ya está— y `cxxopts`, su parser de argumentos, que es una # cabecera y entró como `recipes/cxxopts.toml`. name = "pamixer" version = "1.6" license = "GPL-3.0-or-later" [source] tarball = "https://github.com/cdemoulins/pamixer/archive/refs/tags/1.6/pamixer-1.6.tar.gz" sha256 = "8b7199e495dc19b190f8f02ace8782f533266a4bd7c7d3cf6f4cf09b2de13e71" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "dynamic" flags = [] [build.phases] # `--prefer-static` para que pkg-config entregue los `Requires.private`: el corpus es # estático-primero y sin eso el enlace puede no cerrar (lección de `swayimg`, donde # `libfontconfig.a` dejaba 11 símbolos de expat sin resolver). configure = 'PKG_CONFIG_PATH=/usr/lib/pkgconfig meson setup output --prefix=/usr --buildtype=release --prefer-static' compile = 'meson compile -C output' # El guardián comprueba por SÍMBOLO DEFINIDO y no por `NEEDED`: con `--prefer-static` casi nada # queda en NEEDED, y pedirlo ahí rechazaría un build correcto — es el error que cometí cinco veces # el 20-oct, incluido en esta misma campaña con `swayimg`. install = ''' set -e DESTDIR=/out meson install -C output [ -x /out/usr/bin/pamixer ] || { echo "pamixer: no quedó el binario — NO sello" >&2; exit 1; } definido() { readelf -sW "$1" 2>/dev/null | awk -v s="$2" '$8==s && $7!="UND" {f=1} END{exit !f}' } # `pa_context_connect` es lo que hace que esto sirva de algo: sin la biblioteca de PulseAudio # dentro, el binario existe y no puede hablar con el servidor. definido /out/usr/bin/pamixer pa_context_connect || readelf -d /out/usr/bin/pamixer 2>/dev/null | grep -q 'libpulse' || { echo "pamixer: ni símbolo pa_context_connect definido ni NEEDED a libpulse — no podría conectarse al servidor de audio" >&2 readelf -d /out/usr/bin/pamixer 2>/dev/null | grep NEEDED >&2 exit 1 } # Y que ARRANQUE. Ejecución y truncado separados: el estado de una tubería es el del último comando. sal=$(/out/usr/bin/pamixer --help 2>&1) || true printf '%s\n' "$sal" | grep -qiE 'usage|--get-volume|--increase' || { echo "pamixer: --help no muestra su uso; el binario no arranca bien" >&2 printf '%s\n' "$sal" | head -5 >&2 exit 1 } echo "pamixer: binario + libpulse · controla volumen, mute y fuentes" ''' [deps] # ⚠ `python3` NO es opcional aunque pamixer no lo use: **meson es un script de Python**, y sin él # `meson setup` muere con `exit 127` — «comando no encontrado» — que no menciona a python. Está # documentado en la memoria del repo (`receta-meson-exige-python3`) y aun así me lo salté acá. build = ["meson", "samurai", "pkgconf", "pulseaudio", "cxxopts", "binutils", "python3", # ⚠ **LA CADENA DE PULSEAUDIO BAJA TRES NIVELES, Y YA ESTABA DOCUMENTADA EN ESTE REPO.** # `pamixer` no nombra ninguna de estas, pero el cargador sí: # # Error loading shared library libsndfile.so.1: No such file or directory # (needed by /usr/lib/pulseaudio/libpulsecommon-17.0.so) # Error relocating libpulsecommon-17.0.so: sf_command: symbol not found # # O sea: pamixer → libpulse.so → libpulsecommon.so → **libsndfile.so.1**. Tres saltos, y el # sandbox sólo monta lo DECLARADO, así que hay que nombrarlas aunque pamixer no las # mencione nunca. `glib`, `libffi` y `pcre2` son las deps de runtime de pulseaudio por el # mismo motivo. # # ⚠ Esto es **literalmente** lo que escribí hoy en `recipes/espeak-ng.toml`, con los mismos # símbolos (`sf_command`, `sf_error_number`) y la cadena dibujada — y no lo apliqué acá. La # nota estaba en mi propio repo y la volví a pagar. "libsndfile", "glib", "libffi", "pcre2"] # ⚠ Lo que de verdad necesita en EJECUCIÓN es la capa de compatibilidad de PulseAudio que publica # PipeWire: sin ella arranca y no se conecta. Ver la nota de arriba. runtime = ["pipewire", "pulseaudio", "libsndfile", "glib", "libffi", "pcre2"]