Skip to main content
Tyto scores incoming audio so you can inspect conditions associated with downstream voice AI failures. This guide uses Python SDK 3.4.0/core 0.26.0 and tyto-1.2-l-16khz. For complete files, see batch call analysis. For LiveKit Agents, the ai-coustics LiveKit extras plugin schedules analysis and exposes its collector as a frame processor. See LiveKit audio-quality analysis.

Two objects, two threads

The collector and analyzer may run concurrently. Each independent stream needs its own pair. Tyto’s window is 5 s; newer samples replace the oldest ones. Nothing is analyzed until your application calls analyze_buffered(). CPU cost grows with analysis frequency and concurrent streams. Start at a 5 s interval and measure before reducing it; 5 s is not a minimum. A 1 s interval analyzes overlapping audio. If inference falls behind, reduce frequency or concurrency instead of accumulating jobs.

Set up the pair

Create the collector and analyzer with analyzer_pair(). Use Python 3.12 or newer, a valid SDK key in AIC_SDK_LICENSE and a non-silent mono WAV file containing at least 5 s of user speech. Create an isolated environment:
Save the script below as analyze_stream.py. It feeds a recording at its original rate to demonstrate the same collector/worker division you use with live input. It does not capture a microphone or make a call.

Buffer and analyze

Run:
Expect JSON scores after the first full window and a completed-pass count. Scores depend on your input. Authorization or analysis errors fail the run. The script allocates blocks and uses Python synchronization to keep the example clear. It is a paced file demonstration, not allocation-free callback code. In a native real-time callback, preallocate buffers and keep logging, waits, model loading and analysis off the audio thread.

The first few seconds

Before the collector has a full window, the analyzer fills missing context with silence. The example waits until it has buffered 5 s of real input before accepting a score. This avoids interpreting a partially empty startup window as a representative call segment. Keep sample count, audio timestamps and analysis timestamps separate. A new score describes the latest buffered window, not necessarily a new non-overlapping span. Use the smoothing guidance when designing interventions.

Reset between streams

Call analyzer.reset() on discontinuity or before reusing a pair for another call. This requests clearing of analyzer and collector history while preserving collector configuration. Clear your application warmup count and smoothing state too. Coordinate reset with the owner of the input stream and analysis worker so old frames cannot arrive after reset. A native reset operation is real-time safe, but the surrounding Python/task coordination is not an allocation-free callback guarantee. A terminated session needs a new pair.

Running alongside enhancement and VAD

Give the collector and dedicated voice activity detector (VAD) the original input. The Python processor returns enhanced output; native in-place APIs should run enhancement after the read-only consumers:
Initialize all consumers for the actual host rate and block size. The model’s native rate is not necessarily the input rate; the core collector handles supported non-native host rates. See audio format.

When analysis stops being allowed

ProcessingNotAllowedError can occur after startup as well as on initial analysis. Inspect authorization, session termination and required reporting/connectivity conditions using troubleshooting. Report degraded analysis, preserve your application’s audio policy and bound recovery attempts. Do not treat stale scores as current results. Enhancement and VAD have separate processing-error paths.

Entry points per language

Check initialization, errors and supported versions in your binding guide. Node.js analyze() blocks its thread; analyzeAsync() uses a worker. Browser analysis also needs scheduling appropriate to its execution context.

Find out more