docs

Streaming

First audio in a few hundred milliseconds. Stream by default.

How it works

Set stream: true on POST /v1/audio/speech and the server returns audio in a chunked HTTP response as it’s generated, rather than buffering the whole clip first. For anything longer than a sentence this is the difference between “instant” and “broken”. Stream by default. (If you’re feeding text in incrementally, for example from an LLM, use input streaming over WebSocket instead.)

Formats & latency

pcm is the lowest-latency path: headerless 16-bit LE mono at your sample_rate (24 kHz default), playable the instant bytes arrive. Compressed formats (mp3, opus) stream too, but add a little container overhead.

Negotiate capabilities from GET /health: the engine and stream_formats fields tell you exactly what the current deployment streams. Don’t assume; read it.

Browser playback

Two approaches depending on format. For pcm, queue decoded buffers onto an AudioContext with a small (~150 ms) jitter buffer:

const res = await fetch("/api/tts", {          // your backend proxy
  method: "POST",
  body: JSON.stringify({ voice: "3b5275e4f2", stream: true, // voice: Tara
                         response_format: "pcm", input: text }),
});

const ctx = new AudioContext({ sampleRate: 24000 });
const reader = res.body.getReader();
let playAt = ctx.currentTime + 0.15;           // jitter buffer

for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  const pcm = new Int16Array(value.buffer);
  const buf = ctx.createBuffer(1, pcm.length, 24000);
  const ch = buf.getChannelData(0);
  for (let i = 0; i < pcm.length; i++) ch[i] = pcm[i] / 32768;
  const src = ctx.createBufferSource();
  src.buffer = buf;
  src.connect(ctx.destination);
  src.start(playAt);
  playAt += buf.duration;
}
Keep your API key on the server. The browser should call your backend, which holds the key and proxies to Svara.

Native & server playback

On native platforms, request pcm and write bytes to your audio sink as they arrive; first bytes land in a few hundred milliseconds on GPU serving. Re-align to 2-byte frames across chunk boundaries (a chunk can split a sample).

import pyaudio

pa = pyaudio.PyAudio()
out = pa.open(format=pyaudio.paInt16, channels=1, rate=24000, output=True)

with client.audio.speech.with_streaming_response.create(
    model="svara-1", voice="3b5275e4f2", input=text,  # voice: Tara
    response_format="pcm", extra_body={"stream": True},
) as response:
    tail = b""
    for chunk in response.iter_bytes():
        data = tail + chunk
        n = len(data) - (len(data) % 2)      # whole samples only
        out.write(data[:n]); tail = data[n:]

Telephony

For phone systems, request companded 8 kHz audio directly; no transcoding step in your media server:

  • { "response_format": "ulaw", "sample_rate": 8000 }: North American / μ-law
  • { "response_format": "alaw", "sample_rate": 8000 }: European / A-law

Resampling runs in-process and scales: 8 kHz streams are cheap, so this fans out to many concurrent calls.