# speech-dispatcher 0.12.1 — el SERVIDOR de voz. Es lo que convierte «la distro habla» en # «las aplicaciones de la distro pueden hablar». # # ══ QUÉ AÑADE SOBRE espeak-ng, QUE YA ESTÁ ═════════════════════════════════════════════════════ # `espeak-ng` es un sintetizador: un proceso que recibe texto y hace ruido. Si cada aplicación lo # invoca por su cuenta, dos que hablen a la vez se pisan, nadie puede interrumpir a nadie, y cambiar # de voz o de velocidad es cosa de cada app. `speech-dispatcher` es la capa que falta: un daemon con # COLA y PRIORIDADES, una API estable (`libspeechd` en C y el módulo `speechd` en Python), y los # sintetizadores detrás como módulos intercambiables. # # ⇒ Es la dep que `orca` —el lector de pantalla— usa para hablar, y también lo que hace que # `spd-say "hola"` funcione desde cualquier script. Sin esto, el hueco de accesibilidad del censo # sigue abierto aunque la máquina ya tenga voz. # # ══ LO QUE PIDE, MEDIDO EN SU `configure.ac` ═══════════════════════════════════════════════════ # De sus once `PKG_CHECK_MODULES`, **obligatorios**: `glib-2.0`, `gthread-2.0`, `gmodule-2.0` # (los tres los da `glib`), `sndfile` y **`dotconf >= 1.3`**. El resto va detrás de un `--with-*`. # `libsystemd` trae su propio fallback (`[:]` en la línea 139), que es exactamente lo que permite # construir esto en una distro sin systemd — no hubo que parchear nada. # # `dotconf` era la ÚNICA que el corpus no tenía, y se midió sobre el `configure.ac` y no sobre los # paquetes de otra distro: ver `recipes/dotconf.toml`, que se compila a mano porque upstream no # publica releases y el lab no tiene autoconf. # # ══ LAS PERILLAS, Y QUÉ GANA O PIERDE CADA UNA ═════════════════════════════════════════════════ # --disable-ltdl **evita libltdl entero.** Su default es `check`: si encuentra # `lt_dlopen` lo usa, y si no cae a `dlopen`. Apagándolo # explícitamente usa el `dlopen` de libc, que musl trae, y el # `AC_DEFINE(USE_DLOPEN)` queda fijo en vez de depender de qué había # en el sysroot — un build que decide su propio mecanismo según el # entorno no es reproducible por construcción. # --with-espeak-ng el sintetizador que tenemos # --without-espeak el espeak VIEJO, distinto paquete; no está y no hace falta # --with-pulse --with-pipewire --with-alsa # las tres salidas de audio que el corpus tiene. **El servidor de # audio de esta distro es PipeWire**, que además habla el protocolo de # PulseAudio; ALSA queda como camino directo sin servidor (un # instalador, una consola de rescate) # --with-default-audio-method=pipewire # sin esto el default es «el primero que se descubra», o sea que el # orden de detección decide por nosotros # --enable-python el módulo `speechd`, que es **cómo orca habla con el daemon**. # Comprobado que no necesita setuptools ni pip: lo instala automake # plano (`python_PYTHON`), así que sólo pide el intérprete # --disable-doc la documentación en texinfo # # ⚠ **APAGADOS Y SE DICE POR QUÉ**: `--without-libao --without-oss --without-nas` (no están en el # corpus; `oss` y `nas` además son caminos históricos) y `--without-flite --without-ibmtts # --without-voxin --without-ivona --without-pico --without-baratinoo --without-kali`, que son otros # sintetizadores: `flite` no está en el corpus y **los otros seis son propietarios o de pago**. Con # espeak-ng detrás, el servidor habla 100+ idiomas sin ninguno de ellos. # # `gettext-tiny` basta acá: se comprobó que `po/` **no trae `ar.po`**, que es el fichero con el que # su `msgfmt` muere por los plurales del árabe (documentado en este repo). name = "speech-dispatcher" version = "0.12.1" license = "GPL-2.0-or-later" [source] # ⚠ El asset del RELEASE, no el archive del tag: trae `configure` y `Makefile.in` ya generados, y # el lab no tiene autoconf ni automake. Es la misma lección que `pcaudiolib` — cuando un proyecto # autotools no construye por falta de autoconf, mirar si publica un tarball de release ANTES de # escribir el autoconf. tarball = "https://github.com/brailcom/speechd/releases/download/0.12.1/speech-dispatcher-0.12.1.tar.gz" sha256 = "b14a5238d287d2dcce4dd42bbd66ca65fa228e7e683708267f7b34036f7ba4b4" [build] compiler = "zig-cc" target = "x86_64-linux-musl" link = "dynamic" flags = [] [build.phases] configure = ''' set -e [ -f ./configure ] || { echo "speech-dispatcher: el tarball no trae ./configure — ¿se cambió por el archive del tag?" >&2; exit 1; } # ⚠ `--sysconfdir=/etc` NO es opcional: con `--prefix=/usr` a secas, autotools lo deriva como # `/usr/etc` **en silencio**, y ahí fue a parar `speechd.conf` en la primera pasada. El daemon # hornea esa ruta, así que el artefacto es auto-consistente y nadie se entera — salvo que la # configuración de este paquete queda fuera de donde está la del resto de la distro, y nadie la # encuentra para editarla. **31 recetas de este repo ya lo pasan**: la omisión era la anomalía, no # una decisión. ./configure --build=$CBUILD --host=$CHOST --prefix=/usr --sysconfdir=/etc \ --disable-ltdl --disable-doc --enable-python \ --with-espeak-ng --without-espeak \ --without-flite --without-ibmtts --without-voxin --without-ivona \ --without-pico --without-baratinoo --without-kali \ --with-pulse --with-pipewire --with-alsa \ --without-libao --without-oss --without-nas \ --with-default-audio-method=pipewire ''' compile = 'make -j"$(nproc)"' # Guardián escrito contra lo que este paquete PROMETE, que es «las apps pueden hablar», y cada # control cubre una forma distinta de sellar algo que no cumple: # · sin el daemon no hay servidor: la API conecta a nada # · sin módulo de salida el daemon arranca, acepta texto y no suena # · sin módulo espeak-ng hay servidor y hay audio, y ninguna voz que sintetice # · sin el módulo python el daemon anda y **orca no puede usarlo**, que es el consumidor por el # que esta receta existe install = ''' set -e make install DESTDIR=/out [ -x /out/usr/bin/speech-dispatcher ] || { echo "speech-dispatcher: no quedó el daemon — NO sello" >&2; exit 1; } [ -x /out/usr/bin/spd-say ] || { echo "speech-dispatcher: falta spd-say — es la forma de comprobar a mano que la máquina habla" >&2; exit 1; } # Los módulos de SÍNTESIS viven en libexec/speech-dispatcher-modules. md=$(find /out/usr -type d -name 'speech-dispatcher-modules' 2>/dev/null | head -1) [ -n "$md" ] || { echo "speech-dispatcher: no hay directorio de módulos — el daemon no tendría con qué sintetizar" >&2; find /out/usr -maxdepth 3 -type d >&2; exit 1; } [ -x "$md/sd_espeak-ng" ] || { echo "speech-dispatcher: falta el módulo sd_espeak-ng — habría servidor y audio, y ninguna voz" >&2; ls "$md" >&2; exit 1; } # La API en C, que es lo que enlaza cualquier app no-Python. so=$(find /out/usr/lib -name 'libspeechd.so*' -type f 2>/dev/null | head -1) [ -n "$so" ] || { echo "speech-dispatcher: no quedó libspeechd.so — las apps en C no podrían hablar" >&2; exit 1; } # Y el módulo de Python, por el que orca existe. py=$(find /out/usr/lib -type d -name speechd 2>/dev/null | head -1) [ -n "$py" ] || { echo "speech-dispatcher: no se instaló el módulo python 'speechd' — orca no podría hablar con el daemon" >&2; find /out/usr/lib -maxdepth 4 -type d -name 'python*' >&2; exit 1; } # ⚠ El audio por defecto, comprobado donde VIVE el contrato y no donde yo creía. # # Mi primera versión miraba `speechd.conf` buscando `pipewire`, y eso estaba mal por dos razones a # la vez: la config caía en `/usr/etc` (ver la nota del `--sysconfdir` arriba), y **el `.conf` no es # el contrato** — upstream deja la línea COMENTADA a propósito, como documentación del default, y # el valor real lo hornea el `configure`. Medido en el binario: de los cinco métodos posibles # (`pipewire pulse alsa oss nas`) el daemon sólo contiene la cadena `pipewire`. # # ⇒ Se comprueba el BINARIO, que es quien decide, y además que la config esté en /etc, que es lo # que permite editarla. Un aviso blando que nadie lee no es un control; esto falla. [ -f /out/etc/speech-dispatcher/speechd.conf ] || { echo "speech-dispatcher: speechd.conf no está en /etc — autotools lo derivó a otro sitio y nadie la encontraría" >&2; find /out -name 'speechd.conf' >&2; exit 1; } strings /out/usr/bin/speech-dispatcher 2>/dev/null | grep -qx 'pipewire' || { echo "speech-dispatcher: el daemon no trae 'pipewire' como método de audio — el default sería «el primero que se descubra»" >&2; strings /out/usr/bin/speech-dispatcher 2>/dev/null | grep -xE 'pulse|alsa|oss|nas' >&2; exit 1; } n=$(ls "$md" 2>/dev/null | wc -l) echo "speech-dispatcher: daemon + spd-say + $n módulo(s) + libspeechd.so + módulo python" ''' [deps] build = ["make", "pkgconf", "dotconf", "glib", "libsndfile", "espeak-ng", "pulseaudio", "pipewire", "alsa-lib", "python3", "pcre2", "libffi", "zlib", "gettext-tiny", "libtool", # ⚠ `binutils` está por el GUARDIÁN y no por el build: aporta `strings`, que es con lo que # se comprueba el método de audio horneado en el daemon. Sin declararlo el control fallaría # por falta de herramienta en vez de por el defecto que busca — y acusaría a la receta de # algo que no hizo. Es la misma nota que lleva `espeak-ng`. "binutils"]