Header Logo

Load Testing TTS for Live AI Avatars: Latency, Jitter, and Concurrency

Load Testing TTS for Live AI Avatars: Latency, Jitter, and Concurrency

Load test TTS for live AI avatars: measure first-audio latency, jitter, lip-sync, and session concurrency.

Introduction


When you put a realtime avatar behind a voice agent, the hard part is rarely “can it talk?” The hard part is whether it can keep talking, lip-syncing, and rendering video without falling apart under load. In practice, the user experience is defined by three latency budgets at once: ASR and LLM response time, TTS generation time, and the video pipeline’s ability to stay synchronized while sessions start, stop, and overlap.


This matters even more for live products because avatar systems don’t just stream audio. They also have to ship frames, maintain session state, and survive bursty concurrency from demo traffic, product launches, and long-tail customer usage. By the end of this post, you should be able to reason about the main failure modes, design a realistic load test for TTS-driven avatar sessions, and know what to watch when the system starts getting slow or “wobbly.”


What to measure: latency is necessary, not sufficient


For voice-first avatars, “latency” usually gets used as a single number. That’s too coarse. You want to split it into at least four measurements:


  • TTFB for speech: time from text availability to first audio bytes from TTS.

  • End-to-end utterance time: time from text input to fully synthesized speech ready for playback.

  • Frame delay: time between audio progression and avatar video update.

  • Session setup time: time to create the avatar session and join the media pipeline.


For a live avatar, the first audible phoneme matters more than the final byte. A TTS service that finishes an 8-second utterance in 1.2 seconds may still feel slow if the first 250 ms are spent in queueing or if the avatar video starts two frames behind the audio.


The practical target is to measure the pipeline as the user experiences it. That means instrumenting timestamps at the edges: when text is submitted, when the first audio chunk arrives, when playback starts, and when the avatar becomes visibly active. If you only watch server CPU and request duration, you’ll miss synchronization failures that users can clearly see.


Latency versus jitter: why average numbers lie


Average latency is a weak predictor of perceived quality. Jitter—variation across requests and across a session—is often the real problem. In a conversation, users tolerate a slightly slower avatar better than one that alternates between “instant” and “stalled.”


There are two forms of jitter worth tracking:


  • Inter-request jitter: variation across different TTS calls under similar conditions.

  • Intra-session jitter: variation between consecutive utterances in the same active avatar session.


Intra-session jitter is especially important because it reveals stateful bottlenecks: warm caches going cold, connection reuse failing, token refresh overhead, or backend queue contention once concurrency rises. A system that is stable at p50 but spiky at p95 and p99 will create audible gaps and visible mouth-position stutter, even if the mean looks fine.


For load testing, don’t just record p50/p95/p99. Also chart standard deviation and the distribution over time. A simple rolling window often shows whether you’re hitting a throughput wall or just a transient queue.


Concurrency: model sessions, not just requests


Load testing TTS for avatars is not the same as load testing a stateless text API. You should model sessions because the expensive part is often the media lifecycle: session creation, auth, room join, audio track attachment, and video frame synchronization.


A realistic test plan usually includes:


  1. Ramp-up: gradually increase active avatar sessions to expose queue buildup.

  2. Steady state: maintain a fixed number of concurrent sessions long enough to surface memory leaks and tail latency.

  3. Bursts: simulate marketing traffic or live events where many sessions start at once.

  4. Churn: mix session termination and new session creation to stress cleanup paths.


If you only blast a TTS endpoint with independent requests, you may miss the two failure modes that matter most in production:


  • Cold-start amplification: the first utterance in a new session takes much longer than subsequent utterances.

  • Resource fragmentation: concurrency grows, but some backend pool or media worker saturates and latency rises nonlinearly.


For avatars, always include a think time model. Real users don’t speak continuously; they pause, interrupt, and resume. That creates a different load profile than synthetic “firehose” traffic and often reveals queue starvation more accurately.


How to build a useful load test


A good test harness should drive the same path your production app uses, not a synthetic shortcut. For a TTS-backed avatar, that usually means one of these patterns:


  • Voice agent process generates text, sends it to TTS, and renders audio/video.

  • Backend creates avatar sessions, then a client streams utterances into those sessions.

  • Browser or media client joins an iframe/embed or WebRTC session and exercises the realtime path.


