20.2 Speech Server Protocols

Emacsvox produces spoken output by communicating with one of several speech servers. Two protocol families coexist:

This chapter is primarily for speech-server and client developers. The detailed Omnivox contracts are owned by the Omnivox repository; this manual summarizes their relationship to Emacsvox and then documents the legacy line protocol.

For additional notes on how to log and view TTS server commands when developing a speech server, see the historical Emacspeak article at http://emacspeak.blogspot.com/2015/04/howto-log-speech-server-output-to-aid.html.

20.2.1 Omnivox Structured Protocol

At process startup the Emacsvox adapter requests capabilities and live engine inventory. Features are used only after negotiation; an older server continues on the legacy path. Current Emacsvox requires presentation_timeline_v3 before it submits an Aural Presentation as a structured timeline.

Concrete Aural plans retain a bounded compatibility lowering when those features are absent. Speech, voice commands, silence, tones, dispatch, and interruption use the established legacy queue commands. A legacy tone cannot preserve the explicit overlay clock: both insert and overlay modes become an ordered t command, and a fractional frequency is rounded to the nearest hertz. The surrounding speech continues rather than being rejected for that loss of presentation precision.

Guarantee-bearing operations do not invent success on a legacy server. Playback completion, source markers, and domain-scoped replacement remain unavailable when the selected server cannot acknowledge them truthfully.

Ordinary control requests belong to their speech process. They have a 30-second response deadline and an admission limit of 64 outstanding requests per process. Background inventory refreshes share one pending request per process. Capability negotiation uses omnivox-control-negotiation-timeout. Previews, parameter queries, palette application, and synchronous library operations retain their own deadlines and cancellation rules.

The client detaches a request and cancels its timer before invoking its callback. A response deadline or process exit produces a local error response with the original request ID, :origin client, and code timeout or process_closed. This does not prove that a submitted server operation was cancelled or had no effect. Late replies cannot change the completed outcome. Ordinary navigation Stop leaves metadata requests pending; each speech lane owns its requests independently.

When adding an ordinary control caller, use omnivox--send-control-request. Its callback may run during the send. Use the internal managed timeout only when the enclosing operation already enforces a deadline and calls omnivox--take-control-request on every cancellation or nonlocal exit. Private preview operations keep their existing playback ownership and reserved callbacks. No control wire version changes for this client lifecycle handling.

A complete timeline contains its delivery policy, replacement domain, generation, dispatch ID, speech spans, and positioned actions. Small timelines use one bounded frame; large timelines use a bounded multipart envelope that is validated and admitted atomically. Decodable rejected or stale direct timelines receive terminal status so Emacs callbacks can retire their dispatch records.

ordered and urgent timelines are admitted immediately. Only matching replaceable work uses the short server-side coalescing window. Receipt of a newer valid replaceable generation immediately cancels queued, synthesizing, and buffered work in the same replacement domain. It does not globally stop ordered, urgent, legacy, or differently keyed output.

Marker events report playback start and positioned playback boundaries; tracked status reports terminal completion. With opt-in Aural diagnostics, Emacs records successful dispatch send, first received utterance_started, and terminal observation under the same dispatch ID. Omnivox’s normal session log records protocol admission, worker queue wait, individual engine attempts, audio queueing, first mixer-source consumption, and terminal playback under that ID. This correlation uses existing marker and terminal records rather than adding a wire-protocol version. Playback markers track mixer-source consumption and may precede physical sound by the output device’s buffer latency; a protocol write or terminal callback is therefore not proof of acoustic onset.

Recent Feedback retains a separate, data-only playback snapshot. Owned, validated start and voice-choice events associate actual physical voices with the frozen registry layers and retained run ranges. A presentation shares a 64 KiB evidence budget, with at most 128 dispatches and 128 spans per dispatch; speech text remains subject to the existing 4096-byte history limit. Exhausted or incomplete evidence disables original replay without blocking delivery. Completed snapshots drive exact private voice previews with fallback disabled. They never rewrite the named-voice registry or borrow another lane’s latest logical-voice realization. Ordinary history navigation retains the requested annotations; explicit original playback uses this observed snapshot.

The canonical protocol documents are:

20.2.2 Legacy Line Protocol

The TTS server reads commands from standard input. Script speech-server can be used to cause a TTS server to communicate via a TCP socket. Speech server commands are used by the client application to make specific requests of the server; the server listens for these requests in a non-blocking read-eval-print (REPL) loop and executes requests as they become available. Requests can be classified as follows:

All commands are of the form

commandWord {arguments}

The braces are optional when the command argument contains no whitespace. The speech server’s current state determines speech rate, punctuation mode and other output characteristics. The state-setting commands below describe those controls. The client queues text and non-speech audio, then asks the server to dispatch the queued requests and begin producing output.

Once the server has been asked to produce output, it removes items from the front of the queue, sends the requisite commands to the underlying TTS engine, and waits for the engine to acknowledge that the request has been completely processed. This is a non-blocking operation, i.e., if the client application generates additional requests, these are processed immediately.

