Realtime hosting
A device-backed host adds an audio callback around the same host-neutral transport contract. Keep the callback path boring: fixed planar buffers, prepared sources, bounded atomic work, and no host policy. Put setup, source preparation, telemetry interpretation, and recovery on control or message threads.
Allocate before the callback
Section titled “Allocate before the callback”Create the transport with capacities that fit the intended route, then treat getRenderConfig() as immutable for that controller. Preallocate the exact output planes, scratch/interleave buffers, command-related host state, and any capture rings before starting the device. The controller requires exactly outputChannels writable output buffers and no more than maxBlockFrames frames per processAudio() call.
A valid device callback supplies a planar AudioProcessBlock; input and output channel counts are independent. The block’s pointers are valid only for the call. Do not retain them or infer input width from output width. Validate the callback’s shape before invoking downstream code; malformed shapes are no-touch returns, while valid zero-frame blocks remain valid state transitions.
Source: transport_controller.h, transport_controller.h, and audio_driver.h.
Keep the callback prohibition list literal
Section titled “Keep the callback prohibition list literal”Inside processAudio() and the device callback, do not allocate, grow containers, acquire locks, sleep, perform file/network/system I/O, log implicitly, or invoke host callbacks. File open, decode setup, hashing, resampler setup, cue/trim prewarming, and source page preparation happen before playback on a non-realtime thread. Callback diagnostics should be opt-in and allocation-free; production callbacks record simple counters rather than assembling history.
Stop and shutdown require explicit callback-lifetime coordination. Stop the producer, drain the relevant leases/events, and only then destroy callback targets or sources. A fixed delay is not a safe substitute for proving that no callback can still access the object.
Source: REALTIME_AUDIT.md, audio_driver.h, and audio_file_writer.h.
Prepare sources and define underrun behavior
Section titled “Prepare sources and define underrun behavior”Register files, apply metadata, and call prepareClipAudio() from control/background code. Short sources may become whole-file immutable PCM; long sources use a fixed page ring serviced by a background worker. On a streaming cache miss, the source read returns false with the destination untouched. The transport renders silence and emits a BufferUnderrun event rather than blocking for decode or file I/O.
The control side must prime the first-render pages for an accepted start or seek before publication. A failed prime is a preparation failure; it does not silently select an unprepared or source-less fallback. This behavior preserves callback timing and makes an underrun observable instead of hiding a blocking operation.
Source: clip_source.h, clip_source.h, and transport_controller.h.
Admit commands without an unbounded retry loop
Section titled “Admit commands without an unbounded retry loop”Concurrent control producers can submit supported transport commands through the fixed bounded MPSC ingress. It has 255 usable nodes and at most 32 publication CAS attempts per call. A full pool or bounded publication-contention refusal returns NotReady; it does not apply metadata, choke peer voices, or create a tagged start settlement. Preparation errors remain distinct from queue refusal.
Treat NotReady as an admission result to surface on the control side, not as an instruction for the audio callback to spin. Poll getCommandIngressTelemetry() from a non-realtime consumer to distinguish attempted, admitted, slot-unavailable, publication-contention, preparation-rejected, and processed counts. Counters saturate and may be independently observed while producers and the audio consumer are active.
The command pool bounds the realtime work, but whole control calls are not a wall-clock wait-free guarantee: registry lookup, source priming, and retained payload reclamation may allocate, lock, or perform file I/O on the producer thread.
Source: transport_controller.h, transport_controller.h, and REALTIME_AUDIT.md.
Drain telemetry on the message thread
Section titled “Drain telemetry on the message thread”The transport’s realtime telemetry bridge has one audio producer and one message-thread consumer. The audio side records callback health and copies fixed-size snapshots into a preallocated ring; it never allocates, locks, blocks, performs I/O, or overwrites an unread slot. A full ring drops the new snapshot and increments the drop count. The message thread owns all work after tryRead().
Configure decimation and drain with RealtimeTelemetry::tryRead() from exactly one message-thread consumer. Sequence gaps identify dropped snapshots. Use the snapshot for bounded transport position, callback diagnostics, active voice count, group/output meters, and routing meter availability. Build UI histories, smoothing, FFTs, and other analyzer state only after the read; none of that state belongs in the realtime bridge.
processCallbacks() is a separate audio-to-control event pump and must also be called from exactly one control thread. Callback delivery counters do not reset when that pump drains events, so poll them independently when diagnosing lost notifications.
Source: realtime_telemetry.h, realtime_telemetry.h, and transport_controller.h.