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
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