Implement TTS Component for Voice Pipeline Completion

Resolved 💬 2 comments Opened Oct 20, 2025 by sanchitmonga22 Closed Oct 20, 2025

Priority

CRITICAL - Production Blocker

Context

The Kotlin SDK currently has only a stub TTS component, making it impossible to complete the voice pipeline (VAD → STT → LLM → TTS). The iOS SDK has a fully functional TTS implementation that should be used as the source of truth.

Current State

  • File: src/commonMain/kotlin/com/runanywhere/sdk/components/tts/TTSComponent.kt (stub only)
  • Status: Empty implementation, no platform-specific code
  • Impact: Voice pipeline cannot generate audio responses

iOS Reference Implementation

  • Base: sdk/runanywhere-swift/Sources/RunAnywhere/Components/TTS/TTSComponent.swift
  • Services: sdk/runanywhere-swift/Sources/RunAnywhere/Components/TTS/Services/TTSService.swift
  • Platform: sdk/runanywhere-swift/Sources/RunAnywhere/Infrastructure/TTS/

iOS Architecture Pattern

// Component
public final class TTSComponent: ModelBasedComponent {
    private var service: TTSService?
    
    public func synthesize(text: String, options: TTSOptions) async throws -> Data
    public var availableVoices: [String] { get async }
}

// Service Interface
public protocol TTSService: Sendable {
    func synthesize(text: String, options: TTSOptions) async throws -> Data
    var availableVoices: [String] { get async }
}

Implementation Plan

1. Define Common Interfaces (commonMain)

// commonMain/kotlin/com/runanywhere/sdk/components/tts/TTSComponent.kt
class TTSComponent(
    configuration: TTSConfiguration,
    serviceContainer: ServiceContainer? = null
) : BaseComponent<TTSService>(configuration, serviceContainer) {
    
    suspend fun synthesize(text: String, options: TTSOptions): ByteArray
    val availableVoices: List<String>
    
    override suspend fun createService(): TTSService {
        val provider = ModuleRegistry.ttsProvider(configuration.modelId)
        return provider?.createTTSService(configuration)
            ?: throw SDKError.ComponentNotAvailable("No TTS provider")
    }
}

// commonMain/kotlin/com/runanywhere/sdk/components/tts/services/TTSService.kt
interface TTSService {
    suspend fun synthesize(text: String, options: TTSOptions): ByteArray
    val availableVoices: List<String>
}

// commonMain/kotlin/com/runanywhere/sdk/components/tts/models/TTSConfiguration.kt
data class TTSConfiguration(
    val modelId: String,
    val voice: String? = null,
    val language: Language = Language.EN,
    val speed: Float = 1.0f,
    val pitch: Float = 1.0f
) : ComponentConfiguration

data class TTSOptions(
    val voice: String? = null,
    val speed: Float = 1.0f,
    val pitch: Float = 1.0f
)

2. Platform Implementations

Android (androidMain)
// androidMain/kotlin/com/runanywhere/sdk/components/tts/services/AndroidTTSService.kt
class AndroidTTSService(
    private val context: Context,
    private val configuration: TTSConfiguration
) : TTSService {
    
    private val textToSpeech = TextToSpeech(context) { status ->
        // Initialize
    }
    
    override suspend fun synthesize(text: String, options: TTSOptions): ByteArray {
        // Use Android TTS API
    }
    
    override val availableVoices: List<String>
        get() = textToSpeech.voices.map { it.name }
}
JVM (jvmMain)
// jvmMain/kotlin/com/runanywhere/sdk/components/tts/services/JvmTTSService.kt
class JvmTTSService(
    private val configuration: TTSConfiguration
) : TTSService {
    
    // Use third-party library (MaryTTS or similar)
    override suspend fun synthesize(text: String, options: TTSOptions): ByteArray {
        // Implementation
    }
    
    override val availableVoices: List<String>
        get() = emptyList() // Platform-specific
}

3. Provider Registration

// commonMain/kotlin/com/runanywhere/sdk/core/ModuleRegistry.kt
interface TTSServiceProvider {
    suspend fun createTTSService(configuration: TTSConfiguration): TTSService
    fun canHandle(modelId: String?): Boolean
    val name: String
}

object ModuleRegistry {
    private val ttsProviders = CopyOnWriteArrayList<TTSServiceProvider>()
    
    fun registerTTS(provider: TTSServiceProvider) {
        ttsProviders.add(provider)
    }
    
    fun ttsProvider(modelId: String? = null): TTSServiceProvider? {
        return ttsProviders.firstOrNull { it.canHandle(modelId) }
    }
}

Files to Create/Modify

New Files (commonMain)

  • [ ] components/tts/TTSComponent.kt (implement full component)
  • [ ] components/tts/services/TTSService.kt (service interface)
  • [ ] components/tts/models/TTSConfiguration.kt (configuration)
  • [ ] components/tts/models/TTSOptions.kt (synthesis options)
  • [ ] components/tts/models/TTSVoice.kt (voice metadata)
  • [ ] components/tts/providers/TTSServiceProvider.kt (provider interface)

New Files (androidMain)

  • [ ] components/tts/services/AndroidTTSService.kt

New Files (jvmMain)

  • [ ] components/tts/services/JvmTTSService.kt

Files to Modify

  • [ ] core/ModuleRegistry.kt (add TTS provider registration)
  • [ ] events/ComponentEvent.kt (add TTS events if needed)

Testing Requirements

  • [ ] Unit tests for TTSComponent lifecycle
  • [ ] Integration tests with mock provider
  • [ ] Android platform tests with TextToSpeech
  • [ ] JVM platform tests
  • [ ] Voice enumeration tests
  • [ ] Error handling tests (synthesis failures)

Success Criteria

  • [ ] TTSComponent can be initialized and cleaned up properly
  • [ ] Android implementation uses native TextToSpeech API
  • [ ] JVM implementation has a working third-party solution
  • [ ] Voice pipeline (VAD → STT → LLM → TTS) works end-to-end
  • [ ] Proper error handling for missing voices/models
  • [ ] Thread-safe provider registration
  • [ ] Privacy-compliant logging (no sensitive data)

Estimated Effort

2-3 weeks (120-180 hours)

  • Component architecture: 2-3 days
  • Android implementation: 3-5 days
  • JVM implementation: 5-7 days
  • Testing and integration: 3-5 days

Dependencies

  • Depends on: #142 (thread safety fixes for ModuleRegistry)
  • Depends on: #147 (privacy-first logging)
  • Blocks: Voice Agent Component (#151)
  • Blocks: Voice Capability Service (#152)

Related Issues

  • Part of voice pipeline completion roadmap
  • Required for production voice features
  • Aligns with iOS TTS architecture

🤖 Generated with Claude Code

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