|
|
@@ -484,6 +484,8 @@ class Worker:
|
|
|
self.room = rtc.Room()
|
|
|
self.tasks: dict = {}
|
|
|
self.hist: list[dict] = []
|
|
|
+ self._exit_task = None
|
|
|
+ self._shutdown_event = asyncio.Event()
|
|
|
|
|
|
async def run(self):
|
|
|
# Pre-load Silero VAD at startup (not lazy)
|
|
|
@@ -499,7 +501,7 @@ class Worker:
|
|
|
|
|
|
self.room.on("track_subscribed", self._on_track)
|
|
|
self.room.on("participant_disconnected", self._on_off)
|
|
|
- self.room.on("participant_connected", lambda p: None)
|
|
|
+ self.room.on("participant_connected", self._on_on)
|
|
|
self.room.on("track_published", lambda pub, p: None)
|
|
|
await self.room.connect(LIVEKIT_URL, _token(self.rn, self.id))
|
|
|
logger.info("Worker ready (VAD+ASR+LLM+TTS)")
|
|
|
@@ -509,7 +511,7 @@ class Worker:
|
|
|
if pub.track and pub.kind == rtc.TrackKind.KIND_AUDIO:
|
|
|
self._on_track(pub.track, pub, p)
|
|
|
try:
|
|
|
- await asyncio.Future()
|
|
|
+ await self._shutdown_event.wait()
|
|
|
finally:
|
|
|
await self.room.disconnect()
|
|
|
|
|
|
@@ -524,10 +526,27 @@ class Worker:
|
|
|
x = self.tasks.pop(p.sid, None)
|
|
|
if x:
|
|
|
x.cancel()
|
|
|
- # Auto-exit when last participant leaves
|
|
|
+ # Auto-exit when room stays empty for a grace period, to allow App resume.
|
|
|
if not self.room.remote_participants:
|
|
|
- logger.info("Room empty, exiting")
|
|
|
- asyncio.create_task(self.room.disconnect())
|
|
|
+ if self._exit_task is None or self._exit_task.done():
|
|
|
+ logger.info("Room empty, scheduling exit")
|
|
|
+ self._exit_task = asyncio.create_task(self._delayed_exit())
|
|
|
+ else:
|
|
|
+ if self._exit_task and not self._exit_task.done():
|
|
|
+ self._exit_task.cancel()
|
|
|
+ self._exit_task = None
|
|
|
+
|
|
|
+ def _on_on(self, p):
|
|
|
+ if self._exit_task and not self._exit_task.done():
|
|
|
+ logger.info("Participant rejoined, canceling exit")
|
|
|
+ self._exit_task.cancel()
|
|
|
+ self._exit_task = None
|
|
|
+
|
|
|
+ async def _delayed_exit(self, delay_s: float = 60.0):
|
|
|
+ await asyncio.sleep(delay_s)
|
|
|
+ if not self.room.remote_participants:
|
|
|
+ logger.info("Room still empty, exiting")
|
|
|
+ self._shutdown_event.set()
|
|
|
|
|
|
async def _run(self, sid, track):
|
|
|
logger.info("_run %s", sid)
|