The playback API is a high-level API that provides a simple interface for playing, pausing, and stopping speech. ReadiumSpeechNavigator wraps a ReadiumSpeechPlaybackEngine that you provide — e.g. WebSpeechEngine or SpeechServerEngine, each documented separately for construction/options; this page covers the shared engine contract and navigator API.
Once initialized, you can use the navigator to load content (utterances) and control playback.
ReadiumSpeechNavigator implements ReadiumSpeechNavigatorContract, which extends Configurable<SpeechSettings, SpeechPreferences> — see Preferences for verbosity/prosody settings (settings, preferencesEditor, submitPreferences(), omitted below):
interface ReadiumSpeechNavigatorContract {
// Voice Management
getVoices(): Promise<ReadiumSpeechVoice[]>;
setVoice(voice: ReadiumSpeechVoice | string): void;
getCurrentVoice(): ReadiumSpeechVoice | null;
setSpeakInContentLanguage(enabled: boolean): void;
getSpeakInContentLanguage(): boolean;
// Content Management
loadContent(content: ReadiumSpeechUtterance | ReadiumSpeechUtterance[]): void;
loadGndContent(nodes: GndObject[]): Promise<void>;
getCurrentContent(): ReadiumSpeechUtterance | null;
getContentQueue(): ReadiumSpeechUtterance[];
// Playback Control
play(): void;
pause(): void;
stop(): void;
// Navigation
next(): boolean;
previous(): boolean;
jumpTo(utteranceIndex: number): void;
// State
getState(): ReadiumSpeechPlaybackState;
// Events
on(
event: ReadiumSpeechPlaybackEvent["type"] | "contentchange",
listener: (event: ReadiumSpeechPlaybackEvent) => void
): () => void;
// Lifecycle
destroy(): Promise<void>;
}
import { WebSpeechEngine, ReadiumSpeechNavigator } from "@readium/speech";
const navigator = new ReadiumSpeechNavigator(new WebSpeechEngine());
navigator.loadContent([
{ plain: "Hello world.", language: "en" }
]);
function togglePlayback() {
const state = navigator.getState();
if (state === "playing") {
navigator.pause();
} else {
navigator.play();
}
}
togglePlayback();
Two ways to load content — simple and advanced:
loadContent() takes already-extracted ReadiumSpeechUtterances directly. No GND, no extraction options — you own the utterance list.loadGndContent(nodes) takes a raw Guided Navigation tree instead. The navigator retains it and re-runs extractUtterances itself when an extraction-affecting preference changes via submitPreferences(), so verbosity/skip/contextualize/language stay live over the whole tree — loadContent() keeps no such source, so those preferences are no-ops on it; prosody preferences still apply either way — see Preferences.contextualizationOverridesSet once at construction — not part of submitPreferences(), since it doesn’t change at runtime:
const navigator = new ReadiumSpeechNavigator(engine, {
contextualizationOverrides: { contextualizations, shapes, params },
});
Each field forwards to the matching extractUtterances option — see that doc for what each does and worked examples for every use case (rewording a role, adding a role the catalog has none for, feeding a placeholder the extractor doesn’t compute on its own):
contextualizations → contextualization.contextualizationsparams → contextualization.paramsshapes → contextualization.shapes, but keyed one level deeper, by verbosity level ({ table: { few: "inline", most: "block" } }) — each preset already has its own built-in shape table, so an override here only needs the levels you want to change, "custom" included (custom is the one level with no built-in table of its own).ReadiumSpeechPlaybackEventtype ReadiumSpeechPlaybackEvent = {
type:
| "start" // Playback started
| "pause" // Playback paused
| "resume" // Playback resumed
| "end" // Playback ended naturally
| "stop" // Playback stopped manually
| "skip" // Skipped to another utterance
| "error" // An error occurred
| "boundary" // Reached a word/sentence boundary
| "mark" // Reached a named mark in SSML
| "idle" // No content loaded
| "loading" // Loading content
| "ready" // Ready to play
| "voiceschanged" // Available voices changed
| "languagefallback"; // No voice matched an utterance's content language
detail?: any; // Event-specific data
};
By default, playback always uses the selected/default voice. Call setSpeakInContentLanguage(true) to instead match each utterance’s own language field to the best available voice for that language, falling back to the selected/default voice when no match exists (which also fires a "languagefallback" event with detail: { language, reason: "no-matching-voice" }).
ReadiumSpeechPlaybackStatetype ReadiumSpeechPlaybackState = "playing" | "paused" | "idle" | "loading" | "ready";
ReadiumSpeechUtteranceinterface ReadiumSpeechUtterance {
id?: string; // Unique identifier for this content
plain?: string; // Plain-text rendering, when available
ssml?: string; // SSML rendering, when available
language?: string; // Language of this content (BCP 47)
locate?: LocatorOptions; // Decoded from the source node's textref — spread into createLocator()/decorate()
synthetic?: boolean; // True when plain/ssml is a synthesized label/announcement, not text copied from the source
}
Represents a single piece of content to be spoken, as plain text and/or SSML.
synthetic is set on a contextualization catalog entry, or an alt/caption-derived description, rather than text found verbatim in the document (e.g. a table’s “Table. 3 lines. 2 columns.” or a pagebreak’s label) — locate is still safe to use for element-scoped highlighting, but a word-level substring/text-quote search against the DOM should be skipped, since the text isn’t actually there.