From 4aea7784c98d4b80c3cf96eec4b98f066cd65355 Mon Sep 17 00:00:00 2001 From: Filipi da Silva Fuchter Date: Wed, 18 Mar 2026 16:55:59 -0400 Subject: [PATCH] Fixed the ordering of `_maybe_pause_frame_processing` call in `TTSService` (#4071) * Fixing the invocation of pause_frame_processing at the correct time when receiving LLMFullResponseEndFrame and EndFrame. --- changelog/4071.fixed.md | 1 + src/pipecat/services/tts_service.py | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 changelog/4071.fixed.md 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}]")