fix: Audio queue for sequential TTS playback (no overlap/skip)
- Audio packets queued instead of stopping previous - _playNext() plays sequentially, each sentence after the previous - stopPlayback() clears queue - Fixes overlapping/skipping with XTTS sentence-by-sentence rendering Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b3d3b8b6bc
commit
e4e0e793a8
|
|
@ -55,6 +55,10 @@ class AudioService {
|
|||
private recorder: AudioRecorderPlayer;
|
||||
private recordingPath: string = '';
|
||||
|
||||
// Audio-Queue fuer sequentielle TTS-Wiedergabe
|
||||
private audioQueue: string[] = [];
|
||||
private isPlaying: boolean = false;
|
||||
|
||||
// VAD State
|
||||
private vadEnabled: boolean = false;
|
||||
private lastSpeechTime: number = 0;
|
||||
|
|
@ -198,15 +202,27 @@ class AudioService {
|
|||
|
||||
// --- Wiedergabe ---
|
||||
|
||||
/** Base64-kodiertes Audio abspielen (z.B. TTS-Antwort von ARIA) */
|
||||
/** Base64-kodiertes Audio in die Queue stellen und abspielen */
|
||||
async playAudio(base64Data: string): Promise<void> {
|
||||
if (!base64Data) return;
|
||||
|
||||
// Laufende Wiedergabe stoppen
|
||||
this.stopPlayback();
|
||||
this.audioQueue.push(base64Data);
|
||||
if (!this.isPlaying) {
|
||||
this._playNext();
|
||||
}
|
||||
}
|
||||
|
||||
/** Naechstes Audio aus der Queue abspielen */
|
||||
private async _playNext(): Promise<void> {
|
||||
if (this.audioQueue.length === 0) {
|
||||
this.isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
const base64Data = this.audioQueue.shift()!;
|
||||
|
||||
try {
|
||||
// Base64 -> temporaere WAV-Datei -> Sound abspielen
|
||||
const tmpPath = `${RNFS.CachesDirectoryPath}/aria_tts_${Date.now()}.wav`;
|
||||
await RNFS.writeFile(tmpPath, base64Data, 'base64');
|
||||
|
||||
|
|
@ -214,6 +230,7 @@ class AudioService {
|
|||
if (error) {
|
||||
console.error('[Audio] Fehler beim Laden:', error);
|
||||
RNFS.unlink(tmpPath).catch(() => {});
|
||||
this._playNext();
|
||||
return;
|
||||
}
|
||||
this.currentSound?.play((success) => {
|
||||
|
|
@ -225,15 +242,20 @@ class AudioService {
|
|||
this.currentSound?.release();
|
||||
this.currentSound = null;
|
||||
RNFS.unlink(tmpPath).catch(() => {});
|
||||
// Naechstes Audio abspielen
|
||||
this._playNext();
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[Audio] Wiedergabefehler:', err);
|
||||
this._playNext();
|
||||
}
|
||||
}
|
||||
|
||||
/** Laufende Wiedergabe stoppen */
|
||||
/** Laufende Wiedergabe stoppen + Queue leeren */
|
||||
stopPlayback(): void {
|
||||
this.audioQueue = [];
|
||||
this.isPlaying = false;
|
||||
if (this.currentSound) {
|
||||
this.currentSound.stop();
|
||||
this.currentSound.release();
|
||||
|
|
|
|||
Loading…
Reference in New Issue