Skip to content

Transport and routing

Transport is a host-neutral sample renderer. It owns clip voice state, prepared source views, logical groups, and the routing matrix; it does not own application scheduling, UI policy, or analyzer history. Device-backed hosts can feed its planar output into a driver, while an offline host can consume the same render contract into a file.

Prepare sources before a latency-critical start

Section titled “Prepare sources before a latency-critical start”

Registering a file and preparing its source are control/background operations. registerClipAudio() opens the file and reads metadata; prepareClipAudio() prewarms the registered reader at its trim-in point. Neither belongs in the audio callback. A registered source cannot be replaced in place while the old registration is active; stop and drain the relevant lifetimes, unregister, and then register a replacement.

The prepared-source boundary has two implementations:

  • A PreparedClipSource decodes the whole file to immutable engine-rate PCM. It is suitable for short clips and cannot miss once resident.
  • A StreamingClipSource retains a fixed page window filled by a background worker. The audio thread reads resident pages with position-explicit copies. A cache miss returns without touching the destination; transport renders silence and reports a buffer underrun while the worker catches up.

The control side primes the first-render pages before publishing an accepted start or seek. If preparation fails, the command fails rather than falling back to an unprepared source. This keeps file decode, resampling, seeking, hashing, and cue/trim prewarming out of the realtime path.

Source: clip_source.h, clip_source.h, and transport_controller.h.

A reliable lifecycle is:

  1. Create a nonzero clip handle in the host’s session model.
  2. Register the source on a control/background thread.
  3. Apply trim, fades, gain, loop, voice-mode, and routing-group metadata.
  4. Call prepareClipAudio() after registration or metadata changes and before a latency-critical start.
  5. Submit start/stop/seek commands from a control producer; the audio thread consumes only the prepared source and bounded command payload.
  6. Drain callbacks with processCallbacks() from one control/message thread.
  7. Stop and drain active voices and unread source commands before unregisterClipAudio(); NotReady means an ownership pin remains.

Metadata updates validate the complete operation. For example, updateClipMetadata() applies no changes if any field fails validation. A source replacement must therefore be a lifecycle transition, not an in-place pointer swap.

Source: transport_controller.h, transport_controller.h, and REALTIME_AUDIT.md.

Treat command ingress as bounded admission

Section titled “Treat command ingress as bounded admission”

Transport control methods may be called by concurrent UI, MIDI, OSC, and automation producers without an external dispatcher or mutex. This is bounded admission, not a promise that a complete call cannot spend time on control-side preparation. Registry work and payload reclamation may allocate, lock, or perform file I/O before publication.

The ingress has 255 usable nodes and permits at most 32 publication CAS attempts for one call. Publication order defines concurrent admission order; overlapping producers do not receive a scheduler-independent total order. A full pool or bounded publication refusal returns NotReady without persistent metadata mutation, peer choke, or tagged start settlement. Preparation rejection is a separate failure category, not a queue drop.

Poll getCommandIngressTelemetry() when diagnosing capacity pressure. Its counters are independent observations while producers or the consumer are active and saturate instead of wrapping. Do not spin or retry from the audio callback. The one audio consumer detaches the pending chain and processes it FIFO without allocation or blocking.

Source: transport_controller.h, transport_controller.h, and REALTIME_AUDIT.md.

A TransportConfig fixes sample rate, output-channel count, maximum block frames, active-voice capacity, group count, maximum source width, and source-channel policy for the controller lifetime. The routing matrix exposes up to 64 logical channels, 16 groups, and 32 outputs in its documented topology; route each logical group to a contiguous physical output bus with setGroupOutputBus().

Choose source handling deliberately:

  • Discrete keeps each source channel independent and is the target for multichannel or broadcast routing.
  • StereoPairs preserves stereo pairs, duplicates mono to left/right, and applies the configured downmix policy to wider material. This is the current transport playback behavior when stereo-pair handling is selected.
  • MonoFoldDown collapses source channels before routing.
  • DownmixPolicy::None does not invent a route for a wider source; the host must configure the missing routing. The SDK also provides ITU-style and equal-power downmix policies when a fold-down is explicitly desired.

The current transport source-channel behavior has an important limitation: clip rendering still uses stereo pair buffers even though the routing matrix carries explicit source and downmix policies. Do not document an arbitrary multichannel clip path as equivalent to a fully independent multichannel renderer. The configured output count and each route’s channel span remain the authority.

Source: routing_matrix.h, routing_matrix.h, transport_controller.h, and ARCHITECTURE.md.