Skip to content

Commit 2ae01b7

Browse files
DA-344pre-commit-ci[bot]Lulalaby
authored
fix: 4006 voice crashes and upgrade to voice v8 (#2812)
Signed-off-by: Lala Sabathil <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Lala Sabathil <[email protected]>
1 parent a5aa21f commit 2ae01b7

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ These changes are available on the `master` branch, but have not yet been releas
119119
([#2781](https://github.com/Pycord-Development/pycord/pull/2781))
120120
- Fixed `VoiceClient` crashing randomly while receiving audio
121121
([#2800](https://github.com/Pycord-Development/pycord/pull/2800))
122+
- Fixed `VoiceClient.connect` failing to do initial connection.
123+
([#2812](https://github.com/Pycord-Development/pycord/pull/2812))
122124

123125
### Changed
124126

@@ -138,6 +140,8 @@ These changes are available on the `master` branch, but have not yet been releas
138140
([#2564](https://github.com/Pycord-Development/pycord/pull/2564))
139141
- Changed the default value of `ApplicationCommand.nsfw` to `False`.
140142
([#2797](https://github.com/Pycord-Development/pycord/pull/2797))
143+
- Upgraded voice websocket version to v8.
144+
([#2812](https://github.com/Pycord-Development/pycord/pull/2812))
141145

142146
### Deprecated
143147

discord/gateway.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import traceback
3636
import zlib
3737
from collections import deque, namedtuple
38+
from typing import TYPE_CHECKING
3839

3940
import aiohttp
4041

@@ -208,6 +209,9 @@ def ack(self):
208209

209210

210211
class VoiceKeepAliveHandler(KeepAliveHandler):
212+
if TYPE_CHECKING:
213+
ws: DiscordVoiceWebSocket
214+
211215
def __init__(self, *args, **kwargs):
212216
super().__init__(*args, **kwargs)
213217
self.recent_ack_latencies = deque(maxlen=20)
@@ -216,7 +220,10 @@ def __init__(self, *args, **kwargs):
216220
self.behind_msg = "High socket latency, shard ID %s heartbeat is %.1fs behind"
217221

218222
def get_payload(self):
219-
return {"op": self.ws.HEARTBEAT, "d": int(time.time() * 1000)}
223+
return {
224+
"op": self.ws.HEARTBEAT,
225+
"d": {"t": int(time.time() * 1000), "seq_ack": self.ws.seq_ack},
226+
}
220227

221228
def ack(self):
222229
ack_time = time.perf_counter()
@@ -784,6 +791,7 @@ def __init__(self, socket, loop, *, hook=None):
784791
self._close_code = None
785792
self.secret_key = None
786793
self.ssrc_map = {}
794+
self.seq_ack: int = -1
787795
if hook:
788796
self._hook = hook
789797

@@ -804,6 +812,9 @@ async def resume(self):
804812
"token": state.token,
805813
"server_id": str(state.server_id),
806814
"session_id": state.session_id,
815+
# this seq_ack will allow for us to do buffered resume, which is, receive the
816+
# lost voice packets while trying to resume the reconnection
817+
"seq_ack": self.seq_ack,
807818
},
808819
}
809820
await self.send_as_json(payload)
@@ -824,7 +835,7 @@ async def identify(self):
824835
@classmethod
825836
async def from_client(cls, client, *, resume=False, hook=None):
826837
"""Creates a voice websocket for the :class:`VoiceClient`."""
827-
gateway = f"wss://{client.endpoint}/?v=4"
838+
gateway = f"wss://{client.endpoint}/?v=8"
828839
http = client._state.http
829840
socket = await http.ws_connect(gateway, compress=15)
830841
ws = cls(socket, loop=client.loop, hook=hook)
@@ -860,14 +871,21 @@ async def client_connect(self):
860871
await self.send_as_json(payload)
861872

862873
async def speak(self, state=SpeakingState.voice):
863-
payload = {"op": self.SPEAKING, "d": {"speaking": int(state), "delay": 0}}
874+
payload = {
875+
"op": self.SPEAKING,
876+
"d": {
877+
"speaking": int(state),
878+
"delay": 0,
879+
},
880+
}
864881

865882
await self.send_as_json(payload)
866883

867884
async def received_message(self, msg):
868885
_log.debug("Voice websocket frame received: %s", msg)
869886
op = msg["op"]
870887
data = msg.get("d")
888+
self.seq_ack = data.get("seq", self.seq_ack)
871889

872890
if op == self.READY:
873891
await self.initial_connection(data)

discord/voice_client.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,7 @@ async def on_voice_server_update(self, data: VoiceServerUpdatePayload) -> None:
325325
)
326326
return
327327

328-
self.endpoint, _, _ = endpoint.rpartition(":")
329-
if self.endpoint.startswith("wss://"):
330-
# Just in case, strip it off since we're going to add it later
331-
self.endpoint = self.endpoint[6:]
332-
328+
self.endpoint = endpoint.removeprefix("wss://")
333329
# This gets set later
334330
self.endpoint_ip = MISSING
335331

@@ -471,8 +467,8 @@ async def poll_voice_ws(self, reconnect: bool) -> None:
471467
# The following close codes are undocumented, so I will document them here.
472468
# 1000 - normal closure (obviously)
473469
# 4014 - voice channel has been deleted.
474-
# 4015 - voice server has crashed
475-
if exc.code in (1000, 4015):
470+
# 4015 - voice server has crashed, we should resume
471+
if exc.code == 1000:
476472
_log.info(
477473
"Disconnecting from voice normally, close code %d.",
478474
exc.code,
@@ -494,6 +490,21 @@ async def poll_voice_ws(self, reconnect: bool) -> None:
494490
)
495491
await self.disconnect()
496492
break
493+
if exc.code == 4015:
494+
_log.info("Disconnected from voice, trying to resume...")
495+
496+
try:
497+
await self.ws.resume()
498+
except asyncio.TimeoutError:
499+
_log.info(
500+
"Could not resume the voice connection... Disconnection..."
501+
)
502+
if self._connected.is_set():
503+
await self.disconnect(force=True)
504+
else:
505+
_log.info("Successfully resumed voice connection")
506+
continue
507+
497508
if not reconnect:
498509
await self.disconnect()
499510
raise

0 commit comments

Comments
 (0)