Files
2026-08-07 18:15:36 -04:00

44 lines
1.5 KiB
Python

"""Stop the agent from hearing itself.
On laptop speakers with no acoustic echo cancellation, the microphone picks up
whatever Kokoro just said. The recognizer transcribes it, the aggregator treats
it as a user turn, and the agent answers its own greeting — which is exactly
what happens without this.
Pipecat's ``AlwaysUserMuteStrategy`` mutes while the bot is speaking, but
unmutes the instant playback ends, and the tail of that audio is still in the
input buffer. This keeps the mute up for a short while afterwards.
"""
import time
from pipecat.frames.frames import BotStartedSpeakingFrame, BotStoppedSpeakingFrame, Frame
from pipecat.turns.user_mute.base_user_mute_strategy import BaseUserMuteStrategy
class EchoGuardUserMuteStrategy(BaseUserMuteStrategy):
"""Mute the user while the bot speaks, plus a tail to let echo drain.
Args:
tail_secs: How long to stay muted after playback ends.
"""
def __init__(self, *, tail_secs: float = 0.4):
super().__init__()
self._tail_secs = tail_secs
self._bot_speaking = False
self._stopped_at = 0.0
async def process_frame(self, frame: Frame) -> bool:
await super().process_frame(frame)
if isinstance(frame, BotStartedSpeakingFrame):
self._bot_speaking = True
elif isinstance(frame, BotStoppedSpeakingFrame):
self._bot_speaking = False
self._stopped_at = time.monotonic()
if self._bot_speaking:
return True
return time.monotonic() - self._stopped_at < self._tail_secs