mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-02 00:00:02 +00:00
Fix voice connection issues and upgrade to voice v8
This commit is contained in:
parent
20055e7cc1
commit
2175bd51c0
@ -212,6 +212,9 @@ class KeepAliveHandler(threading.Thread):
|
|||||||
|
|
||||||
|
|
||||||
class VoiceKeepAliveHandler(KeepAliveHandler):
|
class VoiceKeepAliveHandler(KeepAliveHandler):
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
ws: DiscordVoiceWebSocket
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
name: str = kwargs.pop('name', f'voice-keep-alive-handler:{id(self):#x}')
|
name: str = kwargs.pop('name', f'voice-keep-alive-handler:{id(self):#x}')
|
||||||
super().__init__(*args, name=name, **kwargs)
|
super().__init__(*args, name=name, **kwargs)
|
||||||
@ -223,7 +226,10 @@ class VoiceKeepAliveHandler(KeepAliveHandler):
|
|||||||
def get_payload(self) -> Dict[str, Any]:
|
def get_payload(self) -> Dict[str, Any]:
|
||||||
return {
|
return {
|
||||||
'op': self.ws.HEARTBEAT,
|
'op': self.ws.HEARTBEAT,
|
||||||
'd': int(time.time() * 1000),
|
'd': {
|
||||||
|
't': int(time.time() * 1000),
|
||||||
|
'seq_ack': self.ws.seq_ack,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def ack(self) -> None:
|
def ack(self) -> None:
|
||||||
@ -830,6 +836,8 @@ class DiscordVoiceWebSocket:
|
|||||||
self._keep_alive: Optional[VoiceKeepAliveHandler] = None
|
self._keep_alive: Optional[VoiceKeepAliveHandler] = None
|
||||||
self._close_code: Optional[int] = None
|
self._close_code: Optional[int] = None
|
||||||
self.secret_key: Optional[List[int]] = None
|
self.secret_key: Optional[List[int]] = None
|
||||||
|
# defaulting to -1
|
||||||
|
self.seq_ack: int = -1
|
||||||
if hook:
|
if hook:
|
||||||
self._hook = hook # type: ignore
|
self._hook = hook # type: ignore
|
||||||
|
|
||||||
@ -850,6 +858,7 @@ class DiscordVoiceWebSocket:
|
|||||||
'token': state.token,
|
'token': state.token,
|
||||||
'server_id': str(state.server_id),
|
'server_id': str(state.server_id),
|
||||||
'session_id': state.session_id,
|
'session_id': state.session_id,
|
||||||
|
'seq_ack': self.seq_ack,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
await self.send_as_json(payload)
|
await self.send_as_json(payload)
|
||||||
@ -874,14 +883,16 @@ class DiscordVoiceWebSocket:
|
|||||||
*,
|
*,
|
||||||
resume: bool = False,
|
resume: bool = False,
|
||||||
hook: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None,
|
hook: Optional[Callable[..., Coroutine[Any, Any, Any]]] = None,
|
||||||
|
seq_ack: int = -1,
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Creates a voice websocket for the :class:`VoiceClient`."""
|
"""Creates a voice websocket for the :class:`VoiceClient`."""
|
||||||
gateway = f'wss://{state.endpoint}/?v=4'
|
gateway = f'wss://{state.endpoint}/?v=8'
|
||||||
client = state.voice_client
|
client = state.voice_client
|
||||||
http = client._state.http
|
http = client._state.http
|
||||||
socket = await http.ws_connect(gateway, compress=15)
|
socket = await http.ws_connect(gateway, compress=15)
|
||||||
ws = cls(socket, loop=client.loop, hook=hook)
|
ws = cls(socket, loop=client.loop, hook=hook)
|
||||||
ws.gateway = gateway
|
ws.gateway = gateway
|
||||||
|
ws.seq_ack = seq_ack
|
||||||
ws._connection = state
|
ws._connection = state
|
||||||
ws._max_heartbeat_timeout = 60.0
|
ws._max_heartbeat_timeout = 60.0
|
||||||
ws.thread_id = threading.get_ident()
|
ws.thread_id = threading.get_ident()
|
||||||
@ -934,6 +945,7 @@ class DiscordVoiceWebSocket:
|
|||||||
_log.debug('Voice websocket frame received: %s', msg)
|
_log.debug('Voice websocket frame received: %s', msg)
|
||||||
op = msg['op']
|
op = msg['op']
|
||||||
data = msg['d'] # According to Discord this key is always given
|
data = msg['d'] # According to Discord this key is always given
|
||||||
|
self.seq_ack = msg.get('seq', self.seq_ack) # this key could not be given
|
||||||
|
|
||||||
if op == self.READY:
|
if op == self.READY:
|
||||||
await self.initial_connection(data)
|
await self.initial_connection(data)
|
||||||
|
@ -321,7 +321,7 @@ class VoiceConnectionState:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.endpoint, _, _ = endpoint.rpartition(':')
|
self.endpoint = endpoint
|
||||||
if self.endpoint.startswith('wss://'):
|
if self.endpoint.startswith('wss://'):
|
||||||
# Just in case, strip it off since we're going to add it later
|
# Just in case, strip it off since we're going to add it later
|
||||||
self.endpoint = self.endpoint[6:]
|
self.endpoint = self.endpoint[6:]
|
||||||
@ -574,7 +574,10 @@ class VoiceConnectionState:
|
|||||||
self._disconnected.clear()
|
self._disconnected.clear()
|
||||||
|
|
||||||
async def _connect_websocket(self, resume: bool) -> DiscordVoiceWebSocket:
|
async def _connect_websocket(self, resume: bool) -> DiscordVoiceWebSocket:
|
||||||
ws = await DiscordVoiceWebSocket.from_connection_state(self, resume=resume, hook=self.hook)
|
seq_ack = -1
|
||||||
|
if self.ws is not MISSING:
|
||||||
|
seq_ack = self.ws.seq_ack
|
||||||
|
ws = await DiscordVoiceWebSocket.from_connection_state(self, resume=resume, hook=self.hook, seq_ack=seq_ack)
|
||||||
self.state = ConnectionFlowState.websocket_connected
|
self.state = ConnectionFlowState.websocket_connected
|
||||||
return ws
|
return ws
|
||||||
|
|
||||||
@ -603,15 +606,17 @@ class VoiceConnectionState:
|
|||||||
# The following close codes are undocumented so I will document them here.
|
# The following close codes are undocumented so I will document them here.
|
||||||
# 1000 - normal closure (obviously)
|
# 1000 - normal closure (obviously)
|
||||||
# 4014 - we were externally disconnected (voice channel deleted, we were moved, etc)
|
# 4014 - we were externally disconnected (voice channel deleted, we were moved, etc)
|
||||||
# 4015 - voice server has crashed
|
# 4015 - voice server has crashed, we should resume
|
||||||
if exc.code in (1000, 4015):
|
# 4021 - rate limited, we should not reconnect
|
||||||
|
# 4022 - call terminated, similar to 4014
|
||||||
|
if exc.code == 1000:
|
||||||
# Don't call disconnect a second time if the websocket closed from a disconnect call
|
# Don't call disconnect a second time if the websocket closed from a disconnect call
|
||||||
if not self._expecting_disconnect:
|
if not self._expecting_disconnect:
|
||||||
_log.info('Disconnecting from voice normally, close code %d.', exc.code)
|
_log.info('Disconnecting from voice normally, close code %d.', exc.code)
|
||||||
await self.disconnect()
|
await self.disconnect()
|
||||||
break
|
break
|
||||||
|
|
||||||
if exc.code == 4014:
|
if exc.code in (4014, 4022):
|
||||||
# We were disconnected by discord
|
# We were disconnected by discord
|
||||||
# This condition is a race between the main ws event and the voice ws closing
|
# This condition is a race between the main ws event and the voice ws closing
|
||||||
if self._disconnected.is_set():
|
if self._disconnected.is_set():
|
||||||
@ -631,6 +636,31 @@ class VoiceConnectionState:
|
|||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if exc.code == 4021:
|
||||||
|
_log.warning('We are being ratelimited while trying to connect to voice. Disconnecting...')
|
||||||
|
if self.state is not ConnectionFlowState.disconnected:
|
||||||
|
await self.disconnect()
|
||||||
|
break
|
||||||
|
|
||||||
|
if exc.code == 4015:
|
||||||
|
_log.info('Disconnected from voice, attempting a resume...')
|
||||||
|
try:
|
||||||
|
await self._connect(
|
||||||
|
reconnect=reconnect,
|
||||||
|
timeout=self.timeout,
|
||||||
|
self_deaf=(self.self_voice_state or self).self_deaf,
|
||||||
|
self_mute=(self.self_voice_state or self).self_mute,
|
||||||
|
resume=True,
|
||||||
|
)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_log.info('Could not resume the voice connection... Disconnecting...')
|
||||||
|
if self.state is not ConnectionFlowState.disconnected:
|
||||||
|
await self.disconnect()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
_log.info('Successfully resumed voice connection')
|
||||||
|
continue
|
||||||
|
|
||||||
_log.debug('Not handling close code %s (%s)', exc.code, exc.reason or 'no reason')
|
_log.debug('Not handling close code %s (%s)', exc.code, exc.reason or 'no reason')
|
||||||
|
|
||||||
if not reconnect:
|
if not reconnect:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user