fix: TTS read-aloud downloads audio via OkHttp before playing

MediaPlayer.setDataSource(url) with HTTPS URLs can silently fail due to
certificate issues, redirect handling, or listener race conditions (listeners
were set after prepareAsync). Fix: download the WAV file via OkHttp (same
client as all other network calls) to a temp file, set listeners before
prepareAsync, play from local path. Temp file cleaned up on completion/error.
This commit is contained in:
Bruno Deanoz 2026-06-24 01:33:23 +02:00
parent 287cdb4c6b
commit bb53b24655

View file

@ -370,28 +370,44 @@ fun ChatScreen(
} }
fun playTtsUrl(url: String, messageId: Long) { fun playTtsUrl(url: String, messageId: Long) {
scope.launch {
try { try {
val tmpFile = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) {
val req = okhttp3.Request.Builder().url(url).build()
KaizenApi.imageClient.newCall(req).execute().use { resp ->
if (!resp.isSuccessful) return@withContext null
val bytes = resp.body!!.bytes()
java.io.File.createTempFile("tts_", ".wav", context.cacheDir).also { it.writeBytes(bytes) }
}
}
if (tmpFile == null) {
playingTtsForId = null
return@launch
}
val player = MediaPlayer().apply { val player = MediaPlayer().apply {
setDataSource(url)
prepareAsync()
setOnPreparedListener { start() } setOnPreparedListener { start() }
setOnCompletionListener { setOnCompletionListener {
release() release()
ttsPlayerRef.value = null ttsPlayerRef.value = null
playingTtsForId = null playingTtsForId = null
tmpFile.delete()
} }
setOnErrorListener { _, _, _ -> setOnErrorListener { _, _, _ ->
release() release()
ttsPlayerRef.value = null ttsPlayerRef.value = null
playingTtsForId = null playingTtsForId = null
tmpFile.delete()
true true
} }
setDataSource(tmpFile.absolutePath)
prepareAsync()
} }
ttsPlayerRef.value = player ttsPlayerRef.value = player
} catch (_: Exception) { } catch (_: Exception) {
playingTtsForId = null playingTtsForId = null
} }
} }
}
fun readAloud(content: String, messageId: Long, wireId: String) { fun readAloud(content: String, messageId: Long, wireId: String) {
val cfg = session.config ?: return val cfg = session.config ?: return