Пример #1
0
        private async Task Stage1(VoiceReadyPayload voiceReady)
        {
            // IP Discovery
            this.UdpClient.Setup(this.UdpEndpoint);

            var pck = new byte[70];

            PreparePacket(pck);
            await this.UdpClient.SendAsync(pck, pck.Length).ConfigureAwait(false);

            var ipd = await this.UdpClient.ReceiveAsync().ConfigureAwait(false);

            ReadPacket(ipd, out var ip, out var port);
            this.DiscoveredEndpoint = new IpEndpoint
            {
                Address = ip,
                Port    = port
            };
            this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceHandshake, "Endpoint dicovery finished - discovered endpoint is {0}:{1}", ip, port);

            void PreparePacket(byte[] packet)
            {
                var ssrc       = this.SSRC;
                var packetSpan = packet.AsSpan();

                MemoryMarshal.Write(packetSpan, ref ssrc);
                Helpers.ZeroFill(packetSpan);
            }

            void ReadPacket(byte[] packet, out System.Net.IPAddress decodedIp, out ushort decodedPort)
            {
                var packetSpan = packet.AsSpan();

                var ipString = Utilities.UTF8.GetString(packet, 4, 64 /* 70 - 6 */).TrimEnd('\0');

                decodedIp = System.Net.IPAddress.Parse(ipString);

                decodedPort = BinaryPrimitives.ReadUInt16LittleEndian(packetSpan.Slice(68 /* 70 - 2 */));
            }

            // Select voice encryption mode
            var selectedEncryptionMode = Sodium.SelectMode(voiceReady.Modes);

            this.SelectedEncryptionMode = selectedEncryptionMode.Value;

            // Ready
            this.Discord.Logger.LogTrace(VoiceNextEvents.VoiceHandshake, "Selected encryption mode is {0}", selectedEncryptionMode.Key);
            var vsp = new VoiceDispatch
            {
                OpCode  = 1,
                Payload = new VoiceSelectProtocolPayload
                {
                    Protocol = "udp",
                    Data     = new VoiceSelectProtocolPayloadData
                    {
                        Address = this.DiscoveredEndpoint.Address.ToString(),
                        Port    = (ushort)this.DiscoveredEndpoint.Port,
                        Mode    = selectedEncryptionMode.Key
                    }
                }
            };
            var vsj = JsonConvert.SerializeObject(vsp, Formatting.None);

            await this.WsSendAsync(vsj).ConfigureAwait(false);

            this.SenderTokenSource = new CancellationTokenSource();
            this.SenderTask        = Task.Run(this.VoiceSenderTask, this.SenderToken);

            this.ReceiverTokenSource = new CancellationTokenSource();
            this.ReceiverTask        = Task.Run(this.UdpReceiverTask, this.ReceiverToken);
        }
Пример #2
0
        private async Task ProcessPayloadAsync(BaseDiscordPayload payload)
        {
            LogHandler <WsVoiceClient> .Log.Debug($"Received {Enum.GetName(typeof(VoiceOpType), payload.Op)} payload.");

            switch (payload.Op)
            {
            case VoiceOpType.Ready:
                Vrp  = payload.Data.TryCast <VoiceReadyPayload>();
                _udp = new UdpClient(Vrp.IpAddress, Vrp.Port);
                await _udp.SendDiscoveryAsync(Vrp.Ssrc).ConfigureAwait(false);

                LogHandler <WsVoiceClient> .Log.Debug($"Sent UDP discovery with {Vrp.Ssrc} ssrc.");

                _heartBeatTask = HandleHeartbeatAsync(Vrp.HeartbeatInterval);
                LogHandler <WsVoiceClient> .Log.Debug(
                    $"Started heartbeat task with {Vrp.HeartbeatInterval} interval.");

                var selectProtocol = new BaseDiscordPayload(VoiceOpType.SelectProtocol,
                                                            new SelectPayload(Vrp.IpAddress, Vrp.Port));
                await _socket.SendAsync(selectProtocol)
                .ConfigureAwait(false);

                LogHandler <WsVoiceClient> .Log.Debug($"Sent select protocol with {Vrp.IpAddress}:{Vrp.Port}.");

                _ = VoiceSenderTask();
                break;

            case VoiceOpType.SessionDescription:
                var sdp = payload.Data.TryCast <SessionDescriptionPayload>();
                if (sdp.Mode != "xsalsa20_poly1305")
                {
                    return;
                }

                _sdp        = sdp;
                SodiumCodec = new SodiumCodec(_sdp.SecretKey);


                await _socket.SendAsync(new BaseDiscordPayload(VoiceOpType.Speaking, new
                {
                    delay = 0,
                    speaking = false
                })).ConfigureAwait(false);


                _ = SendKeepAliveAsync().ConfigureAwait(false);
                break;

            case VoiceOpType.Hello:
                var helloPayload = payload.Data.TryCast <HelloPayload>();
                if (_heartBeatTask != null)
                {
                    _heartBeatCancel.Cancel(false);
                    _heartBeatTask.Dispose();
                    _heartBeatTask = null;
                }

                _heartBeatTask = HandleHeartbeatAsync(helloPayload.HeartBeatInterval);
                break;
            }
        }
