Prompt audio
The prompts under sounds/prompts/en/ are the fragments voicemail and the menus
assemble — "you have" + "three" + "new messages". They are generated by an
operator, committed, and played from disk.
Synthesis never happens during a call. Everything the dialplan plays is validated and preloaded when the PBX starts, so a bad file stops the process instead of a conversation; putting a third-party API in that path would trade that for dead air on an outage. It also means the API key never has to exist in production.
Generating a set
LYNO_ELEVENLABS_API_KEY=… ./bin/lyno -tts -manifest configs/prompts-en.yaml
-tts is a mode flag on the main binary, not a subcommand. It takes precedence
over everything else, including -configure, and exits when it is done.
| Flag | Purpose |
|---|---|
-tts | Enter prompt-generation mode and exit. |
-manifest | A YAML prompt set to generate in bulk. |
-text | One sentence to synthesise. Requires -out. |
-out | Destination WAV for -text. |
-voice | Voice id, overriding the configuration and the manifest. |
-model | Model id, same. |
-force | Regenerate even when nothing changed. |
-voices | List the voices the key can use, and exit. |
./bin/lyno -tts -voices # what the key can use
./bin/lyno -tts -text "We are closed" -out sounds/closed.wav
-tts with none of -text+-out, -manifest or -voices is an error. Within
-tts, -voices wins over -manifest, which wins over -text. The whole run
is bounded at 30 minutes.
The manifest
voice: mwkFMsRX1kc5niMwNsbT
model: eleven_multilingual_v2
out_dir: ../sounds/prompts/en
prompts:
- {name: digit-3, text: "three"}
- {name: vm-youhave, text: "You have"}
- {name: vm-options, text: "To replay this message, press 1. To save it, press 2. …"}
| Key | Required | Meaning |
|---|---|---|
out_dir | yes | Where the WAVs land. A relative path resolves against the manifest. |
voice, model | no | Defaults for the whole set. |
settings | no | Voice settings for the whole set. |
prompts[].name | yes | The filename, without .wav. |
prompts[].text | yes | What it says. |
prompts[].voice, .settings | no | Override the set wholesale, not field by field. |
The manifest is decoded strictly, so a misspelt key is an error rather than a setting that quietly does nothing.
The shipped set holds 75 prompts: digit-0…digit-20 and the tens, eight
feature-* confirmations, goodbye, invalid, transfer, and the vm-* set
the retrieval menu needs.
beep.wav is deliberately not in the manifest — it is a 1 kHz tone, not speech.
Reruns are cheap
Each prompt writes <name>.wav plus a <name>.wav.tts.json sidecar recording
the text, voice, model, format and settings it was generated from. Only
fragments whose inputs changed are synthesised again; the rest are recognised and
skipped, so a rerun costs nothing.
-force regenerates regardless.
The API key
Read in this order:
LYNO_ELEVENLABS_API_KEYin the environment;tts.apiKeyFilein the configuration — the contents of the file;tts.apiKeyin the configuration.
The third is the worst of the three, because configs/ is usually under version
control.
configVersion: lyno/v1
kind: System
spec:
tts:
provider: elevenlabs
apiKeyFile: /etc/lyno/elevenlabs.key
voice: mwkFMsRX1kc5niMwNsbT
model: eleven_multilingual_v2
ElevenLabs is the only provider. provider is validated against that one
name; nothing dispatches on it.
What comes out
8 kHz mono 16-bit PCM WAV — exactly what the PBX plays.
The format is checked three times: the response is validated before it is
accepted, the file is tidied, and what actually landed on disk is validated
again. That catches a provider quietly switching sample rate, and an HTML error
page returned behind a 200.
After synthesis each fragment is trimmed and levelled to a common loudness. That is what keeps "you have" + "three" + "new messages" sounding like one reader across three files rather than three. Changing the target level invalidates the whole set.
Fragments are concatenated into a single playback at call time, so there is no audible gap between them.
Which prompts are actually used
Voicemail loads its fragments by name from voicemail.promptsDir. A fragment
that is absent is skipped rather than treated as an error, so a partial set
still announces something; one that is present and unplayable fails at
startup.
Ten prompts in the shipped manifest are generated and never loaded:
vm-menu, vm-login, vm-mailboxfull, vm-toolong, vm-greetingsaved,
vm-recordgreeting, vm-message, vm-messages, vm-new and vm-old. They
describe an Asterisk-style menu Lyno does not implement — the real menu prompt is
vm-options. Removing them from your own manifest saves the synthesis cost.
Conversely the manifest has no weekday, month or ordinal fragments, which is why voicemail does not announce a date for anything older than yesterday.
Prompts for menus and greetings
Nothing forces you to use -tts. Any 8 kHz mono 16-bit PCM WAV works, from any
source:
ffmpeg -i input.mp3 -ar 8000 -ac 1 -acodec pcm_s16le output.wav
-tts -text … -out … is a convenience for producing one of those in the same
voice as the rest of the set.