fix(audio): kurze TTS-Texte spielen wieder ab — AudioTrack-Buffer entkoppelt von Preroll
OnePlus A12 stallte bei kurzem Text mit pos=0/34112: 336KB Buffer fuer 3.5s Preroll, aber nur 68KB Daten drin → AudioTrack faehrt nicht an. Fix: Buffer fest auf ~2s, plus play()-Retry bei pos=0 nach 500ms. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,9 +78,12 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
val encoding = AudioFormat.ENCODING_PCM_16BIT
|
val encoding = AudioFormat.ENCODING_PCM_16BIT
|
||||||
val minBuf = AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding)
|
val minBuf = AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding)
|
||||||
val bytesPerSecond = sampleRate * channels * 2 // 16-bit = 2 bytes
|
val bytesPerSecond = sampleRate * channels * 2 // 16-bit = 2 bytes
|
||||||
// Buffer muss mindestens PREROLL + etwas Spielraum fassen.
|
|
||||||
val prerollTarget = (bytesPerSecond * prerollSec).toInt()
|
val prerollTarget = (bytesPerSecond * prerollSec).toInt()
|
||||||
val bufferSize = (minBuf * 32).coerceAtLeast(prerollTarget * 2)
|
// Buffer entkoppelt von Preroll — fester ~2s-Buffer reicht. Wenn er
|
||||||
|
// an Preroll gekoppelt ist (z.B. 7s bei preroll=3.5s) und nur kurz
|
||||||
|
// gefuettert wird, stallt AudioTrack auf manchen Geraeten (OnePlus
|
||||||
|
// Android 12: pos bleibt 0 obwohl play() lief).
|
||||||
|
val bufferSize = (bytesPerSecond * 2).coerceAtLeast(minBuf * 8)
|
||||||
prerollBytes = prerollTarget
|
prerollBytes = prerollTarget
|
||||||
bytesBuffered = 0
|
bytesBuffered = 0
|
||||||
playbackStarted = false
|
playbackStarted = false
|
||||||
@@ -237,12 +240,21 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
|
|||||||
val totalFrames = (bytesBuffered / streamBytesPerFrame).toInt()
|
val totalFrames = (bytesBuffered / streamBytesPerFrame).toInt()
|
||||||
var lastPos = -1
|
var lastPos = -1
|
||||||
var stalledCount = 0
|
var stalledCount = 0
|
||||||
|
var retried = false
|
||||||
while (!writerShouldStop) {
|
while (!writerShouldStop) {
|
||||||
val pos = t.playbackHeadPosition
|
val pos = t.playbackHeadPosition
|
||||||
if (pos >= totalFrames) break
|
if (pos >= totalFrames) break
|
||||||
// Safety: wenn Position 2s nicht mehr vorwaerts → AudioTrack hing
|
|
||||||
if (pos == lastPos) {
|
if (pos == lastPos) {
|
||||||
stalledCount++
|
stalledCount++
|
||||||
|
// Nach 500ms Stillstand: AudioTrack-Quirk auf manchen
|
||||||
|
// Geraeten (OnePlus A12) — play() nochmal anstossen.
|
||||||
|
if (stalledCount == 10 && pos == 0 && !retried) {
|
||||||
|
retried = true
|
||||||
|
Log.w(TAG, "playback nicht angefahren — retry play()")
|
||||||
|
try { t.play() } catch (e: Exception) {
|
||||||
|
Log.w(TAG, "retry play() failed: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
if (stalledCount > 40) {
|
if (stalledCount > 40) {
|
||||||
Log.w(TAG, "playback stalled at $pos/$totalFrames — give up")
|
Log.w(TAG, "playback stalled at $pos/$totalFrames — give up")
|
||||||
break
|
break
|
||||||
|
|||||||
Reference in New Issue
Block a user