Cierra la decisión que quedó abierta anoche en `docs/plan-apps-usuario-final.md`: el corpus no tenía ningún cliente de audio salvo ALSA, y eso bloqueaba a toda app multimedia. GANA LA VARIANTE DE COSMIC y la promoción es GRATIS: era la única cuyo cierre ya resolvía entero contra el catálogo padre, así que `recipes/pipewire.toml` sella b3:e240653a — el mismo hash que tenía en la cola. Con ella suben `libsndfile` (las tres copias sellaban idéntico) y `dbus-shared` (gnome y cosmic, idénticas). Se jubilan 9 copias de cola. POR QUÉ ESTO NO REPITE EL EPISODIO DE LAS DOS GLIB — leído de los artefactos sellados, no razonado: **ningún pipewire de los tres enlaza glib.** Los NEEDED de las tres variantes son exactamente `libdbus-1.so.3`, `libpulse.so.0` y `libsndfile.so.1`; glib entraba sólo como Requires transitivo de pkg-config, en tiempo de build. ⇒ `libpipewire-0.3.so` es glib-free y se comparte entre las cuatro imágenes sin riesgo. ⚠ Y POR ESO `pulseaudio` NO SE PROMUEVE, aunque sea la dep de al lado. Ahí la objeción SÍ aplica y el número lo dice solo: `libpulse-mainloop-glib.so.0.0.6` mide **45.712 bytes** en la variante de GNOME (NEEDED `libglib-2.0.so.0`) y **2.455.600** en la del corpus, que se traga la glib ESTÁTICA del catálogo. Meter ésa en el proceso de gnome-shell —que ya carga la glib sombra dinámica— es literalmente el cuadro de colord. `incoming-kde/pulseaudio` e `incoming-gnome/pulseaudio` se quedan donde están: son variantes deliberadas, no duplicados. La copia del corpus existe sólo para que pipewire tenga contra qué enlazar `libpulse.so.0`, y ese enlace es por SONAME — en runtime lo sirve la libpulse de cada imagen, ABI-compatible (misma 0.24.3). Enlazar contra una variante y correr contra otra es legítimo cuando lo que cruza es un SONAME; lo que NO se puede es hidratar dos artefactos distintos en la misma ruta. Esa distinción es la que decide qué se promueve y qué no. mpv (b3:392e9690) pasa a `-Dpipewire=enabled`, con ALSA encendida detrás: prueba pipewire primero y cae a alsa si no hay demonio —KDE todavía no lista PipeWire entre sus raíces—. Evidencia: NEEDED … libasound.so.2 **libpipewire-0.3.so.0** libEGL.so.1 libc.so --ao=help → pipewire (PipeWire audio output), alsa, null Impacto medido antes de tocar, hasheando las 336 recetas de cola y comparando: 9 retiradas, **5 rebuilds** (wireplumber, xdg-desktop-portal ×2, kpipewire, spectacle) — los 5 sellados. Sin la salvedad de pulseaudio habrían sido 8, incluido gnome-shell. Perfiles: KDE 188/188, GNOME 132/132, sway 145/145. ⚠ COSMIC 105/106: `xdg-desktop-portal-cosmic` murió por OOM por TERCERA vez (7 G de RAM sin cgroups, con otro agente compilando Rust). Sigue siendo la máquina, no la receta.
146 lines
10 KiB
TOML
146 lines
10 KiB
TOML
# ══ PROMOVIDA AL CORPUS 2026-09-03 — hash IDÉNTICO (b3:e240653a…) ═══════════════════════════════
|
|
# Vivía en TRES copias, una por cola de escritorio, y ninguna en el corpus. Eso convertía a
|
|
# `libpipewire-0.3` en inalcanzable para cualquier app del catálogo: `mpv` tuvo que salir con
|
|
# `--ao=alsa` en vez de su salida nativa, y `wf-recorder` —que graba con pipewire o pulse— no se
|
|
# podía ni escribir. Una receta del corpus resuelve sibling-first y después el catálogo padre, nunca
|
|
# una cola hermana.
|
|
#
|
|
# GANA LA VARIANTE DE COSMIC, y no por gusto: era la única cuyo cierre ya resolvía ENTERO contra el
|
|
# corpus (`glib`, `pcre2` y `dbus-shared` del catálogo padre). Subirla no cambió una sola arista ⇒
|
|
# mismo ArtifactHash y cache hit. Las de KDE y GNOME resolvían `glib-shared`/`pcre2-shared` y la
|
|
# glib SOMBRA de `incoming-gnome`, que no existen en el corpus.
|
|
#
|
|
# ══ POR QUÉ ESTO NO REPITE EL EPISODIO DE LAS DOS GLIB, medido antes de moverla ═════════════════
|
|
# La objeción obvia es la que la propia cabecera de la copia de cosmic dejó escrita: dos artefactos
|
|
# del mismo nombre con bytes distintos, hidratados en la misma imagen, ponen dos registros de GType
|
|
# en un proceso. Acá no aplica, y se comprobó leyendo los artefactos sellados, no razonando:
|
|
#
|
|
# ningún pipewire de los tres enlaza glib. Los NEEDED de las tres variantes son exactamente
|
|
# `libdbus-1.so.3`, `libpulse.so.0` y `libsndfile.so.1`. glib entraba sólo como Requires
|
|
# transitivo de pkg-config, en tiempo de BUILD.
|
|
#
|
|
# ⇒ `libpipewire-0.3.so` es glib-free y se puede compartir entre las cuatro imágenes.
|
|
#
|
|
# Lo que sí queda enlazado por SONAME es `libpulse.so.0`, y eso es correcto: en runtime lo resuelve
|
|
# la libpulse de CADA imagen, que es ABI-compatible (misma 0.24.3). Enlazar contra una variante y
|
|
# correr contra otra es legítimo cuando lo que cruza es un SONAME; lo que NO se puede es hidratar
|
|
# dos artefactos distintos en la misma ruta.
|
|
#
|
|
# ⚠ Y POR ESO `pulseaudio` NO SE PROMOVIÓ, aunque sea la dep de al lado: ahí la objeción SÍ aplica.
|
|
# `libpulse-mainloop-glib.so.0.0.6` mide 45.712 bytes en la variante de GNOME (NEEDED
|
|
# `libglib-2.0.so.0`) y 2.455.600 en la del corpus, que se traga la glib ESTÁTICA del catálogo. Meter
|
|
# ésa en el proceso de gnome-shell —que ya carga la glib sombra dinámica— es literalmente el cuadro
|
|
# de colord. Las tres pulseaudio se quedan donde están y eso está bien: son variantes deliberadas,
|
|
# no duplicados.
|
|
# pipewire 1.2.7 — EL SERVIDOR DE AUDIO DE LA DISTRO. Decisión tomada por el usuario (2026-07-29):
|
|
# **PipeWire, no PulseAudio.** Hasta hoy el corpus tenía sólo el CLIENTE libpulse y el demonio quedaba
|
|
# sin decidir; esta receta cierra esa pregunta abierta.
|
|
#
|
|
# CÓMO CONVIVE CON EL `pulseaudio` DE ESTA MISMA COLA, que es lo que hace que la decisión no rompa
|
|
# nada: `pulseaudio` se construyó `-Ddaemon=false` (sólo cliente, para que gvc pueda HABLAR el
|
|
# protocolo) y pipewire va con `-Dlibpulse=enabled`, que produce **`pipewire-pulse`**: un servidor que
|
|
# habla el protocolo de PulseAudio. O sea que gnome-shell sigue usando libpulse sin saber que del otro
|
|
# lado hay PipeWire. Elegir PipeWire NO obligó a tocar una línea del cliente.
|
|
#
|
|
# ⚠ LLEVA UN PARCHE: `pipewire-sound-initialized.patch`. SPA descartaba TODAS las tarjetas de sonido
|
|
# porque exige la propiedad `SOUND_INITIALIZED`, que **no la pone el kernel sino udevd al correr sus
|
|
# reglas** — y acá el udev es libudev-zero, que lee /sys directo y no ejecuta reglas por diseño. El
|
|
# síntoma era un `wpctl status` con `Devices:` vacío, IDÉNTICO al de no tener ALSA en el kernel. Ver el
|
|
# parche: dice por qué se toca pipewire (radio 2) y no libudev-zero (radio 51), y por qué quitar ese
|
|
# guarda es legítimo (protege de una carrera contra udevd que sin udevd no existe).
|
|
#
|
|
# ⚠ GOTCHA DEL LAB, aprendido a la mala el 2026-07-30: **los BYTES del fichero `.patch` entran al
|
|
# ArtifactHash** (`Recipe::hash_inputs` lee el patch entero, no sólo su diff), así que **editar la PROSA
|
|
# de un parche re-sella el artefacto y todo lo que dependa de él**. Corregir un comentario obsoleto en
|
|
# `pipewire-sound-initialized.patch` re-hasheó pipewire y arrastró wireplumber.
|
|
# La distinción que conviene tener presente: **comentar una RECETA es gratis** —`hash_inputs` sólo toma
|
|
# source/compiler/target/link/flags/fases/deps, no los comentarios del TOML— **y comentar un PARCHE
|
|
# cuesta un rebuild**. Si hay que corregir el relato de un parche, hacerlo cuando se pueda pagar.
|
|
#
|
|
# ⚠ SIN GESTOR DE SESIÓN todavía (`-Dsession-managers=[]`). PipeWire arranca y acepta clientes —lo que
|
|
# quita el `Gvc-WARNING: Failed to connect context: Connection refused` del shell— pero sin
|
|
# wireplumber no enumera ni enruta dispositivos: no hay política de qué entra y qué sale. Para una VM
|
|
# sin tarjeta de sonido alcanza; **para audio de verdad falta autorar `wireplumber`** (Lua + su propio
|
|
# cierre). Queda dicho para no confundir «el shell conecta» con «hay sonido».
|
|
#
|
|
# POR QUÉ UNA COPIA EN ESTA COLA Y NO REUSAR incoming-kde/pipewire.toml: los dos cierres traen glib y
|
|
# **NO son la misma glib** — `incoming-kde/glib-shared` y `incoming-gnome/glib` producen
|
|
# `libglib-2.0.so.0.8800.1` con bytes DISTINTOS (verificado con `cmp`), y comparten 370 ficheros de
|
|
# rutas. Hidratar la receta de KDE en el rootfs de GNOME pondría las dos en la misma ruta, y una
|
|
# ganaría por orden de proyección: dos registros de GType en el mismo proceso, que es el cuadro que ya
|
|
# costó el episodio de colord. La copia resuelve contra la glib de la isla dinámica.
|
|
#
|
|
# EL PRECIO DE LA COPIA, medido: cambian `glib-shared`→`glib`, `dbus`→`dbus-shared` y
|
|
# `pcre2-shared`→`pcre2`, así que el ArtifactHash NO coincide con el de KDE y se reconstruye. Lo que
|
|
# SÍ fue gratis es `alsa-lib`: su única dep es `pkgconf`, que resuelve al catálogo PADRE, ⇒ copiarla
|
|
# dio **hash idéntico y cache hit** (b3:93cae411). Es la regla de [[frente-gnome]] sobre duplicar
|
|
# recetas entre colas, aplicada con la medición delante.
|
|
#
|
|
# Fuente del gitlab.freedesktop.org (como networkmanager/modemmanager).
|
|
# Recortado al core + SPA: sin bluez5 (cadena de códecs aptx/ldac/aac/opus enorme), sin jack/v4l2/
|
|
# libcamera/gstreamer/ffmpeg/vulkan/roc/lv2/avahi/x11/echo-cancel-webrtc/libusb/flatpak/snap.
|
|
# systemd/logind/selinux/rtkit off (no hay systemd acá). alsa=enabled + sndfile=enabled + libpulse=enabled
|
|
# (el emulador pulse: deja que los clientes libpulse hablen con pipewire) — las 3 ya selladas.
|
|
#
|
|
# SIN ncurses a propósito: la única consumidora es la tool `pw-top` (monitor de terminal), guardada por
|
|
# `if ncurses_dep.found()`. El ncurses del catálogo es static-only y su .pc arrastra `-static` al link ⇒
|
|
# "error: using shared libraries requires dynamic linking" al enlazar pw-top contra libpipewire-0.3.so.
|
|
# Quitando la dep, meson saltea pw-top y el resto construye.
|
|
name = "pipewire"
|
|
version = "1.2.7"
|
|
license = "MIT"
|
|
|
|
[source]
|
|
tarball = "https://gitlab.freedesktop.org/pipewire/pipewire/-/archive/1.2.7/pipewire-1.2.7.tar.gz"
|
|
sha256 = "e75568ed18bcbe75e9779af57cb9cc256fd7ebfaadc12bb347a0717055d1d3a9"
|
|
patches = ["pipewire-sound-initialized.patch"]
|
|
|
|
[build]
|
|
compiler = "zig-cc"
|
|
target = "x86_64-linux-musl"
|
|
link = "dynamic"
|
|
flags = []
|
|
|
|
[build.phases]
|
|
configure = '''
|
|
PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release \
|
|
-Ddefault_library=shared \
|
|
-Ddocs=disabled -Dman=disabled -Dexamples=disabled -Dtests=disabled \
|
|
-Dgstreamer=disabled -Dgstreamer-device-provider=disabled \
|
|
-Dsystemd=disabled -Dlogind=disabled -Dsystemd-system-service=disabled \
|
|
-Dsystemd-user-service=disabled -Dselinux=disabled -Dlegacy-rtkit=false \
|
|
-Dpipewire-jack=disabled -Dpipewire-v4l2=disabled -Djack=disabled -Dv4l2=disabled \
|
|
-Dlibcamera=disabled -Dbluez5=disabled -Dffmpeg=disabled -Dvulkan=disabled \
|
|
-Droc=disabled -Dlv2=disabled -Davahi=disabled -Dx11=disabled -Dx11-xfixes=disabled \
|
|
-Decho-cancel-webrtc=disabled -Dlibusb=disabled -Dflatpak=disabled -Dsnap=disabled \
|
|
-Dlibmysofa=disabled -Dsdl2=disabled -Dopus=disabled -Dlibffado=disabled -Dcompress-offload=disabled \
|
|
-Dlibcanberra=disabled -Dgsettings=disabled -Dreadline=disabled -Draop=disabled -Davb=disabled \
|
|
-Dsession-managers=[] \
|
|
-Dalsa=enabled -Dsndfile=enabled -Dlibpulse=enabled -Ddbus=enabled -Dudev=enabled \
|
|
-Dpipewire-alsa=enabled \
|
|
-Dspa-plugins=enabled -Daudioconvert=enabled -Daudiomixer=enabled -Dcontrol=enabled \
|
|
-Dvideoconvert=enabled -Dsupport=enabled
|
|
'''
|
|
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
|
|
install = '''
|
|
set -e
|
|
PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild
|
|
# ── CABLEAR EL PLUGIN ALSA, que meson instala pero NO enchufa ──────────────────────────────────
|
|
# `-Dpipewire-alsa=enabled` deja el plugin en /usr/lib/alsa-lib (que es donde alsa-lib lo busca, OK)
|
|
# y su configuración en /usr/share/alsa/alsa.conf.d — un directorio que **alsa-lib no lee**. Su
|
|
# `alsa.conf` sólo carga /var/lib/alsa/conf.d, /usr/etc/alsa/conf.d y /etc/alsa/conf.d (verificado
|
|
# en el artefacto sellado, no supuesto). Sin este enlace el plugin está instalado y no lo usa nadie:
|
|
# el caso clásico de "sellado y aun así inerte".
|
|
# Es lo mismo que hace el subpaquete `pipewire-alsa` de Alpine. Los DOS ficheros, no uno:
|
|
# 50-pipewire.conf define `pcm.pipewire` — hace que el destino EXISTA
|
|
# 99-pipewire-default.conf define `pcm.!default` — hace que sea el destino POR DEFECTO, que es
|
|
# lo que redirige a un cliente que abre "default" (mpv --ao=alsa)
|
|
mkdir -p /out/etc/alsa/conf.d
|
|
ln -sf /usr/share/alsa/alsa.conf.d/50-pipewire.conf /out/etc/alsa/conf.d/50-pipewire.conf
|
|
ln -sf /usr/share/alsa/alsa.conf.d/99-pipewire-default.conf /out/etc/alsa/conf.d/99-pipewire-default.conf
|
|
'''
|
|
|
|
[deps]
|
|
build = ["meson", "samurai", "python3", "pkgconf", "dbus-shared", "expat", "alsa-lib", "libsndfile",
|
|
"pulseaudio", "glib", "pcre2", "libffi", "libudev-zero", "zlib-shared", "gettext-tiny"]
|