private void StartListener()
        {
            try
            {
                while (State > MediaConnectionState.NotConnected)
                {
                    byte[] received = UdpClient.Receive(ref _localEndpoint);

                    if (BitConverter.ToInt16(new byte[] { received[1], received[0] }, 0) == 2)
                    {
                        string ip = "";
                        for (int i = 8; i < received.Length; i++)
                        {
                            if (received[i] == 0)
                            {
                                break;
                            }
                            else
                            {
                                ip += (char)received[i];
                            }
                        }

                        _localEndpoint = new IPEndPoint(IPAddress.Parse(ip), BitConverter.ToUInt16(new byte[] { received[received.Length - 1], received[received.Length - 2] }, 0));

                        SelectProtocol(_localEndpoint);
                    }
                    else if (received[0] == 0x80 || received[0] == 0x90)
                    {
                        while (SecretKey == null)
                        {
                            Thread.Sleep(100);
                        }

                        //Console.WriteLine($"{received[0]} {received[1]} {received[2]} {received[3]} {received[4]} {received[5]} {received[6]} {received[7]} {received[8]} {received[9]} {received[10]} {received[11]}");

                        /*
                         * var ok = RTPPacketHeader.Read(SecretKey, received, out var _);
                         *
                         * Console.WriteLine($"{ok.Type} {ok.Flags} {ok.Sequence} {ok.Timestamp} {ok.SSRC} {ok.HasExtensions}");
                         */
                        // not much point in doing this rn since the decryption fails

                        if (_parentClient.Config.ParseIncomingRTPData)
                        {
                            try
                            {
                                var header = RTPPacketHeader.Read(SecretKey, received, out byte[] payload);

                                OnUdpPacket?.Invoke(this, new MediaPacketEventArgs(header, payload));
                            }
                            catch (SodiumException) { }
                        }
                    }
                }
            }
            catch { }

            UdpClient.Close();
        }
        private void StartListener()
        {
            int id     = WebSocket.Id;
            var client = UdpClient;

            try
            {
                while (JustifyThread(id))
                {
                    byte[] received = client.Receive(ref _localEndpoint);

                    if (BitConverter.ToInt16(new byte[] { received[1], received[0] }, 0) == 2)
                    {
                        string ip = "";
                        for (int i = 8; i < received.Length; i++)
                        {
                            if (received[i] == 0)
                            {
                                break;
                            }
                            else
                            {
                                ip += (char)received[i];
                            }
                        }

                        _localEndpoint = new IPEndPoint(IPAddress.Parse(ip), BitConverter.ToUInt16(new byte[] { received[received.Length - 1], received[received.Length - 2] }, 0));

                        WebSocket.SelectProtocol(_localEndpoint);
                    }
                    else if (received[0] == 0x80 || received[0] == 0x90)
                    {
                        while (SecretKey == null)
                        {
                            Thread.Sleep(100);
                        }

                        try
                        {
                            var header = RTPPacketHeader.Read(SecretKey, received, out byte[] payload);

                            HandlePacket(header, payload);
                        }
                        catch (SodiumException) { }
                    }
                }
            }
            catch (Exception ex)
            {
                Log("Listener err: " + ex);
            }

            client?.Close();

            Log("Killed listener for " + id);
        }
        public static RTPPacketHeader Read(byte[] secretKey, byte[] packet, out byte[] payload)
        {
            byte[] rawHeader = new byte[HeaderLength];
            Buffer.BlockCopy(packet, 0, rawHeader, 0, rawHeader.Length);

            RTPPacketHeader header = new RTPPacketHeader()
            {
                // Version = packet[0],
                Type      = packet[1],
                Sequence  = BitConverter.ToUInt16(new byte[] { rawHeader[3], rawHeader[2] }, 0),
                Timestamp = BitConverter.ToUInt32(new byte[] { rawHeader[7], rawHeader[6], rawHeader[5], rawHeader[4] }, 0),
                SSRC      = BitConverter.ToUInt32(new byte[] { rawHeader[11], rawHeader[10], rawHeader[9], rawHeader[8] }, 0)
            };

            byte[] decrypted = new byte[packet.Length - HeaderLength - Sodium.LengthDifference];

            byte[] nonce = new byte[rawHeader.Length * 2];
            Buffer.BlockCopy(rawHeader, 0, nonce, 0, rawHeader.Length);

            Sodium.Decrypt(packet, HeaderLength, packet.Length - HeaderLength, decrypted, 0, nonce, secretKey);

            if (packet[0] == 0x90) // later on we might wanna check if index 3 (7 - 3 cuz big indian) is 1 to make anarchy's feature here live on for longer
            {
                header.ExtraExtensionData = new byte[ExtensionLength / 2];
                Buffer.BlockCopy(decrypted, 0, header.ExtraExtensionData, 0, header.ExtraExtensionData.Length);

                ushort extensionCount = BitConverter.ToUInt16(new byte[] { decrypted[3], decrypted[2] }, 0);
                extensionCount++;

                for (int i = 1; i < extensionCount; i++)
                {
                    byte[] extension = new byte[ExtensionLength];
                    Buffer.BlockCopy(decrypted, i * ExtensionLength, extension, 0, ExtensionLength);

                    header.Extensions.Add(extension);
                }

                payload = new byte[decrypted.Length - extensionCount * ExtensionLength];
                Buffer.BlockCopy(decrypted, extensionCount * ExtensionLength, payload, 0, payload.Length);
            }
            else
            {
                payload = decrypted;
            }

            return(header);
        }
