tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

⎇ main recipes/speech-dispatcher.toml TOML · 139 líneas · 9.9 KB Historia crudo

accesibilidad: el SERVIDOR de voz, no sólo el sintetizador a709d76c2 · Sergio ·

1# speech-dispatcher 0.12.1 — el SERVIDOR de voz. Es lo que convierte «la distro habla» en
2# «las aplicaciones de la distro pueden hablar».
3#
4# ══ QUÉ AÑADE SOBRE espeak-ng, QUE YA ESTÁ ═════════════════════════════════════════════════════
5# `espeak-ng` es un sintetizador: un proceso que recibe texto y hace ruido. Si cada aplicación lo
6# invoca por su cuenta, dos que hablen a la vez se pisan, nadie puede interrumpir a nadie, y cambiar
7# de voz o de velocidad es cosa de cada app. `speech-dispatcher` es la capa que falta: un daemon con
8# COLA y PRIORIDADES, una API estable (`libspeechd` en C y el módulo `speechd` en Python), y los
9# sintetizadores detrás como módulos intercambiables.
10#
11# ⇒ Es la dep que `orca` —el lector de pantalla— usa para hablar, y también lo que hace que
12# `spd-say "hola"` funcione desde cualquier script. Sin esto, el hueco de accesibilidad del censo
13# sigue abierto aunque la máquina ya tenga voz.
14#
15# ══ LO QUE PIDE, MEDIDO EN SU `configure.ac` ═══════════════════════════════════════════════════
16# De sus once `PKG_CHECK_MODULES`, **obligatorios**: `glib-2.0`, `gthread-2.0`, `gmodule-2.0`
17# (los tres los da `glib`), `sndfile` y **`dotconf >= 1.3`**. El resto va detrás de un `--with-*`.
18# `libsystemd` trae su propio fallback (`[:]` en la línea 139), que es exactamente lo que permite
19# construir esto en una distro sin systemd — no hubo que parchear nada.
20#
21# `dotconf` era la ÚNICA que el corpus no tenía, y se midió sobre el `configure.ac` y no sobre los
22# paquetes de otra distro: ver `recipes/dotconf.toml`, que se compila a mano porque upstream no
23# publica releases y el lab no tiene autoconf.
24#
25# ══ LAS PERILLAS, Y QUÉ GANA O PIERDE CADA UNA ═════════════════════════════════════════════════
26#   --disable-ltdl              **evita libltdl entero.** Su default es `check`: si encuentra
27#                               `lt_dlopen` lo usa, y si no cae a `dlopen`. Apagándolo
28#                               explícitamente usa el `dlopen` de libc, que musl trae, y el
29#                               `AC_DEFINE(USE_DLOPEN)` queda fijo en vez de depender de qué había
30#                               en el sysroot — un build que decide su propio mecanismo según el
31#                               entorno no es reproducible por construcción.
32#   --with-espeak-ng            el sintetizador que tenemos
33#   --without-espeak            el espeak VIEJO, distinto paquete; no está y no hace falta
34#   --with-pulse --with-pipewire --with-alsa
35#                               las tres salidas de audio que el corpus tiene. **El servidor de
36#                               audio de esta distro es PipeWire**, que además habla el protocolo de
37#                               PulseAudio; ALSA queda como camino directo sin servidor (un
38#                               instalador, una consola de rescate)
39#   --with-default-audio-method=pipewire
40#                               sin esto el default es «el primero que se descubra», o sea que el
41#                               orden de detección decide por nosotros
42#   --enable-python             el módulo `speechd`, que es **cómo orca habla con el daemon**.
43#                               Comprobado que no necesita setuptools ni pip: lo instala automake
44#                               plano (`python_PYTHON`), así que sólo pide el intérprete
45#   --disable-doc               la documentación en texinfo
46#
47# ⚠ **APAGADOS Y SE DICE POR QUÉ**: `--without-libao --without-oss --without-nas` (no están en el
48# corpus; `oss` y `nas` además son caminos históricos) y `--without-flite --without-ibmtts
49# --without-voxin --without-ivona --without-pico --without-baratinoo --without-kali`, que son otros
50# sintetizadores: `flite` no está en el corpus y **los otros seis son propietarios o de pago**. Con
51# espeak-ng detrás, el servidor habla 100+ idiomas sin ninguno de ellos.
52#
53# `gettext-tiny` basta acá: se comprobó que `po/` **no trae `ar.po`**, que es el fichero con el que
54# su `msgfmt` muere por los plurales del árabe (documentado en este repo).
55name    = "speech-dispatcher"
56version = "0.12.1"
57license = "GPL-2.0-or-later"
58
59[source]
60# ⚠ El asset del RELEASE, no el archive del tag: trae `configure` y `Makefile.in` ya generados, y
61# el lab no tiene autoconf ni automake. Es la misma lección que `pcaudiolib` — cuando un proyecto
62# autotools no construye por falta de autoconf, mirar si publica un tarball de release ANTES de
63# escribir el autoconf.
64tarball = "https://github.com/brailcom/speechd/releases/download/0.12.1/speech-dispatcher-0.12.1.tar.gz"
65sha256  = "b14a5238d287d2dcce4dd42bbd66ca65fa228e7e683708267f7b34036f7ba4b4"
66
67[build]
68compiler = "zig-cc"
69target   = "x86_64-linux-musl"
70link     = "dynamic"
71flags    = []
72
73[build.phases]
74configure = '''
75set -e
76[ -f ./configure ] || { echo "speech-dispatcher: el tarball no trae ./configure — ¿se cambió por el archive del tag?" >&2; exit 1; }
77# ⚠ `--sysconfdir=/etc` NO es opcional: con `--prefix=/usr` a secas, autotools lo deriva como
78# `/usr/etc` **en silencio**, y ahí fue a parar `speechd.conf` en la primera pasada. El daemon
79# hornea esa ruta, así que el artefacto es auto-consistente y nadie se entera — salvo que la
80# configuración de este paquete queda fuera de donde está la del resto de la distro, y nadie la
81# encuentra para editarla. **31 recetas de este repo ya lo pasan**: la omisión era la anomalía, no
82# una decisión.
83./configure --build=$CBUILD --host=$CHOST --prefix=/usr --sysconfdir=/etc \
84  --disable-ltdl --disable-doc --enable-python \
85  --with-espeak-ng --without-espeak \
86  --without-flite --without-ibmtts --without-voxin --without-ivona \
87  --without-pico --without-baratinoo --without-kali \
88  --with-pulse --with-pipewire --with-alsa \
89  --without-libao --without-oss --without-nas \
90  --with-default-audio-method=pipewire
91'''
92compile = 'make -j"$(nproc)"'
93# Guardián escrito contra lo que este paquete PROMETE, que es «las apps pueden hablar», y cada
94# control cubre una forma distinta de sellar algo que no cumple:
95#   · sin el daemon          no hay servidor: la API conecta a nada
96#   · sin módulo de salida   el daemon arranca, acepta texto y no suena
97#   · sin módulo espeak-ng   hay servidor y hay audio, y ninguna voz que sintetice
98#   · sin el módulo python   el daemon anda y **orca no puede usarlo**, que es el consumidor por el
99#                            que esta receta existe
100install = '''
101set -e
102make install DESTDIR=/out
103[ -x /out/usr/bin/speech-dispatcher ] || { echo "speech-dispatcher: no quedó el daemon — NO sello" >&2; exit 1; }
104[ -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; }
105# Los módulos de SÍNTESIS viven en libexec/speech-dispatcher-modules.
106md=$(find /out/usr -type d -name 'speech-dispatcher-modules' 2>/dev/null | head -1)
107[ -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; }
108[ -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; }
109# La API en C, que es lo que enlaza cualquier app no-Python.
110so=$(find /out/usr/lib -name 'libspeechd.so*' -type f 2>/dev/null | head -1)
111[ -n "$so" ] || { echo "speech-dispatcher: no quedó libspeechd.so — las apps en C no podrían hablar" >&2; exit 1; }
112# Y el módulo de Python, por el que orca existe.
113py=$(find /out/usr/lib -type d -name speechd 2>/dev/null | head -1)
114[ -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; }
115# ⚠ El audio por defecto, comprobado donde VIVE el contrato y no donde yo creía.
116#
117# Mi primera versión miraba `speechd.conf` buscando `pipewire`, y eso estaba mal por dos razones a
118# la vez: la config caía en `/usr/etc` (ver la nota del `--sysconfdir` arriba), y **el `.conf` no es
119# el contrato** — upstream deja la línea COMENTADA a propósito, como documentación del default, y
120# el valor real lo hornea el `configure`. Medido en el binario: de los cinco métodos posibles
121# (`pipewire pulse alsa oss nas`) el daemon sólo contiene la cadena `pipewire`.
122#
123# ⇒ Se comprueba el BINARIO, que es quien decide, y además que la config esté en /etc, que es lo
124# que permite editarla. Un aviso blando que nadie lee no es un control; esto falla.
125[ -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; }
126strings /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; }
127n=$(ls "$md" 2>/dev/null | wc -l)
128echo "speech-dispatcher: daemon + spd-say + $n módulo(s) + libspeechd.so + módulo python"
129'''
130
131[deps]
132build = ["make", "pkgconf", "dotconf", "glib", "libsndfile", "espeak-ng",
133         "pulseaudio", "pipewire", "alsa-lib", "python3",
134         "pcre2", "libffi", "zlib", "gettext-tiny", "libtool",
135         # ⚠ `binutils` está por el GUARDIÁN y no por el build: aporta `strings`, que es con lo que
136         # se comprueba el método de audio horneado en el daemon. Sin declararlo el control fallaría
137         # por falta de herramienta en vez de por el defecto que busca — y acusaría a la receta de
138         # algo que no hizo. Es la misma nota que lleva `espeak-ng`.
139         "binutils"]