diff --git a/changelog/4071.fixed.md b/changelog/4071.fixed.md new file mode 100644 index 000000000..0938127c3 --- /dev/null +++ b/changelog/4071.fixed.md @@ -0,0 +1 @@ +- Fixed audio overlap and potential dropped TTS content when multiple assistant turns occur in quick succession. `TTSService` now flushes remaining text before pausing frame processing on `LLMFullResponseEndFrame`/`EndFrame`, instead of pausing first. diff --git a/src/pipecat/services/tts_service.py b/src/pipecat/services/tts_service.py index 7583339c8..f93c13d79 100644 --- a/src/pipecat/services/tts_service.py +++ b/src/pipecat/services/tts_service.py @@ -720,11 +720,6 @@ class TTSService(AIService): self._turn_context_id = self.create_context_id() await self.push_frame(frame, direction) elif isinstance(frame, (LLMFullResponseEndFrame, EndFrame)): - # We pause processing incoming frames if the LLM response included - # text (it might be that it's only a function calling response). We - # pause to avoid audio overlapping. - await self._maybe_pause_frame_processing() - # Flush any remaining text (including text waiting for lookahead) remaining = await self._text_aggregator.flush() # Stop the aggregation metric (no-op if already stopped on first sentence). @@ -732,6 +727,11 @@ class TTSService(AIService): if remaining: await self._push_tts_frames(AggregatedTextFrame(remaining.text, remaining.type)) + # We pause processing incoming frames if the LLM response included + # text (it might be that it's only a function calling response). We + # pause to avoid audio overlapping. + await self._maybe_pause_frame_processing() + # Log accumulated streamed text and emit aggregated usage metric. if self._streamed_text: logger.debug(f"{self}: Generating TTS [{self._streamed_text}]")