Bladeren bron

Fix: Audio-Ducking Unduck vor TTS + Follow-Up Client-Handler

1. Audio-Unduck sofort nach Recording-Ende (vor TTS-Abspielen):
   Vorher wurde die Lautstaerke erst bei ConversationEnd/Timeout
   wiederhergestellt — TTS war kaum hoerbar. Jetzt wird Unduck
   direkt nach RecordingComplete aufgerufen.

2. Follow-Up Client-Handler:
   _handle_follow_up_request ruft jetzt WakewordService._handle_follow_up()
   auf → Satellite wechselt in FOLLOW_UP State und nimmt Audio auf.
   Wartet auf TTS-Abspielen bevor Aufnahme startet (verhindert
   Aufnahme der eigenen TTS-Ausgabe).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
patrick 3 dagen geleden
bovenliggende
commit
a32ca666fb
2 gewijzigde bestanden met toevoegingen van 30 en 0 verwijderingen
  1. 25 0
      trixy_core/client.py
  2. 5 0
      trixy_core/wakeword/service.py

+ 25 - 0
trixy_core/client.py

@@ -861,6 +861,31 @@ class ClientApplication(IApplication):
 
         pdebug(f"Follow-Up-Request empfangen: {request.question[:50]}...")
 
+        # Warten bis TTS-Audio fertig abgespielt ist.
+        # Der FollowUpRequest kommt oft gleichzeitig mit dem Audio —
+        # wir duerfen nicht aufnehmen waehrend Trixy noch spricht,
+        # sonst nimmt das Mikrofon die eigene TTS-Ausgabe auf.
+        audio_player = getattr(self, "_audio_player", None)
+        if audio_player and hasattr(audio_player, "is_playing"):
+            import asyncio
+            wait_count = 0
+            while audio_player.is_playing and wait_count < 60:
+                await asyncio.sleep(0.5)
+                wait_count += 1
+            if wait_count > 0:
+                # Kurze Pause nach TTS damit Echo abklingt
+                await asyncio.sleep(0.3)
+
+        # WakewordService in Follow-Up Modus versetzen
+        # (startet neue Aufnahme ohne Wakeword)
+        wakeword = self.services.get_service("WakewordService")
+        if wakeword and hasattr(wakeword, "_handle_follow_up"):
+            await wakeword._handle_follow_up({
+                "session_id": request.session_id,
+                "question": request.question,
+                "follow_up": True,
+            })
+
         # Keyboard-Input für Antwort öffnen (falls aktiv)
         if self._keyboard_service:
             self._keyboard_service.handle_follow_up_request(request)

+ 5 - 0
trixy_core/wakeword/service.py

@@ -1000,6 +1000,11 @@ class WakewordService(IService):
                 except Exception as e:
                     perror(f"Fehler beim Senden: {e}")
 
+            # Audio-Ducking: Lautstaerke SOFORT wiederherstellen
+            # BEVOR die TTS-Antwort vom Server abgespielt wird.
+            # Sonst ist die TTS-Ausgabe kaum hoerbar.
+            self._unduck_audio()
+
             # Client-Modus: NICHT sofort zurück zu LISTENING!
             # Bleibe in PROCESSING und warte auf ConversationEnd vom Server.
             # Timeout als Sicherheitsnetz, falls Server nie antwortet.