Skip to main content
async function ttsWebsocketLowLatency(client: Cartesia): Promise<void> {
  const sampleRate = 44100;
  const audioCtx = new AudioContext({ sampleRate });
  let nextStartTime = audioCtx.currentTime;

  const ws = await client.tts.websocket();
  ws.on('error', (err) => console.error(err.message));

  try {
    const ctx = ws.context({
      model_id: 'sonic-latest',
      voice: { mode: 'id', id: '6ccbfb76-1fc6-48f7-b71d-91ac6298247b' },
      output_format: { container: 'raw', encoding: 'pcm_f32le', sample_rate: sampleRate },
      language: 'en',
    });

    await ctx.push({
      transcript: 'Low latency streaming. Each chunk plays as soon as it arrives.',
    });
    await ctx.no_more_inputs();

    for await (const event of ctx.receive()) {
      if (event.type === 'chunk' && event.audio) {
        const floats = new Float32Array(
          event.audio.buffer,
          event.audio.byteOffset,
          event.audio.byteLength / 4,
        );

        const audioBuffer = audioCtx.createBuffer(1, floats.length, sampleRate);
        audioBuffer.getChannelData(0).set(floats);

        const source = audioCtx.createBufferSource();
        source.buffer = audioBuffer;
        source.connect(audioCtx.destination);

        // Schedule this chunk right after the previous one
        const startTime = Math.max(nextStartTime, audioCtx.currentTime);
        source.start(startTime);
        nextStartTime = startTime + audioBuffer.duration;
      } else if (event.type === 'error') {
        console.error(event.title, event.message);
      }
    }
  } finally {
    ws.close();
  }
}
From cartesia-js/examples/browser_examples.ts:180

Run this example

This example runs in the browser. See the Next.js example for a working setup.