Skip to content

Text to speech

Choose an API based on how the input text becomes available.

API Use it when
generate() You need one complete audio result.
stream() All text is available, but audio should arrive incrementally over HTTP.
realtime() Text arrives incrementally, such as tokens from a language model.
openRealtimeSession() You need explicit send, flush, finish, or alignment control.

Complete generation

val audio = elevenLabs.textToSpeech.generate(
    TextToSpeechRequest(
        voiceId = voiceId,
        text = "A complete passage to synthesize.",
        outputFormat = OutputFormat.Mp3_44100_128,
    ),
)

HTTP streaming

elevenLabs.textToSpeech.stream(
    TextToSpeechRequest(
        voiceId = voiceId,
        text = "A longer passage to synthesize.",
    ),
).collect { chunk ->
    audioPipeline.write(chunk.bytes)
}

An AudioChunk is an arbitrary transport chunk. It is not guaranteed to contain a complete codec frame or audio container.

Realtime text input

val llmText: Flow<String> = languageModel.responses()

elevenLabs.textToSpeech.realtime(
    voiceId = voiceId,
    text = llmText,
    options = RealtimeTtsOptions(
        modelId = "eleven_flash_v2_5",
        outputFormat = OutputFormat.Pcm_24000,
    ),
).collect { chunk ->
    audioPipeline.write(chunk.bytes)
}

The returned flow is cold. Every collection opens a new session, resolves fresh credentials, sends each non-empty input value, and closes the session on completion, cancellation, or failure.

Controllable realtime session

val session = elevenLabs.textToSpeech.openRealtimeSession(
    voiceId = voiceId,
    options = RealtimeTtsOptions(syncAlignment = true),
)

coroutineScope {
    launch {
        session.events.collect { event ->
            when (event) {
                is RealtimeTtsEvent.Audio -> {
                    audioPipeline.write(event.bytes)
                    updateCaptions(event.normalizedAlignment)
                }
                RealtimeTtsEvent.Finished -> Unit
            }
        }
    }

    session.sendText("Hello ")
    session.sendText("from realtime TTS.", flush = true)
    session.finish()
}

Use finish() for graceful completion. Observe completion through events, or call close() to cancel immediately.