Пример #3
0
        private async Task Stage1(VoiceReadyPayload voiceReady)
        {
#if !NETSTANDARD1_1
            // IP Discovery
            this.UdpClient.Setup(this.ConnectionEndpoint);

            var pck = new byte[70];
            PreparePacket(pck);
            await this.UdpClient.SendAsync(pck, pck.Length).ConfigureAwait(false);

            var ipd = await this.UdpClient.ReceiveAsync().ConfigureAwait(false);

            ReadPacket(ipd, out var ip, out var port);
            this.DiscoveredEndpoint = new IpEndpoint
            {
                Address = ip,
                Port    = port
            };
            this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VNext UDP", $"Endpoint discovery resulted in {ip}:{port}", DateTime.Now);

            void PreparePacket(byte[] packet)
            {
                var ssrc       = this.SSRC;
                var packetSpan = packet.AsSpan();

                MemoryMarshal.Write(packetSpan, ref ssrc);
                Helpers.ZeroFill(packetSpan);
            }

            void ReadPacket(byte[] packet, out System.Net.IPAddress decodedIp, out ushort decodedPort)
            {
                var packetSpan = packet.AsSpan();

                var ipString = new UTF8Encoding(false).GetString(packet, 4, 64 /* 70 - 6 */).TrimEnd('\0');

                decodedIp = System.Net.IPAddress.Parse(ipString);

                decodedPort = BinaryPrimitives.ReadUInt16LittleEndian(packetSpan.Slice(68 /* 70 - 2 */));
            }
#else
            this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VNext UDP", $"Voice receive not supported - not performing endpoint discovery", DateTime.Now);
            await Task.Yield(); // just stop bothering me VS
#endif

            // Select voice encryption mode
            var selectedEncryptionMode = Sodium.SelectMode(voiceReady.Modes);
            this.SelectedEncryptionMode = selectedEncryptionMode.Value;

            // Ready
            this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Selected encryption mode: {selectedEncryptionMode.Key}", DateTime.Now);
            var vsp = new VoiceDispatch
            {
                OpCode  = 1,
                Payload = new VoiceSelectProtocolPayload
                {
                    Protocol = "udp",
                    Data     = new VoiceSelectProtocolPayloadData
                    {
#if !NETSTANDARD1_1
                        Address = this.DiscoveredEndpoint.Address.ToString(),
                        Port    = (ushort)this.DiscoveredEndpoint.Port,
#else
                        Address = "0.0.0.0",
                        Port    = 0,
#endif
                        Mode = selectedEncryptionMode.Key
                    }
                }
            };
            var vsj = JsonConvert.SerializeObject(vsp, Formatting.None);
            this.VoiceWs.SendMessage(vsj);

            this.SenderTokenSource = new CancellationTokenSource();
            this.SenderTask        = Task.Run(this.VoiceSenderTask, this.SenderToken);

            this.ReceiverTokenSource = new CancellationTokenSource();
            this.ReceiverTask        = Task.Run(this.UdpReceiverTask, this.ReceiverToken);
        }