This design allows a legacy Emacsvox TTS server to be highly responsive; Client applications can queue large amounts of text (typically queued a clause at a time to achieve the best prosody), ask the TTS server to start speaking, and interrupt the spoken output at any time.

  1. Testing A Direct Legacy Server

    This protocol-level test is only for a retained direct Tcl-compatible server. Run its launcher from the Emacsvox repository root, for example:

    ./servers/espeak
    

    Then enter:

    q {This is a test.}
    d
    s
    

    The q command queues text, d dispatches it, and s stops speech. Type C-d to close the server. A backend-specific README may provide a stronger diagnostic and should take precedence over this generic protocol test.

  2. Commands That Queue Output.

    This section documents commands that either produce spoken output, or queue output to be produced on demand. Commands that place the request on the queue are clearly marked.

    version
    

    Speaks the version of the TTS engine. Produces output immediately.

    tts_say text
    

    Speaks the specified text immediately. The text is not pre-processed in any way, contrast this with the primary way of speaking text which is to queue text before asking the server to process the queue.

    Note that this command needs to handle the special syntax for morpheme boundaries [*]. The [*] syntax is specific to the Dectalk family of synthesizers; servers for other TTS engines need to map this pattern to the engine-specific code for each engine. As an example, see servers/outloud A morpheme boundary results in synthesizing compound words such as left bracket with the right intonation; using a space would result in that phrase being synthesized as two separate words.

    l c
    

    Speak c a single character, as a letter. The character is spoken immediately. This command uses the TTS engine’s capability to speak a single character with the ability to flush speech immediately. Client applications wishing to produce character-at-a-time output, e.g., when providing character echo during keyboard input should use this command.

    Omnivox clients that negotiate palette_letter_v1 and its complete layered voice bundle use emacsvox_letter {BASE64_UTF8_JSON} instead. Its version 4 or 5 timeline envelope has one layered span containing one visible Unicode scalar, ordered delivery, no replacement key, and no actions. Registration and validation precede interruption. The command retains isolated-character rate, uppercase pitch, pronunciation and short streaming startup while applying the palette’s default voice, actual fallback tuning and native parameters. Playback receipts use the existing layered timeline contracts. Legacy servers continue to receive l; ordinary phonetic words and punctuation names use the normal palette speech path.

    d
    

    This command is used to dispatch all queued requests. It was renamed to a single character command (like many of the commonly used TTS server commands) to work more effectively over slow (9600) dialup lines. The effect of calling this command is for the TTS server to start processing items that have been queued via earlier requests.

    s
    

    Stop speech immediately. Spoken output is interrupted, and all pending requests are flushed from the queue.

    q text
    

    Queues text to be spoken. No spoken output is produced until a dispatch request is received via execution of command d.

    c codes
    

    Queues synthesis codes to be sent to the TTS engine. Codes are sent to the engine with no further transformation or processing. The codes are inserted into the output queue and will be dispatched to the TTS engine at the appropriate point in the output stream.

    a filename
    

    Cues the audio file identified by filename for playing, an ogg file.

    p filename
    

    dispatch play the audio file identified by filename for playing — ogg file.

    t freq length
    

    Queues a tone to be played at the specified frequency and having the specified length. Frequency is specified in hertz and length is specified in milliseconds.

    sh duration
    

    Queues the specified duration of silence. Silence is specified in milliseconds.

  3. Commands That Set State
    tts_reset
    

    Immediately reset TTS engine to default settings. Stops all speech and clears the queue.

    tts_set_punctuations mode
    

    Queues setting TTS engine to the specified punctuation mode. Typically, TTS servers provide at least three modes:

    • None: Do not speak punctuation characters.
    • Some: Speak some punctuation characters. Used for English prose.
    • All: Speak out all punctuation characters; useful in programming modes.
    tts_set_speech_rate rate
    

    Immediately change speech rate. The interpretation of this value is typically engine specific.

    tts_set_character_scale factor
    

    Queues a change to the scale factor used for individual-character speech. For a speech rate of 500 and a character scale of 1.2, command l uses a rate of 600: the base rate multiplied by the character scale.

    tts_split_caps flag
    

    Queues changing of the state of split caps processing. Turn this on to speak mixed-case (AKA Camel Case) identifiers.

    tts_sync_state punct splitcaps caps rate
    

    Immediately apply the passed settings.

    This ensures atomicity i.e., all state settings in the TTS engine happen at one shot. Note that failure to do this might result in some utterances being spoken with a partially set state.

    • punct: see tts_set_punctuations
    • splitcaps: see tts_split_caps
    • caps: engine specific implementation of capital letter handling
    • rate: see tts_set_speech_rate
    set_next_lang say_it
    

    Immediately switch to the next language on the server, maintained internally on the TTS server. If say_it is non-nil say the language change via the TTS.

    set_previous_lang say_it
    

    Immediately switch to the previous language on the server, maintained internally on the TTS server. If say_it is non-nil say the language change via the TTS.

    set_lang language:voice say_it
    

    Immediately switch to the requested language and/or voice, separated by a colon. Examples

    • set_lang "en"
    • set_lang "en:whisper"
    • set_lang ":whisper"

    If say_it is non-nil, speak via the TTS the language and voice selected.

    set_preferred_lang alias lang
    

    Immediately set an alias in the TTS server mapping for example "en" to "en_GB". This can later be used by set_lang.