⚠ ESTE PARCHE NO ERA EL BLOQUEO — leer antes de sacar conclusiones. Se escribió creyendo que `SOUND_INITIALIZED` era lo que impedía enumerar, y **no lo era**: con el parche aplicado, `wpctl status` seguía dando `Devices:` vacío. La causa real está más abajo en el mismo fichero y es ESTRUCTURAL, no una propiedad que falte (ver la nota al final). El parche se conserva porque la incompatibilidad que describe es REAL y volvería a morder en cuanto la enumeración funcione: sin él, SPA descarta toda tarjeta en un sistema sin udevd. Pero no es la solución del problema de audio. pipewire/SPA: no exigir `SOUND_INITIALIZED`, una propiedad que sólo pone udevd con sus reglas. EL SÍNTOMA, y por qué es caro de leer: con ALSA encendido en el kernel, la tarjeta detectada y `/dev/snd/controlC0` presente, `wpctl status` seguía dando Audio ├─ Devices: ← vacío ├─ Sinks: * 33. Dummy Output o sea el MISMO cuadro que cuando no había kernel con sonido. Tres cosas distintas —no hay ALSA, no hay tarjeta, hay tarjeta y el stack no la ve— se ven idénticas en esa salida. LA CAUSA, en la fuente: `spa/plugins/alsa/alsa-udev.c:167` if (udev_device_get_property_value(udev_device, "SOUND_INITIALIZED") == NULL) return SPA_ID_INVALID; /* descarta la tarjeta */ `SOUND_INITIALIZED` no es una propiedad del kernel: **la pone udevd al ejecutar sus reglas** (`78-sound-card.rules` de systemd/eudev marca la tarjeta cuando todos sus devices están listos). Esta distro usa **libudev-zero**, que lee /sys directo y NO EJECUTA REGLAS por diseño — su `udev_enumerate_scan_devices` recorre `/sys/dev/block` y `/sys/dev/char`, así que la tarjeta SÍ se enumera, pero llega sin esa propiedad. Resultado: SPA descarta todas las tarjetas, siempre. POR QUÉ SE PARCHEA PIPEWIRE Y NO libudev-zero: sintetizar `SOUND_INITIALIZED` en libudev-zero sería igual de correcto, pero `yupana radio libudev-zero` da **51 artefactos sellados cayendo a deuda** — está en el cierre de las cinco imágenes. El radio de pipewire son 2. Se paga el barato. POR QUÉ QUITAR EL GUARDA ES LEGÍTIMO Y NO UN ATAJO: ese `if` existe para no correr una carrera contra udevd —evitar tomar una tarjeta cuyos devices todavía no aparecieron—. **Con libudev-zero no hay udevd, así que no hay carrera que perder**: cuando `/sys/dev/char` lista el device, el device existe. Se elimina una comprobación cuya premisa no se cumple acá, no una que nos moleste. Lo que NO se toca: los otros tres guardas del mismo bloque (`ACP_IGNORE`, `SOUND_CLASS=modem`, `DEVPATH`). Los dos primeros son opt-out explícitos del administrador y el tercero es un dato real del kernel — ésos siguen valiendo. diff -Naur a/spa/plugins/alsa/alsa-udev.c b/spa/plugins/alsa/alsa-udev.c --- a/spa/plugins/alsa/alsa-udev.c +++ b/spa/plugins/alsa/alsa-udev.c @@ -164,8 +164,13 @@ if ((str = udev_device_get_property_value(udev_device, "SOUND_CLASS")) && spa_streq(str, "modem")) return SPA_ID_INVALID; - if (udev_device_get_property_value(udev_device, "SOUND_INITIALIZED") == NULL) - return SPA_ID_INVALID; + /* hammer: NO exigir SOUND_INITIALIZED. Esa propiedad la pone udevd al correr + * 78-sound-card.rules, y esta distro usa libudev-zero, que lee /sys directo y no + * ejecuta reglas. El guarda existe para no competir con udevd por una tarjeta a + * medio inicializar; sin udevd no hay carrera: si /sys/dev/char lista el device, + * el device esta. Ver recipes/incoming-gnome/pipewire-sound-initialized.patch. + * Los otros guardas de este bloque (ACP_IGNORE, SOUND_CLASS=modem, DEVPATH) se + * respetan tal cual: son opt-out del administrador o datos reales del kernel. */ if ((str = udev_device_get_property_value(udev_device, "DEVPATH")) == NULL) return SPA_ID_INVALID; ══ LO QUE SÍ BLOQUEA, medido después ═════════════════════════════════════════════════════════════ `get_card_nr` sigue con dos comprobaciones más (alsa-udev.c:178-183): if ((e = strrchr(str, '/')) == NULL) return SPA_ID_INVALID; if (strlen(e) <= 5 || strncmp(e, "/card", 5) != 0) return SPA_ID_INVALID; o sea que **sólo acepta el device CARD** (`/sys/.../sound/card0`), no `controlC0` ni `pcmC0D0p`. Y `card0` es un device de CLASE: no tiene major:minor, no tiene nodo en /dev. `udev_enumerate_scan_devices` de libudev-zero recorre **exclusivamente** `/sys/dev/block` y `/sys/dev/char` (udev_enumerate.c:281) — o sea sólo devices CON nodo. El udev real enumera `/sys/class/*` entero, con nodo o sin él. ⇒ **El device que SPA necesita nunca entra en la enumeración.** No hay guarda que sacar: falta la mitad del espacio de búsqueda. **YA RESUELTO (2026-07-30)**, y por el camino (a): `recipes/libudev-zero-scan-class.patch` enseña a libudev-zero a enumerar devices de CLASE para una lista acotada de subsistemas (hoy `sound`). Se descartó eudev porque sin udevd es PEOR —rompió el input en otro frente— y correr udevd contradice la arquitectura. El audio funciona: `48. HDA Intel [alsa]` con sink y source reales. Los detalles, y por qué la lista es acotada (recorrer `/sys/class` entero rompía el VÍDEO), están en ese parche.