Start by defining the service-level objective in user terms. Example: “95% of first speech chunks should begin within 800 ms after text is ready, while 200 concurrent sessions remain synchronized.” From there, instrument the following:


  • Session create latency

  • TTS time to first audio chunk

  • Audio chunk cadence

  • Video frame generation delay

  • Queue depth / worker utilization

  • Failure rate by phase, not just by request


Be careful with retries. Retrying a slow TTS request can hide the underlying problem and inflate concurrency on the backend. In load tests, it is usually better to record the first-failure behavior separately from recovery behavior.


Example: measuring avatar-session setup with the REST API


If your test needs to create sessions programmatically, use the REST API from a harness that captures timestamps around each step. The exact request shape depends on the endpoint and fields in the docs, but the pattern looks like this:


curl -sS -X POST https://api.protoface.com/<session-endpoint> \
}'
curl -sS -X POST https://api.protoface.com/<session-endpoint> \
}'
curl -sS -X POST https://api.protoface.com/<session-endpoint> \
}'


In your test runner, record:


t0 = time.monotonic()
setup_ms = (t1 - t0) * 1000
t0 = time.monotonic()
setup_ms = (t1 - t0) * 1000
t0 = time.monotonic()
setup_ms = (t1 - t0) * 1000


The important part is not the specific field names; it’s preserving the boundaries so you can separate API overhead from media startup cost. For the exact request and response details, use the docs at docs.protoface.com.


Where the LiveKit plugin fits


If your avatar is part of a voice agent, the most representative test is often to exercise the same agent stack you run in production. The quickstart examples are a good reference for wiring a realtime agent path end to end, and the LiveKit integration lets the agent gain a synchronized talking face without inventing a separate media pipeline.


In that setup, the main load-sensitive boundaries are the agent turn loop and the audio/video handoff. A useful plugin-level smoke test is to spin up multiple concurrent agents, feed each one a short scripted turn, and verify that the avatar remains in lockstep with the audio. Example shape:


from livekit.agents import WorkerOptions, cli

)
from livekit.agents import WorkerOptions, cli

)
from livekit.agents import WorkerOptions, cli

)


What you want to observe is whether new turns increase only total latency, or whether they also destabilize lip sync. If the latter happens, the bottleneck is usually not the model—it’s queueing or media contention.


Common gotchas in avatar TTS load tests


A few failure modes show up repeatedly:


  • Testing only short utterances: short prompts hide streaming backpressure and chunk pacing issues.

  • Ignoring warm-up: caches, connection pools, and media workers often behave differently after the first few sessions.

  • Measuring only backend timing: users see audio and video; your test should too, even if that means capturing playback timestamps client-side.

  • Over-parallelizing one process: a single load generator can become the bottleneck and distort results.

  • Dropping session cleanup: leaked sessions make later results meaningless and create false queue pressure.


Another subtle issue is output variability. If the TTS layer changes pacing based on punctuation or chunk size, your “same request” may not be the same workload. Keep your test corpus stable and representative: short confirmations, medium responses, and a few long answers with pauses.


How Protoface helps in practice


Protoface is useful here because it gives you the surfaces you need to test the whole path, not just the speech synthesizer. If you are building a voice agent with a live avatar, the LiveKit plugin is the most direct way to attach synchronized video to the agent, while the REST API and Python SDK let you automate session creation and teardown from a load harness. For implementation details, the docs at docs.protoface.com are the right place to check the exact session fields, authentication model, and limits.


That matters because concurrency bugs usually appear at the integration boundary: auth, session startup, media attach, and state cleanup. Having a developer-facing API makes it much easier to reproduce those failure modes under controlled load instead of waiting for them to show up in production.


Conclusion


Load testing TTS for live AI avatars is really load testing a realtime system: text generation, speech synthesis, streaming transport, and video synchronization all have to stay within budget. The metrics that matter are first-audio latency, tail latency, jitter, and session-level concurrency behavior—not just average request time.


If you’re designing this from scratch, start with a session-based test plan, measure the edges of the pipeline, and make sure your harness reflects real conversation patterns instead of raw throughput. For deeper implementation details, integration patterns, and SDK references, check docs.protoface.com and the relevant repos on GitHub.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.