class Discordrb::Voice::VoiceUDP
Represents a UDP connection to a voice server. This connection is used to send the actual audio data.
Attributes
@return [true, false] whether or not UDP communications are encrypted.
@return [true, false] whether or not UDP communications are encrypted.
Sets the secret key used for encryption
Public Class Methods
Creates a new UDP connection. Only creates a socket as the discovery reply may come before the data is initialized.
# File lib/discordrb/voice/network.rb, line 41 def initialize @socket = UDPSocket.new end
Public Instance Methods
Initializes the UDP socket with data obtained from opcode 2. @param endpoint [String] The voice endpoint to connect to. @param port [Integer] The port to connect to. @param ssrc [Integer] The Super Secret Relay Code (SSRC). Discord uses this to identify different voice users
on the same endpoint.
# File lib/discordrb/voice/network.rb, line 50 def connect(endpoint, port, ssrc) @endpoint = endpoint @endpoint = @endpoint[6..-1] if @endpoint.start_with? 'wss://' @endpoint = @endpoint.gsub(':80', '') # The endpoint may contain a port, we don't want that @endpoint = Resolv.getaddress @endpoint @port = port @ssrc = ssrc end
Waits for a UDP discovery reply, and returns the sent data. @return [Array(String
, Integer
)] the IP and port received from the discovery reply.
# File lib/discordrb/voice/network.rb, line 62 def receive_discovery_reply # Wait for a UDP message message = @socket.recv(70) ip = message[4..-3].delete("\0") port = message[-2..-1].to_i [ip, port] end
Makes an audio packet from a buffer and sends it to Discord. @param buf [String] The audio data to send, must be exactly one Opus frame @param sequence [Integer] The packet sequence number, incremented by one for subsequent packets @param time [Integer] When this packet should be played back, in no particular unit (essentially just the
sequence number multiplied by 960)
# File lib/discordrb/voice/network.rb, line 75 def send_audio(buf, sequence, time) # Header of the audio packet header = [0x80, 0x78, sequence, time, @ssrc].pack('CCnNN') # Encrypt data, if necessary buf = encrypt_audio(header, buf) if encrypted? send_packet(header + buf) end
Sends the UDP discovery packet with the internally stored SSRC. Discord will send a reply afterwards which can be received using {#receive_discovery_reply}
# File lib/discordrb/voice/network.rb, line 87 def send_discovery discovery_packet = [@ssrc].pack('N') # Add 66 zeroes so the packet is 70 bytes long discovery_packet += "\0" * 66 send_packet(discovery_packet) end
Private Instance Methods
Encrypts audio data using RbNaCl @param header [String] The header of the packet, to be used as the nonce @param buf [String] The encoded audio data to be encrypted @return [String] the audio data, encrypted
# File lib/discordrb/voice/network.rb, line 101 def encrypt_audio(header, buf) raise 'No secret key found, despite encryption being enabled!' unless @secret_key box = RbNaCl::SecretBox.new(@secret_key) # The nonce is the header of the voice packet with 12 null bytes appended nonce = header + ([0] * 12).pack('C*') box.encrypt(nonce, buf) end
# File lib/discordrb/voice/network.rb, line 112 def send_packet(packet) @socket.send(packet, 0, @endpoint, @port) end