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); }
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); }
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); }
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) { }