Skip to content

Commit 348f698

Browse files
committed
Fix voice IP discovery
Apparently this changed at some point without much notice. The old way was deprecated in 2019 and stopped working March 15th 2023.
1 parent 43fdd89 commit 348f698

4 files changed

Lines changed: 26 additions & 17 deletions

File tree

src/Discore/Voice/DiscordVoiceConnection.Sockets.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ partial class DiscordVoiceConnection
1818
int? heartbeatInterval;
1919
IPAddress? udpIP;
2020
int? udpPort;
21-
int? ssrc;
21+
uint? ssrc;
2222
string[]? encryptionModes;
2323
Task? heartbeatLoopTask;
2424
VoiceUdpSocket? udpSocket;
@@ -705,6 +705,8 @@ async Task StartIPDiscovery(CancellationToken ct)
705705
if (udpSocket == null)
706706
throw new InvalidOperationException("[StartIPDiscovery] udpSocket must not be null!");
707707

708+
log.LogVerbose("[StartIPDiscovery] Discovering our IP...");
709+
708710
try
709711
{
710712
await udpSocket.StartIPDiscoveryAsync().ConfigureAwait(false);
@@ -724,7 +726,7 @@ async Task ReceiveIPDiscovery(CancellationToken ct)
724726

725727
IPDiscoveryEventArgs ipData = await udpSocket.IPDiscoveryQueue.TakeAsync(ct).ConfigureAwait(false);
726728

727-
log.LogVerbose($"[ReceiveIPDiscovery] Discovered end-point: {ipData.IP}:{ipData.Port}");
729+
log.LogVerbose($"[ReceiveIPDiscovery] Discovered our endpoint: {ipData.IP}:{ipData.Port}");
728730

729731
discoveredIP = ipData.IP;
730732
discoveredPort = ipData.Port;

src/Discore/Voice/Internal/VoiceReadyEventArgs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ class VoiceReadyEventArgs : EventArgs
77
{
88
public IPAddress IP { get; }
99
public int Port { get; }
10-
public int Ssrc { get; }
10+
public uint Ssrc { get; }
1111
public string[] EncryptionModes { get; }
1212

13-
public VoiceReadyEventArgs(IPAddress ip, int port, int ssrc, string[] encryptionModes)
13+
public VoiceReadyEventArgs(IPAddress ip, int port, uint ssrc, string[] encryptionModes)
1414
{
1515
IP = ip;
1616
Port = port;

src/Discore/Voice/Internal/VoiceUDPSocket.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Nito.AsyncEx;
22
using System;
3+
using System.Buffers.Binary;
34
using System.Net;
45
using System.Net.Sockets;
56
using System.Text;
@@ -27,7 +28,7 @@ class VoiceUdpSocket : IDisposable
2728
public AsyncCollection<IPDiscoveryEventArgs> IPDiscoveryQueue { get; } =
2829
new AsyncCollection<IPDiscoveryEventArgs>();
2930

30-
public int Ssrc { get; }
31+
public uint Ssrc { get; }
3132

3233
public bool IsPaused { get; set; }
3334

@@ -46,7 +47,7 @@ class VoiceUdpSocket : IDisposable
4647
readonly CircularBuffer sendBuffer;
4748
readonly DiscoreLogger log;
4849

49-
public VoiceUdpSocket(string loggingName, int ssrc)
50+
public VoiceUdpSocket(string loggingName, uint ssrc)
5051
{
5152
log = new DiscoreLogger(loggingName);
5253

@@ -155,11 +156,13 @@ async Task HandleIPDiscoveryPacket(byte[] data)
155156
{
156157
discoveringIP = false;
157158

159+
// Discovery response packet is the same as the request but followed by the IP and port
160+
158161
// Read IP as null-terminated string
159-
string ip = Encoding.UTF8.GetString(data, 4, 70 - 6).TrimEnd('\0');
162+
string ip = Encoding.UTF8.GetString(data, index: 8, count: 64).TrimEnd('\0');
160163

161164
// Read port
162-
int port = (ushort)(data[68] | data[69] << 8);
165+
int port = (ushort)(data[72] | data[73] << 8);
163166

164167
await IPDiscoveryQueue.AddAsync(new IPDiscoveryEventArgs(ip, port)).ConfigureAwait(false);
165168
}
@@ -175,7 +178,7 @@ async Task ReceiveLoop()
175178
int read = await socket.ReceiveAsync(buffer, SocketFlags.None)
176179
.ConfigureAwait(false);
177180

178-
if (read == 70 && discoveringIP)
181+
if (read == 74 && discoveringIP) // IP discovery response packet is exactly 74 bytes long
179182
{
180183
await HandleIPDiscoveryPacket(buffer.Array!);
181184

@@ -218,6 +221,8 @@ async Task ReceiveLoop()
218221
break;
219222
}
220223
}
224+
225+
log.LogVerbose("[ReceiveLoop] Exited receive loop.");
221226
}
222227
#endregion
223228

@@ -235,11 +240,13 @@ void Send(byte[] buffer, int offset, int count)
235240
/// <exception cref="SocketException">Thrown if the socket encounters an error while sending data.</exception>
236241
public Task StartIPDiscoveryAsync()
237242
{
238-
byte[] packet = new byte[70];
239-
packet[0] = (byte)(Ssrc >> 24);
240-
packet[1] = (byte)(Ssrc >> 16);
241-
packet[2] = (byte)(Ssrc >> 8);
242-
packet[3] = (byte)(Ssrc >> 0);
243+
byte[] packet = new byte[74];
244+
Span<byte> span = packet.AsSpan();
245+
246+
BinaryPrimitives.WriteInt16BigEndian(span[0..2], 1); // Mark as request (type)
247+
BinaryPrimitives.WriteInt16BigEndian(span[2..4], 70); // Message length (excluding type and length fields)
248+
BinaryPrimitives.WriteUInt32BigEndian(span[4..8], Ssrc); // SSRC
249+
// Remainder of packet is empty for requests
243250

244251
discoveringIP = true;
245252
return SendAsync(new ArraySegment<byte>(packet));

src/Discore/Voice/Internal/VoiceWebSocket.Payloads.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ async Task HandleReadyPayload(JsonElement payload, JsonElement data)
3131
{
3232
var ip = IPAddress.Parse(data.GetProperty("ip").GetString()!);
3333
int port = data.GetProperty("port").GetInt32();
34-
int ssrc = data.GetProperty("ssrc").GetInt32();
34+
uint ssrc = data.GetProperty("ssrc").GetUInt32();
3535

3636
JsonElement modesArray = data.GetProperty("modes");
3737
string[] modes = new string[modesArray.GetArrayLength()];
@@ -205,13 +205,13 @@ void BuildPayload(Utf8JsonWriter writer)
205205
writer.WriteEndObject();
206206
}
207207

208-
log.LogVerbose($"[SelectProtocol] Sending to {ip}:{port}...");
208+
log.LogVerbose($"[SelectProtocol] Using response endpoint {ip}:{port} and requesting encryption mode {encryptionMode}...");
209209
return SendPayload(VoiceOPCode.SelectProtocol, BuildPayload);
210210
}
211211

212212
/// <exception cref="DiscordWebSocketException">Thrown if the payload fails to send because of a WebSocket error.</exception>
213213
/// <exception cref="InvalidOperationException">Thrown if the socket is not connected.</exception>
214-
public Task SendSpeakingPayload(SpeakingFlag flags, int ssrc)
214+
public Task SendSpeakingPayload(SpeakingFlag flags, uint ssrc)
215215
{
216216
void BuildPayload(Utf8JsonWriter writer)
217217
{

0 commit comments

Comments
 (0)