112 lines
5.9 KiB
Markdown
112 lines
5.9 KiB
Markdown
# Audio startup and recovery
|
|
|
|
Fenrir handles speech and sound connections independently. The recovery code
|
|
uses Linux processes, sockets and deadlines; it does not require systemd or a
|
|
particular service manager. Explicit server, speech driver and sound driver
|
|
choices remain authoritative. Failures never select a different audio driver.
|
|
|
|
## Speech
|
|
|
|
Before opening console keyboards or an X11 terminal session, Fenrir retries
|
|
temporary speech connection failures for up to 20 seconds. Permission and
|
|
configuration errors fail without waiting through that retry window. Speech
|
|
Dispatcher's own configuration decides whether to allow daemon autostart.
|
|
|
|
When a running Speech Dispatcher connection fails, the speech worker attempts
|
|
to reconnect for up to 20 seconds. Keyboard forwarding, interruption, mute and
|
|
quit commands remain responsive. Pending speech is discarded during recovery;
|
|
it is not replayed when the connection returns. Numeric speech settings and
|
|
mute state survive recovery. Later output uses the restored connection.
|
|
|
|
If recovery fails, Fenrir reports the error and exits. Keyboard grabs are
|
|
released before waiting for UI tasks, speech or sound shutdown. Native hardware
|
|
speech drivers retain their existing failure handling; they do not start a
|
|
Speech Dispatcher daemon or select a different synthesizer.
|
|
|
|
## Root at boot and sudo sessions
|
|
|
|
A boot service running as root without `SUDO_UID` uses root's Speech Dispatcher
|
|
environment and configuration. It does not choose a logged-in user's daemon.
|
|
Root's speech and sound connections receive the same retry/recovery handling.
|
|
The audio server must be configured to start independently of graphical login
|
|
and permit the required socket and output-device access.
|
|
|
|
For `sudo fenrir`, `SUDO_UID` identifies the invoking user. If the selected local
|
|
Speech Dispatcher is missing, Fenrir looks up that account and starts only the
|
|
daemon child with that account's UID, primary group and supplementary groups.
|
|
The child receives the user's home and an owned runtime directory when present;
|
|
it does not inherit root's session bus or unrelated environment variables.
|
|
An owned `XDG_RUNTIME_DIR` is preferred for the default speech socket, followed
|
|
by the user's owned `/run/user/UID` directory, or the user's cache directory
|
|
when no runtime directory exists. Explicit speech socket/address settings
|
|
still take precedence. Fenrir retains its own console/device privileges.
|
|
|
|
Logging out may stop user-owned Speech Dispatcher or audio services. Recovery
|
|
can reconnect when the same services return; it does not keep a login session
|
|
alive or migrate to another user's audio. No session-owned daemon is killed
|
|
or restarted to force recovery.
|
|
|
|
## Sound effects
|
|
|
|
Sound effects retry failed initialization and disconnected playback in a
|
|
background worker for up to 20 seconds per outage. While unavailable, sound
|
|
cues are rejected so Fenrir can use their speech equivalents. Cues and progress
|
|
tones from an outage are discarded. The latest sound volume is applied to a
|
|
restored connection.
|
|
|
|
Each sound-driver open attempt has a three-second deadline. Some native/library
|
|
calls cannot be interrupted: if an attempt remains stuck, Fenrir stops opening
|
|
new connections for that player. At most one abandoned opener remains, and it
|
|
closes its result if it eventually returns. Working speech and keyboard input
|
|
continue. Exhausted sound recovery disables sound effects for that run.
|
|
|
|
## Limits
|
|
|
|
Retries cannot repair missing services, incorrect permissions, a wrong server,
|
|
or a missing playback device. A successful Speech Dispatcher protocol exchange
|
|
also does not prove audible output: an output module can accept a request and
|
|
fail inside its own audio backend. PipeWire, PulseAudio and Speech Dispatcher
|
|
still need appropriate configuration. In particular, PulseAudio's libpulse
|
|
autospawn behavior does not imply that a PipeWire service will start itself.
|
|
|
|
## Verification
|
|
|
|
Automated checks use private sockets and fake audio backends, without taking
|
|
over the active reader:
|
|
|
|
```sh
|
|
go test -race ./internal/audio ./internal/speech ./internal/sound ./internal/app
|
|
go test ./...
|
|
```
|
|
|
|
For optional isolated Speech Dispatcher startup checks using its dummy module:
|
|
|
|
```sh
|
|
FENRIR_NATIVE_SPEECH_STARTUP=1 go test ./internal/speech -run TestNativeSpeechDispatcherColdStart -count=1
|
|
```
|
|
|
|
Before submission, review the diff and test on an affected machine with a
|
|
recovery path, such as SSH or another accessible console. Keep only one reader
|
|
on a console. Source tests do not prove installed behavior or audible output.
|
|
|
|
1. Boot without a GUI and before user login, with Fenrir started by the normal
|
|
boot service. Verify speech, startup sounds, typing, review and quit. Repeat
|
|
with the audio server delayed briefly: speech should recover if the required
|
|
service becomes available inside the retry window.
|
|
2. Check ordinary `sudo fenrir` startup with the user's Speech Dispatcher both
|
|
already running and initially absent. Check daemon ownership and confirm
|
|
speech and sound. No root-owned daemon should be created in the user's
|
|
runtime directory. Test a console session without systemd as well.
|
|
3. With a recovery connection available, interrupt the configured speech/audio
|
|
service using that system's normal service controls. While it is unavailable,
|
|
check ordinary typing, Control, mute and Fenrir's quit shortcut. Restore the
|
|
service and check fresh review output, volume/rate/pitch and absence of old
|
|
queued announcements. A permanent speech failure must release the keyboard;
|
|
a sound-only failure must leave speech working.
|
|
4. Repeat ordinary X11 terminal startup, review, interruption and exit, plus
|
|
explicit ALSA sound output where available. Check settings changes during
|
|
recovery and verify that saved settings are not silently rewritten.
|
|
5. For user-owned audio, log out and back in with the recovery connection still
|
|
available. Verify behavior against that machine's session-lifetime policy;
|
|
this is separate from root-owned pre-login audio.
|