prism-sys 0.1.1

Raw FFI bindings to the prism speech library
Documentation
## Thread Safety

Prism provides the following thread safety guarantees:

* The functions `prism_init` and `prism_shutdown` are thread-safe. Multiple threads MAY call `prism_init` concurrently; each call returns an independent context. However, `prism_shutdown` MUST only be called once per context, and the context MUST NOT be used from any thread after `prism_shutdown` has been called on that context. If one thread calls `prism_shutdown` while another thread is using the same context, the behavior is undefined.
* All `prism_registry_*` functions are thread-safe when called on the same context from multiple threads. The registry maintains an internal backend cache: a partial mapping from backend identifiers to live backend instances, shared across all contexts bound to that registry. Contexts bound to different registries share no cache state, even for the same compiled-in backend. Each registry function is defined as an ordered sequence of one or more cache operations (lookup or install) and zero or more unsynchronized operations (invocation of a backend's factory, and the call to `prism_backend_initialize`).
* Cache operations are atomic with respect to each other. Cache operations affecting the same backend identifier are totally ordered; the order of cache operations affecting distinct backend identifiers is unspecified. Unsynchronized operations are not ordered with respect to any cache operation or any other unsynchronized operation, and MAY proceed concurrently with arbitrary other registry activity.
* The functions `prism_registry_count`, `prism_registry_id_at`, `prism_registry_id`, `prism_registry_name`, `prism_registry_priority`, `prism_registry_exists`, and `prism_registry_get` consist of cache operations only. They MAY execute concurrently with each other and with the unsynchronized portions of prism_registry_acquire and prism_registry_acquire_best.
* The functions `prism_registry_acquire` and `prism_registry_acquire_best` consist of a sequence of cache operations interleaved with unsynchronized operations. As a consequence of the unsynchronized portion, two threads requesting the same uncached backend MAY each perform an independent construction; in such cases, the cache retains exactly one of the constructed instances, and all callers receive that instance. Discarded instances are destroyed when their reference counts reach zero. Applications MUST NOT rely on `prism_registry_acquire` or `prism_registry_acquire_best` being atomic in their entirety with respect to other registry operations.
* Individual backend instances are NOT thread-safe. Applications MUST NOT call functions on the same `PrismBackend` instance from multiple threads concurrently without external synchronization. This restriction applies even to logically independent operations; for example, calling `prism_backend_get_rate` from one thread while another thread calls `prism_backend_set_volume` on the same backend instance produces undefined behavior.
* Different backend instances MAY be used from different threads concurrently without restriction. For example, if an application creates two backends using `prism_registry_create`, those two backends may be used from separate threads without synchronization.
* The `prism_registry_create`, `prism_registry_create_best`, `prism_registry_acquire`, and `prism_registry_acquire_best` functions are thread-safe with respect to the registry. However, the returned backend instances are subject to the single-threaded constraint described above.
* Audio callbacks passed to `prism_backend_speak_to_memory` MAY be invoked from a thread other than the calling thread, depending on the backend. Callback implementations MUST be prepared for this possibility and MUST provide their own synchronization if they access shared state. The callback MUST NOT call any Prism function on the backend instance that initiated the synthesis, as this would violate the single-threaded backend constraint and may also cause deadlocks.
* When using `prism_registry_acquire` or `prism_registry_acquire_best`, multiple calls may return handles to the same underlying backend instance if a cached instance exists. In this case, all handles share the same backend state, and the single-threaded constraint applies across all handles. Applications that acquire backends from the cache and use them from multiple threads MUST synchronize access externally.
* A registry's backend set is fixed when the registry is created. No registration ever occurs on a live registry, so no registration operation is ordered against any registry operation described above.
* A `PrismRegistryBuilder` is NOT thread-safe. A builder is a transient configuration object, so all operations on a given builder MUST be externally synchronized if it is somehow reachable from more than one thread.
* `prism_registry_retain` and `prism_registry_release` are thread-safe. Note that the final `prism_registry_release` (or the final `prism_shutdown` on a context bound to the registry, whichever comes last) finalizes the registry on the calling thread; any `userdata_free` functions belonging to custom backends may therefore be invoked on that thread.
* Custom backend implementations are subject to the same single-instance constraint as callers: because applications MUST NOT call functions on one backend instance from multiple threads concurrently, a custom backend's vtable functions are never invoked concurrently for the same instance. Distinct instances of the same custom backend MAY be invoked concurrently, and any state they share (for example, state reachable through `userdata` when no `create` function is supplied) MUST be synchronized by the implementation.
* The functions `prism_availability_poll_pause` and `prism_availability_poll_resume` are thread-safe and MAY be called from any thread, including concurrently with each other and with the poll thread's own activity. The availability callback configured through `PrismConfig` is invoked from Prism's internal poll thread, not from a thread owned by the application; callback implementations MUST synchronize any shared state they access, and MUST NOT call `prism_shutdown` on the owning context. The single-threaded backend constraint continues to apply to any backend instance the callback creates or acquires. `prism_availability_auto_power_supported` is thread-safe and MAY be called at any time.
* The logging functions `prism_set_log_handler`, `prism_set_log_level`, `prism_log`, and `prism_log_flush` are thread-safe and MAY be called from any thread concurrently, including before `prism_init` and after `prism_shutdown`. A log handler is invoked only from Prism's internal logging thread and is never invoked concurrently with itself; handler implementations MUST synchronize any shared state and MUST NOT call any logging function. `prism_log_shutdown` is thread-safe with respect to other logging functions, but the application MUST ensure it is not called from within a log handler.

Applications requiring concurrent speech synthesis from multiple threads SHOULD create separate backend instances per thread using `prism_registry_create` or `prism_registry_create_best`.