Пример #4
0
        private async Task Stage1(VoiceReadyPayload voiceReady)
        {
            // IP Discovery
            this.UdpClient.Setup(this.UdpEndpoint);

            var pck = new byte[70];

            PreparePacket(pck);
            await this.UdpClient.SendAsync(pck, pck.Length).ConfigureAwait(false);

            // fetch endpoint it it wasn't done already
            IpEndpoint ownEndpoint;

            try
            {
                var ipd = await this.UdpClient.ReceiveAsync().ConfigureAwait(false);

                ReadPacket(ipd, out var ip, out var port);
                ownEndpoint = new IpEndpoint
                {
                    Address = ip,
                    Port    = port
                };
                this.DiscoveredEndpoint = ownEndpoint;
                this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VNext UDP", $"Endpoint discovery resulted in {ip}:{port}", DateTime.Now);
            } catch (Exception e)
            {
                this.Discord.DebugLogger.LogMessage(LogLevel.Error, "VNext UDP", "Endpoint discovery failed", DateTime.Now, e);

                // fallback to last value if present
                if (this.DiscoveredEndpoint.HasValue)
                {
                    ownEndpoint = this.DiscoveredEndpoint.Value;
                    this.Discord.DebugLogger.LogMessage(LogLevel.Info, "VNext UDP", "Endpoint discovery used old endpoint", DateTime.Now, e);
                }
                else
                {
                    throw e;
                }
            }


            void PreparePacket(byte[] packet)
            {
                var ssrc       = this.SSRC;
                var packetSpan = packet.AsSpan();

                MemoryMarshal.Write(packetSpan, ref ssrc);
                Helpers.ZeroFill(packetSpan);
            }

            void ReadPacket(byte[] packet, out System.Net.IPAddress decodedIp, out ushort decodedPort)
            {
                if (packet.Length != 70)
                {
                    throw new Exception($"Recieved invalid IP discovery data. Expected length 70 but got {packet.Length}");
                }

                var packetSpan = packet.AsSpan();

                var ipString = Utilities.UTF8.GetString(packet, 4, 64 /* 70 - 6 */).TrimEnd('\0');

                decodedIp = System.Net.IPAddress.Parse(ipString);

                decodedPort = BinaryPrimitives.ReadUInt16LittleEndian(packetSpan.Slice(68 /* 70 - 2 */));
            }

            // Select voice encryption mode
            var selectedEncryptionMode = Sodium.SelectMode(voiceReady.Modes);

            this.SelectedEncryptionMode = selectedEncryptionMode.Value;

            // Ready
            this.Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", $"Selected encryption mode: {selectedEncryptionMode.Key}", DateTime.Now);
            var vsp = new VoiceDispatch
            {
                OpCode  = 1,
                Payload = new VoiceSelectProtocolPayload
                {
                    Protocol = "udp",
                    Data     = new VoiceSelectProtocolPayloadData
                    {
                        Address = ownEndpoint.Address.ToString(),
                        Port    = (ushort)ownEndpoint.Port,
                        Mode    = selectedEncryptionMode.Key
                    }
                }
            };
            var vsj = JsonConvert.SerializeObject(vsp, Formatting.None);

            await this.VoiceWs.SendMessageAsync(vsj).ConfigureAwait(false);

            if (this.SenderTokenSource != null)
            {
                this.SenderTokenSource.Cancel();
            }
            this.SenderTokenSource = new CancellationTokenSource();
            this.SenderTask        = Task.Run(this.VoiceSenderTask, this.SenderToken);

            if (this.ReceiverTokenSource != null)
            {
                this.ReceiverTokenSource.Cancel();
            }
            this.ReceiverTokenSource = new CancellationTokenSource();
            this.ReceiverTask        = Task.Run(this.UdpReceiverTask, this.ReceiverToken);
        }