From 962d8143181ed55a2290c0e488842e3e5bfbf306 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 10 May 2026 14:25:43 +0200 Subject: [PATCH] =?UTF-8?q?fix(audio):=20kurze=20TTS=20=E2=80=94=20Padding?= =?UTF-8?q?=20auf=203s=20erhoeht=20(OnePlus=20A12=20Hard-Threshold)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test mit 96000B (2s) Padding zeigte: AudioTrack stallt immer noch mit pos=0/48000. Ab 8 Worten (~2.5s) geht's — der Hard-Threshold liegt also zwischen 2s und 3s. Padding auf 3s, Buffer auf 4s. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../com/ariacockpit/PcmStreamPlayerModule.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt b/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt index 8a42744..c448f17 100644 --- a/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt +++ b/android/android/app/src/main/java/com/ariacockpit/PcmStreamPlayerModule.kt @@ -79,13 +79,11 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex val minBuf = AudioTrack.getMinBufferSize(sampleRate, channelConfig, encoding) val bytesPerSecond = sampleRate * channels * 2 // 16-bit = 2 bytes val prerollTarget = (bytesPerSecond * prerollSec).toInt() - // Buffer entkoppelt von Preroll — fester ~3s-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). - // 3s damit Padding bis 2s vor play() noch Headroom hat (write() ist - // blocking — wenn Buffer voll ist, deadlockt es vor play()). - val bufferSize = (bytesPerSecond * 3).coerceAtLeast(minBuf * 8) + // Buffer entkoppelt von Preroll — fester ~4s-Buffer. OnePlus A12 + // mit USAGE_ASSISTANT laeuft AudioTrack erst ab ~3s gepufferter + // Daten an. Wir padden Kurztexte vor play() auf 3s (siehe Block + // nach mainLoop), Buffer braucht ~1s Headroom weil write() blockt. + val bufferSize = (bytesPerSecond * 4).coerceAtLeast(minBuf * 8) prerollBytes = prerollTarget bytesBuffered = 0 playbackStarted = false @@ -229,10 +227,11 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex bytesBuffered += silence.size } // Bei kurzem Text (play() noch nicht gestartet): Buffer auf min. - // 2s padden + DANN play(). Auf OnePlus A12 startet AudioTrack - // bei einem zu duennen Buffer nicht — pos bleibt auf 0 stehen. + // 3s padden + DANN play(). Auf OnePlus A12 startet AudioTrack + // bei < 3s Buffer-Inhalt nicht — pos bleibt auf 0 stehen. + // (2s war zu wenig, 8 Worte ~2.5s gingen, 3 Worte ~1s nicht.) if (!playbackStarted && !writerShouldStop) { - val minStartBytes = bytesPerSecond * 2 + val minStartBytes = bytesPerSecond * 3 if (bytesBuffered < minStartBytes) { val padBytes = (minStartBytes - bytesBuffered.toInt()) and 0x7FFFFFFE val pad = ByteArray(padBytes)