Skip to content

Commit 9c29dba

Browse files
committed
added 500ms delay for initial audio play
1 parent eda19c1 commit 9c29dba

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

app/agents/voice/automatic/audio/audio_manager.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ def __init__(self, tts_service, transport=None):
2525
self.audio_chunks = [] # 100ms audio chunks for fast interruption
2626
self.user_has_input = False # Ensure audio only starts after user input
2727

28+
# SMART DELAY STATE - 500ms grace period before audio starts
29+
self.delay_task: Optional[asyncio.Task] = None
30+
self.is_in_delay_period = False
31+
self.delay_duration_ms = 500 # Wait 500ms before starting audio
32+
2833
# FUNCTION CALL SET STATE - Track function call set audio
2934
self.is_function_call_set_active = False # Track if we're in a function call set
3035
self.function_call_set_audio_playing = False # Track if function call set audio is playing
@@ -69,8 +74,8 @@ def set_user_input(self):
6974
self.user_has_input = True
7075
logger.info("User input detected - audio enabled")
7176

72-
async def start_audio(self):
73-
"""Start seamless chunked audio playback (only if user has provided input)."""
77+
async def start_audio_with_delay(self):
78+
"""Start audio with 500ms grace period for fast responses."""
7479

7580
# Check prerequisites
7681
if not self.user_has_input:
@@ -79,6 +84,42 @@ async def start_audio(self):
7984
if not self.audio_chunks:
8085
return
8186

87+
if self.is_playing or self.is_in_delay_period:
88+
return
89+
90+
# Start delay period
91+
self.is_in_delay_period = True
92+
logger.info(f"Starting {self.delay_duration_ms}ms grace period before audio")
93+
94+
# Cancel any existing delay task
95+
if self.delay_task and not self.delay_task.done():
96+
self.delay_task.cancel()
97+
98+
# Start delay task
99+
self.delay_task = asyncio.create_task(self._delay_then_start_audio())
100+
101+
async def start_audio(self):
102+
"""Legacy method - now uses smart delay."""
103+
await self.start_audio_with_delay()
104+
105+
async def _delay_then_start_audio(self):
106+
"""Wait for delay period, then start audio if not cancelled."""
107+
try:
108+
# Wait for the grace period
109+
await asyncio.sleep(self.delay_duration_ms / 1000)
110+
111+
# If we reach here, no response came within grace period
112+
if self.is_in_delay_period and self.user_has_input:
113+
logger.info(f"Grace period ended - starting audio")
114+
await self._start_audio_immediately()
115+
116+
except asyncio.CancelledError:
117+
logger.info("Grace period cancelled - fast response received")
118+
finally:
119+
self.is_in_delay_period = False
120+
121+
async def _start_audio_immediately(self):
122+
"""Start audio immediately without delay."""
82123
if self.is_playing:
83124
return
84125

@@ -92,14 +133,23 @@ async def start_audio(self):
92133

93134
# Start seamless audio streaming
94135
self.loop_task = asyncio.create_task(self._stream_seamless_audio())
95-
# logger.info("Started audio playback")
136+
logger.info("Started audio playback")
96137

97138
async def stop_and_disable_audio(self):
98139
"""Stop audio immediately and disable until next user input."""
99140
# Set stop flags
100141
self.is_playing = False
101142
self.user_has_input = False # Require new user input for next audio
102143
self.loop_count = 0
144+
self.is_in_delay_period = False
145+
146+
# Cancel delay task if active
147+
if self.delay_task and not self.delay_task.done():
148+
self.delay_task.cancel()
149+
try:
150+
await self.delay_task
151+
except asyncio.CancelledError:
152+
pass
103153

104154
# Cancel audio task
105155
if self.loop_task and not self.loop_task.done():

app/agents/voice/automatic/processors/llm_spy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@
4545
def _stop_audio_immediately(context: str = "unknown") -> bool:
4646
"""INSTANT audio stopping using simplified AudioManager API."""
4747
audio_manager = get_audio_manager()
48-
if audio_manager and (audio_manager.user_has_input or audio_manager.is_playing):
48+
if audio_manager and (audio_manager.user_has_input or audio_manager.is_playing or audio_manager.is_in_delay_period):
4949
# Stop function call set audio if active
5050
if audio_manager.function_call_set_audio_playing:
5151
asyncio.create_task(audio_manager.stop_function_call_set_audio())
5252
logger.info(f"INSTANT STOP: Function call set audio stopped due to {context}")
5353

54-
# Use the simplified stop method for regular audio
54+
# Use the simplified stop method for regular audio and grace period
5555
asyncio.create_task(audio_manager.stop_and_disable_audio())
5656

5757
logger.info(f"INSTANT AUDIO STOP: {context}")

0 commit comments

Comments
 (0)