Custom Backends and Registries
The requirements stated in the C API’s chapters on custom backends and shared library backends apply to backends implemented in Python.
prism.CustomBackend
Base class of backends implemented in Python.
Syntax
class CustomBackend
Attributes
EXTRA_FEATURES
Feature bits that no method determines: the
silence-trimming bits and the classification bits. A subclass that
presents messages through a screen reader SHOULD set
is_screen_reader; one that synthesizes speech SHOULD set
is_speech_engine. Setting a bit that corresponds to a method
raises ValueError at registration, and setting both
classification bits raises
prism.common.PrismInvalidParamError.
Remarks
A subclass is registered with RegistryBuilder.add_backend and is
then used like any other backend. Prism instantiates the subclass with no
arguments for each backend instance it creates, so the subclass MUST be
constructible without arguments, and state shared between instances MUST be
synchronized.
A subclass overrides the operations it supports. The feature bit of an
operation is set exactly when the subclass overrides the method of the same
name; operations that are not overridden raise
prism.common.PrismNotImplementedError without calling Python.
Methods are named after the members of PrismBackendVTable:
prism.Backend.speaking is implemented by is_speaking, and
prism.Backend.volume by get_volume and set_volume.
Each method MUST behave as described for the corresponding member of
prism.Backend. Prism validates arguments first, so a method never
receives text that is not valid UTF-8 or a voice parameter outside
[0.0, 1.0]. A method MAY receive empty text from callers of the C API.
An exception raised by a method is printed to standard error and reported
as an error: a prism.PrismError as its own code,
NotImplementedError as PRISM_ERROR_NOT_IMPLEMENTED, UnicodeError
as PRISM_ERROR_INVALID_UTF8, ValueError as
PRISM_ERROR_INVALID_PARAM, and any other exception as
PRISM_ERROR_INTERNAL. An exception raised by is_supported is
reported as False.
The methods of one instance are never called concurrently, but MAY be called on any thread. Methods of different instances MAY be called concurrently.
Example
A backend that writes speech requests to standard output:
import prism
class Printer(prism.CustomBackend):
def speak(self, text, interrupt):
print(text)
with prism.RegistryBuilder() as builder:
printer_id = builder.add_backend("Printer", Printer, priority=10)
registry = builder.freeze()
context = prism.Context(registry)
backend = context.create(prism.BackendId(printer_id))
backend.speak("Hello from a custom backend")
CustomBackend.initialize
Prepares the instance for use.
Syntax
def initialize() -> None
Remarks
Called once, after construction and before any operation other than
is_supported. The default does nothing. An implementation whose
screen reader or speech engine is unavailable SHOULD raise
prism.common.PrismBackendNotAvailableError.
CustomBackend.is_supported
Reports whether the backend is available.
Syntax
def is_supported() -> bool
Return Value
Whether the backend is available. The default is True.
Remarks
The result is reported as
prism.BackendFeatures.is_supported_at_runtime, and is sampled by
availability monitoring. This method MAY be called before
initialize, and MUST NOT assume the instance is initialized. It is
called on the sampling thread of contexts that monitor availability, and
SHOULD return quickly.
CustomBackend.speak
Speaks text.
Syntax
def speak(text: str, interrupt: bool) -> None
Parameters
text
The text to speak.
interrupt
Whether to interrupt speech in progress.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.speak.
CustomBackend.speak_to_memory
Synthesizes text and passes the audio to emit.
Syntax
def speak_to_memory(text: str, emit: AudioCallback) -> None
Parameters
text
The text to synthesize.
emit
A function that takes the next portion of audio, as described
under prism.AudioCallback.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.speak_to_memory. The method MUST NOT return
until all audio has been passed to emit. Prism clamps samples to
[-1.0, 1.0] and replaces non-finite values with 0.0 before delivering them.
The channel count and sample rate passed to emit SHOULD match
get_channels and get_sample_rate.
CustomBackend.braille
Shows text on a braille display.
Syntax
def braille(text: str) -> None
Parameters
text
The text to show.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.braille.
CustomBackend.output
Presents text through speech and braille.
Syntax
def output(text: str, interrupt: bool) -> None
Parameters
text
The text to present.
interrupt
Whether to interrupt output in progress.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.output. Prism does not derive this operation from speak and braille; a backend that supports output MUST override it.
CustomBackend.stop
Stops speech and discards queued speech.
Syntax
def stop() -> None
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.stop.
CustomBackend.pause
Pauses speech.
Syntax
def pause() -> None
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.pause.
CustomBackend.resume
Resumes paused speech.
Syntax
def resume() -> None
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.resume.
CustomBackend.is_speaking
Reports whether speech is in progress.
Syntax
def is_speaking() -> bool
Return Value
Whether speech is in progress.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.speaking.
CustomBackend.set_volume
Sets the volume.
Syntax
def set_volume(volume: float) -> None
Parameters
volume
The volume, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.volume.
CustomBackend.get_volume
Returns the volume.
Syntax
def get_volume() -> float
Return Value
The volume, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.volume.
CustomBackend.set_rate
Sets the rate.
Syntax
def set_rate(rate: float) -> None
Parameters
rate
The rate, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.rate.
CustomBackend.get_rate
Returns the rate.
Syntax
def get_rate() -> float
Return Value
The rate, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.rate.
CustomBackend.set_pitch
Sets the pitch.
Syntax
def set_pitch(pitch: float) -> None
Parameters
pitch
The pitch, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.pitch.
CustomBackend.get_pitch
Returns the pitch.
Syntax
def get_pitch() -> float
Return Value
The pitch, from 0.0 to 1.0.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.pitch.
CustomBackend.refresh_voices
Reloads the list of voices.
Syntax
def refresh_voices() -> None
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.refresh_voices.
CustomBackend.count_voices
Returns the number of voices.
Syntax
def count_voices() -> int
Return Value
The number of voices.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.voices_count.
CustomBackend.get_voice_name
Returns the name of a voice.
Syntax
def get_voice_name(voice_id: int) -> str
Parameters
voice_id
The index of the voice.
Return Value
The name of the voice. It MUST NOT contain a NUL character.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.get_voice_name.
CustomBackend.get_voice_language
Returns the language of a voice.
Syntax
def get_voice_language(voice_id: int) -> str
Parameters
voice_id
The index of the voice.
Return Value
The language of the voice, preferably a BCP 47 tag. It MUST NOT contain a NUL character.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.get_voice_language.
CustomBackend.set_voice
Selects a voice.
Syntax
def set_voice(voice_id: int) -> None
Parameters
voice_id
The index of the voice.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.voice.
CustomBackend.get_voice
Returns the index of the selected voice.
Syntax
def get_voice() -> int
Return Value
The index of the selected voice.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.voice.
CustomBackend.get_channels
Returns the number of audio channels.
Syntax
def get_channels() -> int
Return Value
The number of channels.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.channels.
CustomBackend.get_sample_rate
Returns the audio sample rate.
Syntax
def get_sample_rate() -> int
Return Value
The sample rate, in hertz.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.sample_rate.
CustomBackend.get_bit_depth
Returns the native audio bit depth.
Syntax
def get_bit_depth() -> int
Return Value
The bit depth.
Exceptions
Unless overridden.
Remarks
Implements prism.Backend.bit_depth.
prism.RegistryBuilder
Builds a registry.
Syntax
class RegistryBuilder()
Exceptions
If the builder cannot be created.
Remarks
This class wraps prism_registry_builder_new and
prism_registry_builder_free, and MAY be used as a context manager. A new
builder contains the compiled-in backends, whose names and identifiers
therefore cannot be used by other backends. Adding a backend creates no
instance of it.
freeze moves the builder’s backends to a new registry and spends the
builder; a spent builder can only be closed. The builder is closed by
close, when the object is destroyed, or at the end of a with
statement.
A builder is not thread-safe.
RegistryBuilder.add_backend
Adds a backend implemented in Python.
Syntax
def add_backend(
name: str,
backend: type[CustomBackend],
*,
priority: int = 100,
) -> int
Parameters
name
The name of the backend. It MUST be non-empty and unique in the builder. It determines the identifier.
backend
The subclass of CustomBackend that implements the
backend.
priority
The priority of the backend. It MUST NOT be negative. The
priorities of built-in backends are available from
prism.Context.priority_of.
Return Value
The identifier of the backend, which prism.BackendId converts.
Exceptions
If backend is not a subclass of CustomBackend.
If the builder is spent or closed.
If EXTRA_FEATURES sets a bit that corresponds to a
method.
If name is empty, priority is
negative, or both classification bits are set.
If the builder already contains a backend with the same name or identifier.
Remarks
This method wraps prism_registry_builder_add_backend. The backend’s
features are derived from backend as described under
CustomBackend. backend is kept alive for as long as the
registry or any instance created from it.
RegistryBuilder.add_library
Adds the backends of a shared library plugin.
Syntax
def add_library(
path: str | os.PathLike[str],
*,
priority_override: int | None = None,
) -> int
Parameters
path
The path of the library.
priority_override
A non-negative priority for every backend in the
library, or None to use the priorities the library declares.
Return Value
The number of backends added.
Exceptions
If the builder is spent or closed.
If path is not a str or a path-like object yielding
one.
If path is empty or contains a
NUL character, or the library describes an inconsistent backend.
If priority_override is negative.
If the platform does not support shared library backends.
If the library cannot be opened.
If the library is not a Prism plugin.
If the plugin is incompatible with this version of Prism.
If the builder already contains a backend with the name or identifier of one in the library.
Remarks
This method wraps prism_registry_builder_add_library. If any error
occurs, no backend is added and the library is unloaded. Otherwise one
backend is added for each backend the plugin describes, in the plugin’s
order. The library remains loaded while the registry or any instance created
from it exists.
Loading a library runs its code with the privileges of the application, before Prism checks that it is a plugin. Applications MUST load only trusted libraries, from locations that less privileged users cannot write.
The identifiers of the added backends are determined by their names, and
are available from prism.Context.id_of once the registry is frozen.
RegistryBuilder.freeze
Creates a registry from the builder.
Syntax
def freeze() -> Registry
Return Value
The registry.
Exceptions
If the builder is spent or closed, or the registry cannot be created.
Remarks
This method wraps prism_registry_freeze. The builder’s backends are
moved to the registry, and the builder is spent.
RegistryBuilder.close
Releases the builder.
Syntax
def close() -> None
Remarks
This method wraps prism_registry_builder_free. Backends in a builder
closed without being frozen are discarded. Closing a closed builder does
nothing.
prism.Registry
A registry produced by RegistryBuilder.freeze.
Syntax
class Registry(ptr: ffi.CData)
Parameters
ptr
A PrismRegistry * whose reference the object owns.
Remarks
A registry is passed to prism.Context, and cannot be changed. The
object holds a reference to the registry, released through
prism_registry_release by close, when the object is destroyed, or
at the end of a with statement. Each context holds a reference of its
own, so the object MAY be closed once the registry is in use by a context.
Used by RegistryBuilder.freeze.
Registry.close
Releases the object’s reference to the registry.
Syntax
def close() -> None
Remarks
Closing a closed registry does nothing.