diff --git a/changelog/3490.added.md b/changelog/3490.added.md new file mode 100644 index 000000000..905d35b34 --- /dev/null +++ b/changelog/3490.added.md @@ -0,0 +1 @@ +- Added `on_user_mute_started` and `on_user_mute_stopped` event handlers to `LLMUserAggregator` for tracking user mute state changes. diff --git a/examples/foundational/24-user-mute-strategy.py b/examples/foundational/24-user-mute-strategy.py index 00e1ff66a..0797fc092 100644 --- a/examples/foundational/24-user-mute-strategy.py +++ b/examples/foundational/24-user-mute-strategy.py @@ -161,6 +161,14 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments): logger.info(f"Client disconnected") await task.cancel() + @user_aggregator.event_handler("on_user_mute_started") + async def on_user_mute_started(aggregator): + logger.info(f"User mute started") + + @user_aggregator.event_handler("on_user_mute_stopped") + async def on_user_mute_stopped(aggregator): + logger.info(f"User mute stopped") + runner = PipelineRunner(handle_sigint=runner_args.handle_sigint) await runner.run(task) diff --git a/src/pipecat/processors/aggregators/llm_response_universal.py b/src/pipecat/processors/aggregators/llm_response_universal.py index fc0baf843..81dbfe844 100644 --- a/src/pipecat/processors/aggregators/llm_response_universal.py +++ b/src/pipecat/processors/aggregators/llm_response_universal.py @@ -298,6 +298,8 @@ class LLMUserAggregator(LLMContextAggregator): - on_user_turn_stopped: Called when the user turn ends - on_user_turn_stop_timeout: Called when no user turn stop strategy triggers - on_user_turn_idle: Called when the user has been idle for the configured timeout + - on_user_mute_started: Called when the user becomes muted + - on_user_mute_stopped: Called when the user becomes unmuted Example:: @@ -317,6 +319,14 @@ class LLMUserAggregator(LLMContextAggregator): async def on_user_turn_idle(aggregator): ... + @aggregator.event_handler("on_user_mute_started") + async def on_user_mute_started(aggregator): + ... + + @aggregator.event_handler("on_user_mute_stopped") + async def on_user_mute_stopped(aggregator): + ... + """ def __init__( @@ -340,6 +350,8 @@ class LLMUserAggregator(LLMContextAggregator): self._register_event_handler("on_user_turn_stopped") self._register_event_handler("on_user_turn_stop_timeout") self._register_event_handler("on_user_turn_idle") + self._register_event_handler("on_user_mute_started") + self._register_event_handler("on_user_mute_stopped") user_turn_strategies = self._params.user_turn_strategies or UserTurnStrategies() @@ -492,6 +504,12 @@ class LLMUserAggregator(LLMContextAggregator): logger.debug(f"{self}: user is now {'muted' if should_mute_next_time else 'unmuted'}") self._user_is_muted = should_mute_next_time + # Emit mute state change events + if self._user_is_muted: + await self._call_event_handler("on_user_mute_started") + else: + await self._call_event_handler("on_user_mute_stopped") + return should_mute_frame async def _handle_llm_run(self, frame: LLMRunFrame):