예제 #1
0
        private async Task HeartbeatAsync()
        {
            await Task.Yield();

            var token = Token;

            while (true)
            {
                try
                {
                    token.ThrowIfCancellationRequested();

                    var dt = DateTime.Now;
                    Discord.DebugLogger.LogMessage(LogLevel.Debug, "VoiceNext", "Sent heartbeat", dt);

                    var hbd = new VoiceDispatch
                    {
                        OpCode  = 3,
                        Payload = UnixTimestamp(dt)
                    };
                    var hbj = JsonConvert.SerializeObject(hbd);
                    VoiceWs.SendMessage(hbj);

                    LastHeartbeat = dt;
                    await Task.Delay(HeartbeatInterval).ConfigureAwait(false);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
            }
        }
예제 #2
0
        internal Task StartAsync()
        {
            // Let's announce our intentions to the server
            var vdp = new VoiceDispatch();

            if (!Resume)
            {
                vdp.OpCode  = 0;
                vdp.Payload = new VoiceIdentifyPayload
                {
                    ServerId  = ServerData.GuildId,
                    UserId    = StateData.UserId.Value,
                    SessionId = StateData.SessionId,
                    Token     = ServerData.Token
                };
                Resume = true;
            }
            else
            {
                vdp.OpCode  = 7;
                vdp.Payload = new VoiceIdentifyPayload
                {
                    ServerId  = ServerData.GuildId,
                    SessionId = StateData.SessionId,
                    Token     = ServerData.Token
                };
            }
            var vdj = JsonConvert.SerializeObject(vdp, Formatting.None);

            VoiceWs.SendMessage(vdj);

            return(Task.Delay(0));
        }
예제 #3
0
        private async Task Stage1()
        {
#if !NETSTANDARD1_1
            // IP Discovery
            UdpClient.Setup(ConnectionEndpoint);
            var pck = new byte[70];
            Array.Copy(BitConverter.GetBytes(SSRC), 0, pck, pck.Length - 4, 4);
            await UdpClient.SendAsync(pck, pck.Length).ConfigureAwait(false);

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

            var ipe  = Array.IndexOf <byte>(ipd, 0, 4);
            var ip   = new UTF8Encoding(false).GetString(ipd, 4, ipe - 4);
            var port = BitConverter.ToUInt16(ipd, ipd.Length - 2);
            DiscoveredEndpoint = new IpEndpoint {
                Address = System.Net.IPAddress.Parse(ip), Port = port
            };
#endif

            // Ready
            var vsp = new VoiceDispatch
            {
                OpCode  = 1,
                Payload = new VoiceSelectProtocolPayload
                {
                    Protocol = "udp",
                    Data     = new VoiceSelectProtocolPayloadData
                    {
#if !NETSTANDARD1_1
                        Address = DiscoveredEndpoint.Address.ToString(),
                        Port    = (ushort)DiscoveredEndpoint.Port,
#else
                        Address = "0.0.0.0",
                        Port    = 0,
#endif
                        Mode = VOICE_MODE
                    }
                }
            };
            var vsj = JsonConvert.SerializeObject(vsp, Formatting.None);
            VoiceWs.SendMessage(vsj);

#if !NETSTANDARD1_1
            if (Configuration.EnableIncoming)
            {
                ReceiverTokenSource = new CancellationTokenSource();
                ReceiverTask        = Task.Run(VoiceReceiverTask, ReceiverToken);
            }
#endif
        }
예제 #4
0
        /// <summary>
        /// Sends a speaking status to the connected voice channel.
        /// </summary>
        /// <param name="speaking">Whether the current user is speaking or not.</param>
        /// <returns>A task representing the sending operation.</returns>
        public async Task SendSpeakingAsync(bool speaking = true)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The connection is not initialized");
            }

            if (!speaking)
            {
                var nullpcm = new byte[3840];
                for (var i = 0; i < 5; i++)
                {
                    await SendAsync(nullpcm, 20).ConfigureAwait(false);
                }

                SynchronizerTicks = 0;
                if (PlayingWait != null)
                {
                    PlayingWait.SetResult(true);
                }
            }
            else
            {
                if (PlayingWait == null || PlayingWait.Task.IsCompleted)
                {
                    PlayingWait = new TaskCompletionSource <bool>();
                }
            }

            var pld = new VoiceDispatch
            {
                OpCode  = 5,
                Payload = new VoiceSpeakingPayload
                {
                    Speaking = speaking,
                    Delay    = 0
                }
            };

            var plj = JsonConvert.SerializeObject(pld, Formatting.None);

            VoiceWs.SendMessage(plj);
        }
예제 #5
0
        /// <summary>
        /// Sends a speaking status to the connected voice channel.
        /// </summary>
        /// <param name="speaking">Whether the current user is speaking or not.</param>
        /// <returns>A task representing the sending operation.</returns>
        public void SendSpeaking(bool speaking = true)
        {
            if (!IsInitialized)
            {
                throw new InvalidOperationException("The connection is not initialized");
            }

            var pld = new VoiceDispatch
            {
                OpCode  = 5,
                Payload = new VoiceSpeakingPayload
                {
                    Speaking = speaking,
                    Delay    = 0
                }
            };

            var plj = JsonConvert.SerializeObject(pld, Formatting.None);

            VoiceWs.SendMessage(plj);
        }
예제 #6
0
        private async Task Stage1(VoiceReadyPayload voiceReady)
        {
            // IP Discovery
            UdpClient.Setup(ConnectionEndpoint);

            var pck = new byte[70];

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

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

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

            void PreparePacket(byte[] packet)
            {
                var ssrc       = 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 */));
            }

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

            SelectedEncryptionMode = selectedEncryptionMode.Value;

            // Ready
            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 = DiscoveredEndpoint.Address.ToString(),
                        Port    = (ushort)DiscoveredEndpoint.Port,
                        Mode    = selectedEncryptionMode.Key
                    }
                }
            };
            var vsj = JsonConvert.SerializeObject(vsp, Formatting.None);

            VoiceWs.SendMessage(vsj);

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

            ReceiverTokenSource = new CancellationTokenSource();
            ReceiverTask        = Task.Run(UdpReceiverTask, ReceiverToken);
        }