diff --git a/docs/evidencia/cosmic-wireplumber-wpctl-2026-08-05.png b/docs/evidencia/cosmic-wireplumber-wpctl-2026-08-05.png new file mode 100644 index 00000000..c99c8516 Binary files /dev/null and b/docs/evidencia/cosmic-wireplumber-wpctl-2026-08-05.png differ diff --git a/docs/runbooks/cosmic-desktop.md b/docs/runbooks/cosmic-desktop.md index 5dab1c7d..999e8e76 100644 --- a/docs/runbooks/cosmic-desktop.md +++ b/docs/runbooks/cosmic-desktop.md @@ -1090,6 +1090,46 @@ esperarlo. Es una hipótesis, no una medición — construir `wireplumber` la co - Y uno de shell, al automatizar por QMP: **`| head -N` bufferiza** y deja la terminal en blanco hasta que el programa termina. Parece que la sonda colgó cuando en realidad está esperando. +## 🔇 wireplumber: construido, corriendo… y NO era el bloqueo (2026-08-05) + +`recipes/incoming-cosmic/wireplumber.toml` 0.5.15 → **`b3:b8f3baf0`**, selló a la primera. Arranca +desde `cosmic-start` (`wireplumber OK (pid 192) — hay gestor de sesión`), se conecta al grafo (dos +clientes en `wpctl status`) y `wpctl` pasa a mostrar una sección **Video** que antes no existía. + +**Y el `Start` de ScreenCast sigue sin `Response` a los 60s. Exactamente el mismo resultado.** + +La hipótesis de la sección anterior —«falta el gestor de sesión que mueva el nodo de `Paused` a +`Streaming`»— **queda MATADA por medición**. Era mía y era razonable; no era cierta. Se deja escrita +junto con su refutación porque una hipótesis descartada con evidencia vale más que una lista de +sospechosos: acota el próximo paso a lo que queda, que es el propio backend. + +El dato nuevo, que es por dónde seguir: con wireplumber corriendo, `wpctl status` lista +`Video → Streams` **vacío** durante el handshake. O sea que el nodo `cosmic-screencast` que sí existe +en `pw-cli ls Node` **no llega a wireplumber como stream gestionado**. El próximo movimiento es el log +del backend con `RUST_LOG=trace` alrededor de `screencast_thread`, no otra dep. + +### Por qué es una receta propia y no la de GNOME + +La de `incoming-gnome` está sellada y funciona, pero su binario NEEDea `libglib-2.0.so.0`, +`libgobject-2.0.so.0` y `libpipewire-0.3.so.0` **de la isla dinámica de GNOME**: traerla tal cual +metería una segunda glib y una segunda pipewire en la imagen. De las 19 deps, **14 dan hash idéntico** +y las que divergen divergen a propósito — sobre todo `pipewire`, que acá apunta a la de COSMIC +(`338d1d8c`), la que el escritorio realmente arranca. Un gestor de sesión contra otra pipewire que la +que corre no gestiona nada. + +**El cambio de fondo es `glib` → `glib-shared`.** COSMIC usa la glib ESTÁTICA del corpus, que le +alcanza a `xdg-desktop-portal` porque es un ejecutable. Acá no: wireplumber produce +`libwireplumber-0.5.so` y 17 módulos, y `libglib-2.0.a` del corpus tiene **44.275 reubicaciones +`R_X86_64_32/32S`** ⇒ no es PIC y no entra en un `.so`. (Regla del frente GNOME: `readelf -r` ANTES de +gastar el build — acá ahorró uno.) + +La salida no fue una campaña nueva sino una **medición**: `incoming-kde/glib-shared.toml` copiada a +esta cola resuelve al **mismo hash** (`0584ce1f`) y **ya estaba sellada** ⇒ cero rebuild. Idem +`pcre2-shared` (`f254abaa`), `lua` (`e6c35f98`) y `libelogind` (`f1a690b2`). Las dos glib **coexisten +sin pisarse** en el rootfs: `.a` y `.so` son ficheros distintos, y el portal conserva sus 3 NEEDED. + +Cierre: `escritorio-cosmic` pasa de 84 a **89 recetas**, 0 faltantes. + ### El `-L/usr/lib` que pkg-config no da `pkg-config` **omite los `-L` de directorios que considera estándar del sistema**, asumiendo que el @@ -1105,11 +1145,12 @@ existe, y eso cuesta igual que un bug. ## Lo que falta, en orden -1. ~~Arrancar el demonio de pipewire~~ ✅ y ~~el cliente persistente~~ ✅ (`portal-probe`, `b3:af49d32d`). - **Lo que queda es `wireplumber`**: el stream de ScreenCast se crea y llega a `Paused`, con nodo - `cosmic-screencast` visible en pipewire, pero nadie lo pasa a `Streaming` y el backend no emite el - `Response`. La hipótesis es que falta el gestor de sesión — construirlo la confirma o la mata. - Falta también correr `portal-probe filechooser`, que ya puede capturar la URI. +1. ~~Demonio de pipewire~~ ✅, ~~cliente persistente~~ ✅ (`portal-probe`, `b3:af49d32d`), + ~~`wireplumber`~~ ✅ (`b3:b8f3baf0`) — **y wireplumber NO era el bloqueo**: el `Start` sigue sin + `Response`. Lo que queda es el **backend mismo**: con `RUST_LOG=trace` alrededor de + `screencast_thread`, mirando por qué el nodo que sí existe en `pw-cli ls Node` no aparece como + `Video → Streams` en `wpctl`. Falta también correr `portal-probe filechooser`, que ya puede + capturar la URI. 2. **Decidir `gvfs`** (ver la corrección de arriba: las piezas ya están selladas, lo que falta es la decisión sobre la segunda glib). Destrabaría los montajes remotos de cosmic-files y su applet. 3. **Enchufar la tienda a `.swm`**: servir `org.freedesktop.PackageKit` y encender la feature diff --git a/docs/state/targets.toml b/docs/state/targets.toml index d59ce729..43ac29e5 100644 --- a/docs/state/targets.toml +++ b/docs/state/targets.toml @@ -137,6 +137,11 @@ paquetes = [ # porque nadie la declara como dep y sin ella el perfil no incluiría con qué verificarse a sí # mismo — un handshake de portal sólo se puede ejercer DESDE la sesión, con bus y compositor vivos. "portal-probe", + # El GESTOR DE SESIÓN de pipewire. Se lista como raíz porque ningún `[deps]` lo alcanza: es un + # CLIENTE del demonio, no una librería de nadie. Trae consigo la glib COMPARTIDA (`glib-shared`), + # que no es la estática que usa el resto de la cola — wireplumber produce `.so` y la estática del + # corpus no es PIC. Construido y corriendo; NO desbloqueó ScreenCast (ver el runbook). + "wireplumber", # Datos, no binarios: el tema de iconos (y el hicolor del que hereda), las tablas de xkb y una # tipografía. Ninguno es dep de build de nadie y sin ellos el escritorio arranca roto — sin puntero, # sin teclado o con tofu. diff --git a/recipes/incoming-cosmic/glib-shared.toml b/recipes/incoming-cosmic/glib-shared.toml new file mode 100644 index 00000000..555e1116 --- /dev/null +++ b/recipes/incoming-cosmic/glib-shared.toml @@ -0,0 +1,32 @@ +# glib-shared 2.88.1 — variante DINÁMICA (libglib-2.0.so.0 + libgobject/libgio/libgmodule/libgthread) +# para el escritorio KDE. El canónico (recipes/glib.toml) es `-Ddefault_library=static --prefer-static` +# (sólo .a) ⇒ no enlaza dentro de un .so. Es la **deuda Capa 0 "glib shared-PIC"** que el ADR 0011 arrastra +# desde plasma-workspace (se esquivó parcheando NetworkManagerQt a opcional). +# +# glib es foundational para el resto del escritorio: libnm (NetworkManager→plasma-nm), polkit (auth), +# xdg-desktop-portal, gstreamer. Esta variante lo destraba. +# +# Deps: libffi ya es PIC (--with-pic en el canónico, enlazable en .so) ⇒ no necesita variante. +# pcre2-shared SÍ (el pcre2 canónico no tiene --with-pic). zlib-shared por el libz.so versionado. +# Se conservan los switches del canónico (tests/nls/libmount/selinux/introspection off) para no arrastrar +# deps nuevas; sólo cambia el modo de librería. +name = "glib-shared" +version = "2.88.1" + +[source] +tarball = "https://download.gnome.org/sources/glib/2.88/glib-2.88.1.tar.xz" +sha256 = "51ab804c56f6eab3e5045c774d1290ac5e4c923d4f9a3d8e33123bee45c1840e" + +[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 -Dtests=false -Dnls=disabled -Dlibmount=disabled -Dselinux=disabled -Dman-pages=disabled -Dintrospection=disabled -Dglib_debug=disabled -Dglib_assert=false -Dglib_checks=false" +compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output" +install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild" + +[deps] +build = ["meson", "samurai", "python3", "pkgconf", "libffi", "pcre2-shared", "zlib-shared"] diff --git a/recipes/incoming-cosmic/libelogind.toml b/recipes/incoming-cosmic/libelogind.toml new file mode 100644 index 00000000..d6dee0e5 --- /dev/null +++ b/recipes/incoming-cosmic/libelogind.toml @@ -0,0 +1,69 @@ +# libelogind — la C-ABI `sd-login` que le faltaba a la distro, implementada en arje-compat. +# +# QUÉ RESUELVE: mutter (y polkit, gcr, at-spi2-core) exigen un proveedor de logind por pkg-config — +# `libsystemd` o `libelogind`— para llamar la API C sd-login. Esa API NO es un cliente D-Bus: lee +# `/run/systemd/{sessions,users,seats}`. Los otros tres tienen perilla para esquivarla y se +# construyeron por su camino degradado; **mutter no tiene**, porque `-Dudev=false` exige +# `-Dlogind=false` (mutter/meson.build:257) y sin udev+logind no hay backend nativo KMS: no hay +# compositor de verdad, sólo anidado. +# +# POR QUÉ NO ES elogind NI UN STUB: `arje-logind-compat` ya escribe ese estado en /run/systemd (ver +# `arje_compat::login_state`). Lo único que faltaba era una librería que lo LEYERA y lo ofreciera en +# C. `arje-sdlogin-compat` hace exactamente eso — no inventa datos ni levanta un daemon paralelo. +# Empaquetar elogind sería traer un logind entero a competirle al que arje ya tiene. +# +# Corrige de paso lo que afirma el comentario de recipes/arje-logind-compat.toml («no hace falta la +# C-ABI sd-login… los escritorios consultan login1 en RUNTIME por D-Bus»): es cierto para los +# clientes D-Bus y FALSO para mutter, que la enlaza. +# +# HUB-ONLY, como toda receta de fuente tawasuyu: la gitea escucha en :2345 y el worker efímero es +# secretless ⇒ recibe Connection refused en :22. Se muele en el hub. +name = "libelogind" +version = "0.0.1" + +[source] +# El `commit` es el identificador inmutable; la URL es sólo locator y NO entra al ArtifactHash. +# Rama `selfhost/arje-zero-attest-lockfile`, igual que arje-logind-compat, porque es la única que +# versiona el `Cargo.lock` de la raíz: sin él, el vendoreo `--locked` del fetch no es reproducible +# (el monorepo lo gitignora en main). +repo = "gitea@git.tawasuyu.net:tawasuyu/tawasuyu.git" +commit = "749edfe41766e098d3eb18561c6a396610c5cd8e" +# El monorepo COMMITEA su propio `vendor/` (`[patch.crates-io] smithay = { path = "vendor/smithay" }`, +# la copia parcheada que mirada necesita para el tearing) y el `cargo vendor` de hammer escribe ahí +# por defecto, pisándolo: el build muere con `failed to read /src/vendor/smithay/.cargo-checksum.json` +# al resolver la dep git de taffy. Se vendorea a un subdir aparte, igual que arje-logind-compat. +# Apareció recién ahora porque el `vendor/` entró a esta rama con el merge de main, no antes. +# Ver [[hammer-cargo-vendor-clobbers-project-vendor]]. +cargo_vendor_dir = ".hammer-cargo-vendor" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +# dynamic, no static: el producto ES una librería compartida (cdylib). Con `link = "static"` el lab +# exporta -static y no hay .so que valga. +link = "dynamic" +flags = ["-p", "arje-sdlogin-compat"] + +[build.phases] +# Sólo se sobrescribe `install`: el `compile` por defecto del lab (cargo build --release, offline y +# vendoreado) es el correcto. El default de Cargo copia EJECUTABLES a /usr/bin, y acá no hay ninguno: +# hay una .so, una cabecera y un .pc. +# +# El SONAME (libelogind.so.0) lo fija el build.rs del crate, no esta receta, para que un `cargo build` +# a mano también produzca algo enlazable. Por eso el fichero se instala directamente con ese nombre y +# el `libelogind.so` es el symlink de desarrollo que busca el linker. +# +# La cabecera va a /usr/include/elogind/systemd/ y el .pc trae `-I${includedir}/elogind`: así el +# `#include ` de mutter resuelve sin que mutter sepa que somos nosotros. Es el +# mismo arreglo de elogind upstream. +install = ''' +set -e +mkdir -p /out/usr/lib/pkgconfig /out/usr/include/elogind/systemd +cp target/release/libelogind.so /out/usr/lib/libelogind.so.0 +ln -s libelogind.so.0 /out/usr/lib/libelogind.so +cp 03_ukupacha/arje/arje-sdlogin-compat/include/systemd/sd-login.h /out/usr/include/elogind/systemd/ +# sd-daemon.h va aparte porque en systemd también son dos cabeceras y quien la usa la pide por su +# nombre: gdm hace `#include ` en common/gdm-log.c para `sd_booted()`. +cp 03_ukupacha/arje/arje-sdlogin-compat/include/systemd/sd-daemon.h /out/usr/include/elogind/systemd/ +cp 03_ukupacha/arje/arje-sdlogin-compat/pkgconfig/libelogind.pc /out/usr/lib/pkgconfig/ +''' diff --git a/recipes/incoming-cosmic/lua.toml b/recipes/incoming-cosmic/lua.toml new file mode 100644 index 00000000..95c23872 --- /dev/null +++ b/recipes/incoming-cosmic/lua.toml @@ -0,0 +1,95 @@ +# lua 5.4.8 — el intérprete y **la librería compartida**, que es lo que hace falta acá. +# +# POR QUÉ ENTRA: `wireplumber` —el gestor de sesión de PipeWire, sin el cual PipeWire acepta clientes +# pero no enumera ni enruta dispositivos— tiene su política escrita EN LUA y embebe un intérprete +# (`lib/wplua`). Su `subprojects/lua.wrap` DESCARGA Lua 5.5 de lua.org, cosa imposible en el sandbox +# hermético (`--wrap-mode=nodownload`), así que va con `-Dsystem-lua=true` y el sistema tiene que +# tener Lua. Su meson acepta 5.5, 5.4 o 5.3 (meson.build:91-95); se elige **5.4**, la serie estable +# larga que usan las distros, en vez de la 5.5 del wrap. +# +# ══ LO QUE ESTA RECETA TIENE QUE INVENTAR, porque upstream no lo da ═════════════════════════════ +# El Makefile de Lua sólo produce `liblua.a` y los binarios. **No hay regla de `.so` ni fichero +# pkg-config**: los agrega cada distro. Acá se agregan las dos cosas, y a mano, porque no hay dónde +# copiarlas de: +# +# 1. `-fPIC` en `MYCFLAGS`. Sin esto la `.a` no es reubicable y `libwplua` —que es un objeto +# compartido— no linkea: es la regla del corpus sobre `.a` no-PIC dentro de un `.so` +# («relocation R_X86_64_32 … recompile with -fPIC»), la misma que obligó a las variantes +# `-shared` de zlib, sqlite, libxml2, libuuid y dbus. +# 2. La `.so` se enlaza a mano desde la `.a` con `--whole-archive`, porque una librería estática sólo +# aporta los objetos que alguien referencia y acá hay que llevárselos TODOS. SONAME +# `liblua-5.4.so.0`, que es el que graba quien enlace. +# 3. El `.pc` se escribe acá. El nombre importa: wireplumber prueba `lua-5.4`, `lua5.4` y `lua54` en +# ese orden, así que el fichero se llama `lua5.4.pc` y ADEMÁS se deja `lua-5.4.pc` y `lua.pc` como +# enlaces — es más barato satisfacer las tres convenciones que adivinar cuál buscará el próximo +# consumidor. +# +# `-DLUA_USE_LINUX` es lo que activa `dlopen` y el resto de POSIX; sin él Lua se compila en modo ANSI +# genérico y `require` de módulos C no funciona. **SIN readline a propósito**: sólo lo usa el REPL +# interactivo, y el ncurses del catálogo es static-only y arrastra `-static` al link (el mismo +# problema que hizo saltar `pw-top` en la receta de pipewire). +# +# `SYSLIBS` pierde el `-Wl,-E` de upstream: exportar todos los símbolos del EJECUTABLE sirve para que +# módulos C cargados por `require` vean la API de Lua, y acá el que exporta es la `.so`. +name = "lua" +version = "5.4.8" + +[source] +tarball = "https://www.lua.org/ftp/lua-5.4.8.tar.gz" +sha256 = "4f18ddae154e793e46eeab727c59ef1c0c0c2b744e7b94219710d76f530629ae" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "dynamic" + +[build.phases] +configure = "true" +compile = ''' +set -e +# CC se pasa explícito: el Makefile de Lua lo fija a `gcc -std=gnu99` en la línea 9 y ganaría sobre el +# del entorno. +make -C src all CC="hammer-zig-cc -std=gnu99" \ + SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-ldl" MYCFLAGS="-fPIC" +# La .so que upstream no construye. --whole-archive porque de una estática el linker sólo se lleva lo +# referenciado, y acá hay que llevárselo todo. +hammer-zig-cc -shared -o src/liblua-5.4.so.0.0.0 \ + -Wl,-soname,liblua-5.4.so.0 \ + -Wl,--whole-archive src/liblua.a -Wl,--no-whole-archive -lm +''' +install = ''' +set -e +mkdir -p /out/usr/bin /out/usr/lib/pkgconfig /out/usr/include /out/usr/share/man/man1 +install -m755 src/lua /out/usr/bin/lua5.4 +install -m755 src/luac /out/usr/bin/luac5.4 +ln -s lua5.4 /out/usr/bin/lua +ln -s luac5.4 /out/usr/bin/luac +install -m644 src/lua.h src/luaconf.h src/lualib.h src/lauxlib.h src/lua.hpp /out/usr/include/ +install -m644 src/liblua.a /out/usr/lib/liblua-5.4.a +install -m755 src/liblua-5.4.so.0.0.0 /out/usr/lib/ +ln -s liblua-5.4.so.0.0.0 /out/usr/lib/liblua-5.4.so.0 +ln -s liblua-5.4.so.0 /out/usr/lib/liblua-5.4.so +ln -s liblua-5.4.so /out/usr/lib/liblua.so +cat > /out/usr/lib/pkgconfig/lua5.4.pc <<'PC' +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include +INTERPRETER=${exec_prefix}/bin/lua5.4 +COMPILER=${exec_prefix}/bin/luac5.4 + +Name: Lua +Description: Lua language engine +Version: 5.4.8 +Requires: +Libs: -L${libdir} -llua-5.4 -lm +Cflags: -I${includedir} +PC +# Las tres convenciones de nombre que se usan por ahí; wireplumber prueba lua-5.4, lua5.4 y lua54. +ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua-5.4.pc +ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua54.pc +ln -s lua5.4.pc /out/usr/lib/pkgconfig/lua.pc +''' + +[deps] +build = ["make", "pkgconf"] diff --git a/recipes/incoming-cosmic/pcre2-shared.toml b/recipes/incoming-cosmic/pcre2-shared.toml new file mode 100644 index 00000000..7ebc72d7 --- /dev/null +++ b/recipes/incoming-cosmic/pcre2-shared.toml @@ -0,0 +1,36 @@ +# pcre2-shared 10.47 — variante DINÁMICA (libpcre2-8.so.0, PIC) para el escritorio KDE. +# El canónico (recipes/pcre2.toml) es --disable-shared SIN --with-pic ⇒ su .a no enlaza dentro de un .so. +# Lo exige glib-shared (libglib-2.0.so linkea pcre2 para GRegex). Deuda Capa 0 (static↔dinámico). +# +# compiler=gcc igual que el canónico: su comentario advierte que zig-cc MISCOMPILA libs C (patrón file/jq); +# el gcc del rootfs es musl, y el .so resultante es ABI-compatible con los consumidores zig. +# --disable-symvers como el canónico (musl no maneja symbol versioning de la forma que asume pcre2). +name = "pcre2-shared" +version = "10.47" + +[source] +tarball = "https://github.com/PhilipHazel/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.bz2" +sha256 = "47fe8c99461250d42f89e6e8fdaeba9da057855d06eb7fc08d9ca03fd08d7bc7" + +[build] +compiler = "gcc" +target = "x86_64-linux-musl" +link = "dynamic" +flags = [] + +[build.phases] +compile = ''' +./configure \ + --build=$CBUILD --host=$CHOST \ + --prefix=/usr \ + --enable-shared --disable-static \ + --enable-pcre2-16 --enable-pcre2-32 \ + --enable-jit \ + --enable-pcre2grep-libz \ + --disable-symvers +make -j"$(nproc)" +''' +install = "make DESTDIR=/out install && find /out -name '*.la' -delete" + +[deps] +build = ["zlib-shared"] diff --git a/recipes/incoming-cosmic/wireplumber.toml b/recipes/incoming-cosmic/wireplumber.toml new file mode 100644 index 00000000..ab1cec75 --- /dev/null +++ b/recipes/incoming-cosmic/wireplumber.toml @@ -0,0 +1,86 @@ +# wireplumber 0.5.15 — EL GESTOR DE SESIÓN de PipeWire, en la variante de COSMIC. +# +# ── POR QUÉ EXISTE ESTA COPIA Y NO SE REUSA LA DE GNOME ───────────────────────────────────────── +# `recipes/incoming-gnome/wireplumber.toml` está sellada y funciona, pero su binario NEEDea +# `libglib-2.0.so.0`, `libgobject-2.0.so.0` y `libpipewire-0.3.so.0` **de la isla dinámica de GNOME**. +# Traerlo tal cual a la imagen de COSMIC significaría meter una segunda glib y una segunda pipewire — +# justo el choque de 370 ficheros solapados que la campaña midió y evitó. +# +# La regla del runbook es que copiar entre colas sale gratis **sólo si toda la clausura resuelve +# igual**. Acá NO resuelve igual, y eso es lo que se quiere: de las 19 deps, 14 dan hash idéntico y +# las que divergen divergen A PROPÓSITO —`pipewire` apunta a la de COSMIC (`338d1d8c`), que es la que +# el escritorio realmente ARRANCA. Un gestor de sesión contra otra pipewire que la que corre no +# gestiona nada. +# +# ── EL CAMBIO DE FONDO: `glib` → `glib-shared` ────────────────────────────────────────────────── +# COSMIC usa la `glib` ESTÁTICA del corpus (le sirve a `xdg-desktop-portal`, que es un ejecutable). +# Acá no alcanza: wireplumber produce `libwireplumber-0.5.so` y sus módulos, y la estática del corpus +# tiene **44.275 reubicaciones `R_X86_64_32/32S`** en `libglib-2.0.a` ⇒ no es PIC y no se puede +# enlazar dentro de un `.so`. (Regla del frente GNOME: `readelf -r` ANTES de gastar un build.) +# +# La salida no fue una campaña nueva sino una MEDICIÓN: `incoming-kde/glib-shared.toml` copiada acá +# resuelve al **mismo hash** (`0584ce1f`) y **ya está sellada** ⇒ cero rebuild. Idem `pcre2-shared` +# (`f254abaa`), `lua` (`e6c35f98`) y `libelogind` (`f1a690b2`), traídas por la misma razón: no existen +# en el catálogo padre y sus hashes coinciden con los de su cola de origen. +# +# ── LO QUE APORTA, Y POR QUÉ HACE FALTA ACÁ ───────────────────────────────────────────────────── +# `pipewire` se construye con `-Dsession-managers=[]`: arranca, acepta clientes y sirve —el portal ya +# figura como cliente suyo— pero **no hay política** de qué es entrada, qué es salida, ni quién mueve +# un nodo de `Paused` a `Streaming`. Y ahí está parado ScreenCast: el backend crea el nodo +# (`cosmic-screencast`, `Video/Source`, visible en `pw-cli ls Node`), su log dice +# `state-changed 'Connecting' -> 'Paused'`… y no emite el `Response`. La hipótesis a confirmar o +# matar con esta receta es que falta exactamente esto. +# +# La política está escrita EN LUA: embebe un intérprete (`lib/wplua`) y sus reglas viven en +# `src/scripts/*.lua`. Por eso la dep interesante no es PipeWire sino **`lua`**. +# +# `-Dsystem-lua=true` es obligatorio: por defecto usa su `subprojects/lua.wrap`, que **DESCARGA Lua +# 5.5 de lua.org**, y el sandbox va con `--wrap-mode=nodownload`. Con la perilla prendida busca por +# pkg-config `lua-5.5`/`lua5.5`/`lua55`, después las 5.4 y después las 5.3 (meson.build:91-95): +# nuestra `lua5.4.pc` entra por la segunda tanda. +# +# `-Delogind=enabled` — la C-ABI de logind otra vez, y acá la sirve `arje-sdlogin-compat`, el mismo +# shim que en el resto del fractal. wireplumber la usa para saber si la sesión está activa antes de +# tomar los dispositivos, que es justo el problema que ese shim resuelve. +# +# Apagados: `-Dsystemd=disabled` y sus units (PID1 es arje-zero y el arranque lo hace `cosmic-start`); +# `-Ddoc=disabled` (falta sphinx/doxygen); `-Dtests=false -Ddbus-tests=false`; `-Dintrospection=disabled` +# porque nadie carga `Wp-0.5` por typelib. +name = "wireplumber" +version = "0.5.15" + +[source] +tarball = "https://gitlab.freedesktop.org/pipewire/wireplumber/-/archive/0.5.15/wireplumber-0.5.15.tar.gz" +sha256 = "baa121bc918df5fa0e0e70755bb1c99ffab0ab107225ecf99aa470e2c6ba5e7b" + +[build] +compiler = "zig-cc" +target = "x86_64-linux-musl" +link = "dynamic" + +[build.phases] +# Sin `rm -rf output`: con el árbol de fuentes compartido (ADR 0012) borrar el dir de build es +# sabotear a quien esté compilando en paralelo. Lección heredada de la receta de GNOME. +configure = ''' +set -e +PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output \ + --prefix=/usr --buildtype=release --wrap-mode=nodownload \ + -Ddefault_library=shared \ + -Dsystem-lua=true -Dsystem-lua-version=auto \ + -Delogind=enabled -Dsystemd=disabled \ + -Dsystemd-system-service=false -Dsystemd-user-service=false \ + -Dintrospection=disabled -Ddoc=disabled \ + -Dtests=false -Ddbus-tests=false \ + -Dc_args=-Wno-error=date-time +''' +compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output" +install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild" + +[deps] +# Difiere de la de GNOME en cuatro nombres, y los cuatro a propósito: `glib-shared` en vez de `glib` +# (la estática no es PIC), `pcre2-shared` en vez de `pcre2` (coherencia con lo que el `.pc` de +# glib-shared declara), y `pipewire`/`pulseaudio` que resuelven a los de ESTA cola — los que el +# escritorio arranca. +build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "lua", "pipewire", + "glib-shared", "dbus-shared", "libelogind", "alsa-lib", "libsndfile", "pulseaudio", + "expat", "pcre2-shared", "libffi", "libudev-zero", "zlib-shared"] diff --git a/scripts/cosmic/cosmic-start-qemu.sh b/scripts/cosmic/cosmic-start-qemu.sh index 35d27df8..c5c48c40 100755 --- a/scripts/cosmic/cosmic-start-qemu.sh +++ b/scripts/cosmic/cosmic-start-qemu.sh @@ -170,6 +170,34 @@ else say "!! sin /usr/bin/pipewire — ScreenCast no va a poder crear stream" fi +# ── EL GESTOR DE SESIÓN: wireplumber ──────────────────────────────────────────────────────────── +# pipewire se construye con `-Dsession-managers=[]`, o sea que arranca y sirve pero NO TIENE +# POLÍTICA: nada decide qué es entrada, qué es salida, ni quién mueve un nodo de `Paused` a +# `Streaming`. wireplumber es esa política, escrita en Lua. +# +# Por qué está acá y no antes: **necesita el socket de pipewire ya abierto**. Se lanza después a +# propósito, no por orden estético — un gestor de sesión sin demonio que gestionar sale con error. +# +# Acá NO se puede esperar un socket, porque wireplumber no abre ninguno: es un CLIENTE de pipewire, +# no un servidor. Lo que dice que hizo su trabajo es que aparezca como cliente en el grafo +# (`pw-cli ls Client`), y eso es una medición del sistema, no una condición de arranque. Así que se +# espera un instante y se reporta si el proceso sigue vivo — con el log a mano, que es lo que sirve +# cuando falla. +if [ -x /usr/bin/wireplumber ] && [ -S "$XDG_RUNTIME_DIR/pipewire-0" ]; then + /usr/bin/wireplumber >/tmp/wireplumber.log 2>&1 & + WP_PID=$! + sleep 2 + if alive $WP_PID; then + say "wireplumber OK (pid $WP_PID) — hay gestor de sesión" + else + say "!! wireplumber MURIÓ:"; dump /tmp/wireplumber.log + fi +elif [ -x /usr/bin/wireplumber ]; then + say "!! wireplumber presente pero sin socket de pipewire — no se lanza" +else + say "-- sin wireplumber (pipewire sirve, pero sin política de sesión)" +fi + # ── FONDO: color liso, porque la imagen por defecto NO SE PUEDE EMPAQUETAR ──────────────────── # El default de cosmic-bg apunta a `/usr/share/backgrounds/cosmic/orion_nebula_nasa_heic0601a.jpg`, # que vive en el repo `cosmic-wallpapers`… en **git-lfs**: el tarball de GitHub pesa 20 KB y trae diff --git a/scripts/cosmic/hydrate-cosmic.sh b/scripts/cosmic/hydrate-cosmic.sh index 2e6ce37e..e329bba4 100755 --- a/scripts/cosmic/hydrate-cosmic.sh +++ b/scripts/cosmic/hydrate-cosmic.sh @@ -84,6 +84,11 @@ else # con el bus y el compositor vivos— y sale estática, sin un NEEDED, justamente para que nunca # falle por algo del sistema que está midiendo. recipes/incoming-cosmic/portal-probe.toml + # El GESTOR DE SESIÓN de pipewire. Ningún `[deps]` lo alcanza —es un cliente del demonio, no una + # librería de nadie— así que es raíz a mano como todo lo que se lanza por PATH. Trae consigo la + # glib COMPARTIDA (`glib-shared`), que no es la estática que usa el resto de la cola: wireplumber + # produce `.so` y la estática del corpus no es PIC. + recipes/incoming-cosmic/wireplumber.toml recipes/incoming-cosmic/cosmic-app-library.toml recipes/incoming-cosmic/cosmic-workspaces-epoch.toml # Ni binario ni librería: DATOS. El tema de iconos de COSMIC — sin él el escritorio no se ve