feat: Pre-Roll-Buffer kann jetzt auf 0 (sofort abspielen)

F5-TTS ist schnell genug dass der Puffer bei kurzen Saetzen eher
schadet als nuetzt — er verzoegert den play()-Start fuer Sekunden die
dann als Wartezeit auffallen.

Aenderungen:
- audio.ts: TTS_PREROLL_MIN_SEC 1.0 → 0 (Einstellbar in Settings)
- PcmStreamPlayerModule.kt: MIN_PREROLL_SECONDS auf 0.0, Fallback-
  Logic respektiert jetzt 0 als gueltigen Wert (vorher hat der
  .let { if (it > 0) it else DEFAULT } 0 zu 3.5s umgebogen).

Bei preroll=0 greift der Leading-Silence von 200ms immer noch, d.h.
AudioTrack-Startup bleibt sauber. play() wird dann beim allerersten
echten PCM-Chunk aufgerufen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
duffyduck 2026-04-25 01:02:48 +02:00
parent feac7f2479
commit 7919489543
2 changed files with 11 additions and 5 deletions

View File

@ -32,7 +32,10 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
private const val TAG = "PcmStreamPlayer" private const val TAG = "PcmStreamPlayer"
// Fallback wenn JS keinen Wert uebergibt. // Fallback wenn JS keinen Wert uebergibt.
private const val DEFAULT_PREROLL_SECONDS = 3.5 private const val DEFAULT_PREROLL_SECONDS = 3.5
private const val MIN_PREROLL_SECONDS = 0.5 // 0.0 = sofortige Wiedergabe — play() direkt beim ersten Chunk.
// Macht Sinn fuer F5-TTS weil Render so schnell ist dass ein Puffer
// unnoetig ist und bei kurzen Saetzen sogar stoeren kann.
private const val MIN_PREROLL_SECONDS = 0.0
private const val MAX_PREROLL_SECONDS = 10.0 private const val MAX_PREROLL_SECONDS = 10.0
// Stille am Stream-Anfang, damit AudioTrack sauber anfaehrt und die // Stille am Stream-Anfang, damit AudioTrack sauber anfaehrt und die
// ersten Samples nicht abgeschnitten werden (XTTS-Warmup + play()-Latenz). // ersten Samples nicht abgeschnitten werden (XTTS-Warmup + play()-Latenz).
@ -59,9 +62,12 @@ class PcmStreamPlayerModule(reactContext: ReactApplicationContext) : ReactContex
// Alte Session beenden falls vorhanden // Alte Session beenden falls vorhanden
stopInternal() stopInternal()
val prerollSec = prerollSeconds // Nur NaN/Inf → Default. 0.0 ist gueltig (= sofortige Wiedergabe).
.coerceIn(MIN_PREROLL_SECONDS, MAX_PREROLL_SECONDS) val prerollSec = if (prerollSeconds.isFinite() && prerollSeconds >= 0.0) {
.let { if (it.isFinite() && it > 0) it else DEFAULT_PREROLL_SECONDS } prerollSeconds.coerceIn(MIN_PREROLL_SECONDS, MAX_PREROLL_SECONDS)
} else {
DEFAULT_PREROLL_SECONDS
}
val channelConfig = if (channels == 2) AudioFormat.CHANNEL_OUT_STEREO else AudioFormat.CHANNEL_OUT_MONO val channelConfig = if (channels == 2) AudioFormat.CHANNEL_OUT_STEREO else AudioFormat.CHANNEL_OUT_MONO
val encoding = AudioFormat.ENCODING_PCM_16BIT val encoding = AudioFormat.ENCODING_PCM_16BIT

View File

@ -143,7 +143,7 @@ const MAX_RECORDING_MS = 120000;
// Pre-Roll: Wie lange Audio im AudioTrack-Buffer liegt bevor play() startet. // Pre-Roll: Wie lange Audio im AudioTrack-Buffer liegt bevor play() startet.
// Einstellbar via Diagnostic/Settings (Key: aria_tts_preroll_sec). // Einstellbar via Diagnostic/Settings (Key: aria_tts_preroll_sec).
export const TTS_PREROLL_DEFAULT_SEC = 3.5; export const TTS_PREROLL_DEFAULT_SEC = 3.5;
export const TTS_PREROLL_MIN_SEC = 1.0; export const TTS_PREROLL_MIN_SEC = 0; // 0 = sofort abspielen (F5-TTS ist schnell genug)
export const TTS_PREROLL_MAX_SEC = 6.0; export const TTS_PREROLL_MAX_SEC = 6.0;
export const TTS_PREROLL_STORAGE_KEY = 'aria_tts_preroll_sec'; export const TTS_PREROLL_STORAGE_KEY = 'aria_tts_preroll_sec';