Exemple #4
0
        public int Write(byte[] buffer, int offset)
        {
            if (Session.State != MediaSessionState.Authenticated)
            {
                throw new InvalidOperationException("Connection has been closed.");
            }

            lock (Session.VoiceLock)
            {
                if (_nextTick == -1)
                {
                    _nextTick = Environment.TickCount;
                }
                else
                {
                    long distance = _nextTick - Environment.TickCount;

                    if (distance > 0)
                    {
                        Thread.Sleep((int)distance);
                    }
                }

                byte[] opusFrame = new byte[OpusEncoder.FrameBytes];
                int    frameSize = _encoder.EncodeFrame(buffer, offset, opusFrame, 0);

                byte[] packet = new RTPPacketHeader()
                {
                    // Version = 0x80,
                    Type      = DiscordMediaSession.SupportedCodecs["opus"].PayloadType,
                    Sequence  = Session.Sequence,
                    Timestamp = Session.Timestamp,
                    SSRC      = Session.SSRC.Audio
                }.Write(Session.SecretKey, opusFrame, 0, frameSize);

                Session.UdpClient.Send(packet, packet.Length);

                _nextTick += OpusEncoder.TimeBetweenFrames;
                Session.Sequence++;
                Session.Timestamp += OpusEncoder.FrameSamplesPerChannel;
            }

            return(offset + OpusEncoder.FrameBytes);
        }
Exemple #5
0
        public int Write(byte[] buffer, int offset)
        {
            if (_client.State < MediaConnectionState.Ready)
            {
                throw new InvalidOperationException("Client is not currently connected");
            }

            lock (_voiceLock)
            {
                if (_nextTick == -1)
                {
                    _nextTick = Environment.TickCount;
                }
                else
                {
                    long distance = _nextTick - Environment.TickCount;

                    if (distance > 0)
                    {
                        Thread.Sleep((int)distance);
                    }
                }

                byte[] opusFrame = new byte[OpusConverter.FrameBytes];
                int    frameSize = _encoder.EncodeFrame(buffer, offset, opusFrame, 0);

                byte[] packet = new RTPPacketHeader()
                {
                    Type      = DiscordMediaConnection.SupportedCodecs["opus"].PayloadType,
                    Sequence  = _sequence,
                    Timestamp = _timestamp,
                    SSRC      = _client.Connection.SSRC.Audio
                }.Write(_client.Connection.SecretKey, opusFrame, 0, frameSize);

                _client.Connection.UdpClient.Send(packet, packet.Length);

                _nextTick += OpusConverter.TimeBetweenFrames;
                _sequence++;
                _timestamp += OpusConverter.FrameSamplesPerChannel;
            }

            return(offset + OpusConverter.FrameBytes);
        }
Exemple #6
0
        protected override void HandlePacket(RTPPacketHeader header, byte[] payload)
        {
            // for some reason discord sends us voice packets before we get the user's ID. i don't think this impacts the audio tho; it seems like these packets don't have any voice data
            if (header.Type == SupportedCodecs["opus"].PayloadType && _ssrcToUserDictionary.TryGetValue(header.SSRC, out ulong userId))
            {
                if (!_receivers.TryGetValue(userId, out IncomingVoiceStream receiver))
                {
                    receiver = _receivers[userId] = new IncomingVoiceStream(this, userId);

                    if (OnUserSpeaking != null)
                    {
                        Task.Run(() => OnUserSpeaking.Invoke(this, _receivers[userId]));
                    }
                }

                if (payload.SequenceEqual(SilenceFrame))
                {
                    receiver.SilenceFramesReceived++;

                    if (receiver.SilenceFramesReceived >= 10)
                    {
                        receiver.Close();
                        _receivers.Remove(receiver.UserId);
                    }
                }
                else
                {
                    try
                    {
                        byte[] decoded = new byte[OpusEncoder.FrameBytes];
                        int    length  = _decoder.DecodeFrame(payload, 0, payload.Length, decoded, 0, false);

                        receiver.Enqueue(new DiscordVoicePacket(decoded));
                    }
                    catch (OpusException) { }
                }
            }
        }
 public MediaPacketEventArgs(RTPPacketHeader header, byte[] payload)
 {
     Header  = header;
     Payload = payload;
 }
 protected virtual void HandlePacket(RTPPacketHeader header, byte[] payload)
 {
 }