Skip to main content
Stream audio chunks as they are synthesized, enabling playback to start before the full synthesis completes.

Streaming Synthesis

val longText = """
    This is a very long text that will be synthesized in chunks.
    Each chunk will be delivered as soon as it's ready,
    allowing playback to start immediately without waiting
    for the entire synthesis to complete.
""".trimIndent()

RunAnywhere.synthesizeStream(
    text = longText,
    options = TTSOptions(rate = 1.0f),
    onAudioChunk = { chunk ->
        // Play each chunk as it arrives
        audioPlayer.enqueue(chunk)
    }
)

Example: Streaming Audio Player

class StreamingAudioPlayer {
    private val audioQueue = ConcurrentLinkedQueue<ByteArray>()
    private var isPlaying = false

    fun enqueue(audioChunk: ByteArray) {
        audioQueue.add(audioChunk)
        if (!isPlaying) {
            startPlayback()
        }
    }

    private fun startPlayback() {
        isPlaying = true
        CoroutineScope(Dispatchers.IO).launch {
            while (audioQueue.isNotEmpty() || isPlaying) {
                val chunk = audioQueue.poll()
                if (chunk != null) {
                    playChunk(chunk)
                } else {
                    delay(10) // Wait for more chunks
                }
            }
        }
    }

    private fun playChunk(chunk: ByteArray) {
        // Play audio chunk using AudioTrack
    }

    fun stop() {
        isPlaying = false
        audioQueue.clear()
    }
}

Example: Chat Response with Streaming TTS

class ChatViewModel : ViewModel() {
    private val audioPlayer = StreamingAudioPlayer()

    fun sendMessageAndSpeak(prompt: String) {
        viewModelScope.launch {
            // Generate text with streaming
            val streamResult = RunAnywhere.generateStreamWithMetrics(prompt)

            // Collect full response for TTS
            val fullResponse = StringBuilder()
            streamResult.stream.collect { token ->
                fullResponse.append(token)
                _displayText.value += token
            }

            // Stream synthesize the full response
            RunAnywhere.synthesizeStream(
                text = fullResponse.toString(),
                options = TTSOptions(),
                onAudioChunk = { chunk ->
                    audioPlayer.enqueue(chunk)
                }
            )
        }
    }
}

Stop Synthesis

Cancel ongoing synthesis:
// Stop synthesis mid-stream
RunAnywhere.stopSynthesis()

When to Use Streaming

ScenarioRecommended
Short text (under 100 chars)synthesize()
Long text (over 200 chars)synthesizeStream()
Real-time chat responsessynthesizeStream()
Pre-cached audiosynthesize()
Streaming synthesis reduces time-to-first-audio for long text: - Regular synthesis: Wait for full synthesis, then play - Streaming synthesis: Start playing after first chunk (~100ms)

Performance Characteristics

Text LengthRegular SynthesisStreaming First Audio
50 chars~100ms~100ms
200 chars~400ms~100ms
500 chars~1000ms~100ms
1000 chars~2000ms~100ms