fix(voice): add UDP keepalive to prevent Discord dropping voice after silence
Discord drops the UDP voice route after ~60s of silence - no packets arrive even when users start speaking again. Send an Opus silence frame every 15s to keep the UDP session alive.
This commit is contained in:
parent
f1b4d0b280
commit
0cc784068d
1 changed files with 18 additions and 0 deletions
|
|
@ -1002,14 +1002,32 @@ class DiscordAdapter(BasePlatformAdapter):
|
||||||
# Voice listening (Phase 2)
|
# Voice listening (Phase 2)
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
||||||
|
# UDP keepalive interval in seconds — prevents Discord from dropping
|
||||||
|
# the UDP route after ~60s of silence.
|
||||||
|
_KEEPALIVE_INTERVAL = 15
|
||||||
|
|
||||||
async def _voice_listen_loop(self, guild_id: int):
|
async def _voice_listen_loop(self, guild_id: int):
|
||||||
"""Periodically check for completed utterances and process them."""
|
"""Periodically check for completed utterances and process them."""
|
||||||
receiver = self._voice_receivers.get(guild_id)
|
receiver = self._voice_receivers.get(guild_id)
|
||||||
if not receiver:
|
if not receiver:
|
||||||
return
|
return
|
||||||
|
last_keepalive = time.monotonic()
|
||||||
try:
|
try:
|
||||||
while receiver._running:
|
while receiver._running:
|
||||||
await asyncio.sleep(0.2)
|
await asyncio.sleep(0.2)
|
||||||
|
|
||||||
|
# Send periodic UDP keepalive to prevent Discord from
|
||||||
|
# dropping the UDP session after ~60s of silence.
|
||||||
|
now = time.monotonic()
|
||||||
|
if now - last_keepalive >= self._KEEPALIVE_INTERVAL:
|
||||||
|
last_keepalive = now
|
||||||
|
try:
|
||||||
|
vc = self._voice_clients.get(guild_id)
|
||||||
|
if vc and vc.is_connected():
|
||||||
|
vc._connection.send_packet(b'\xf8\xff\xfe')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
completed = receiver.check_silence()
|
completed = receiver.check_silence()
|
||||||
for user_id, pcm_data in completed:
|
for user_id, pcm_data in completed:
|
||||||
if not self._is_allowed_user(str(user_id)):
|
if not self._is_allowed_user(str(user_id)):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue