Class: Rubycord::Voice::VoiceUDP

Inherits:
Object
  • Object
show all
Defined in:
lib/rubycord/voice/network.rb

Overview

Represents a UDP connection to a voice server. This connection is used to send the actual audio data.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeVoiceUDP

Creates a new UDP connection. Only creates a socket as the discovery reply may come before the data is initialized.

[View source]

50
51
52
53
# File 'lib/rubycord/voice/network.rb', line 50

def initialize
  @socket = UDPSocket.new
  @encrypted = true
end

Instance Attribute Details

#encryptedtrue, false Also known as: encrypted?

Deprecated.

Discord no longer supports unencrypted voice communication.

Returns whether or not UDP communications are encrypted.

Returns:

  • (true, false)

    whether or not UDP communications are encrypted.


36
37
38
# File 'lib/rubycord/voice/network.rb', line 36

def encrypted
  @encrypted
end

#modeObject

The UDP encryption mode


43
44
45
# File 'lib/rubycord/voice/network.rb', line 43

def mode
  @mode
end

#secret_key=(value) ⇒ Object (writeonly)

Sets the secret key used for encryption


40
41
42
# File 'lib/rubycord/voice/network.rb', line 40

def secret_key=(value)
  @secret_key = value
end

Instance Method Details

#connect(ip, port, ssrc) ⇒ Object

Initializes the UDP socket with data obtained from opcode 2.

Parameters:

  • ip (String)

    The IP address to connect to.

  • port (Integer)

    The port to connect to.

  • ssrc (Integer)

    The Super Secret Relay Code (SSRC). Discord uses this to identify different voice users on the same endpoint.

[View source]

60
61
62
63
64
# File 'lib/rubycord/voice/network.rb', line 60

def connect(ip, port, ssrc)
  @ip = ip
  @port = port
  @ssrc = ssrc
end

#receive_discovery_replyArray(String, Integer)

Waits for a UDP discovery reply, and returns the sent data.

Returns:

  • (Array(String, Integer))

    the IP and port received from the discovery reply.

[View source]

68
69
70
71
72
73
74
# File 'lib/rubycord/voice/network.rb', line 68

def receive_discovery_reply
  # Wait for a UDP message
  message = @socket.recv(74)
  ip = message[8..-3].delete("\0")
  port = message[-2..].unpack1("n")
  [ip, port]
end

#send_audio(buf, sequence, time) ⇒ Object

Makes an audio packet from a buffer and sends it to Discord.

Parameters:

  • buf (String)

    The audio data to send, must be exactly one Opus frame

  • sequence (Integer)

    The packet sequence number, incremented by one for subsequent packets

  • time (Integer)

    When this packet should be played back, in no particular unit (essentially just the sequence number multiplied by 960)

[View source]

81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rubycord/voice/network.rb', line 81

def send_audio(buf, sequence, time)
  # Header of the audio packet
  header = [0x80, 0x78, sequence, time, @ssrc].pack("CCnNN")

  nonce = generate_nonce(header)
  buf = encrypt_audio(buf, nonce)

  data = header + buf

  # xsalsa20_poly1305 does not require an appended nonce
  data += nonce unless @mode == "xsalsa20_poly1305"

  send_packet(data)
end

#send_discoveryObject

Sends the UDP discovery packet with the internally stored SSRC. Discord will send a reply afterwards which can be received using #receive_discovery_reply

[View source]

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rubycord/voice/network.rb', line 98

def send_discovery
  # Create empty packet
  discovery_packet = ""

  # Add Type request (0x1 = request, 0x2 = response)
  discovery_packet += [0x1].pack("n")

  # Add Length (excluding Type and itself = 70)
  discovery_packet += [70].pack("n")

  # Add SSRC
  discovery_packet += [@ssrc].pack("N")

  # Add 66 zeroes so the packet is 74 bytes long
  discovery_packet += "\0" * 66

  send_packet(discovery_packet)
end