Class: Discordrb::Voice::VoiceWS

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

Overview

Represents a websocket connection to the voice server

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(channel, bot, token, session, endpoint) ⇒ VoiceWS

Returns a new instance of VoiceWS.



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/discordrb/voice/network.rb', line 57

def initialize(channel, bot, token, session, endpoint)
  @channel = channel
  @bot = bot
  @token = token
  @session = session

  @endpoint = endpoint
  @endpoint.gsub!(':80', '')

  @udp = VoiceUDP.new
end

Instance Attribute Details

#udpObject (readonly)

Returns the value of attribute udp.



55
56
57
# File 'lib/discordrb/voice/network.rb', line 55

def udp
  @udp
end

Instance Method Details

#connectObject

Communication goes like this: me discord | | websocket connect -> | | | | <- websocket opcode 2 | | UDP discovery -> | | | | <- UDP reply packet | | websocket opcode 1 -> | | | ...



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/discordrb/voice/network.rb', line 164

def connect
  # Connect websocket
  @thread = Thread.new do
    Thread.current[:discordrb_name] = 'vws'
    init_ws
  end

  @bot.debug('Started websocket initialization, now waiting for UDP discovery reply')

  # Now wait for opcode 2 and the resulting UDP reply packet
  ip, port = @udp.receive_discovery_reply
  @bot.debug("UDP discovery reply received! #{ip} #{port}")

  # Send UDP init packet with received UDP data
  send_udp_connection(ip, port, @udp_mode)
end

#destroyObject



181
182
183
# File 'lib/discordrb/voice/network.rb', line 181

def destroy
  @thread.kill if @thread
end

#send_heartbeatObject

Send a heartbeat (op 3), has to be done every @heartbeat_interval seconds or the connection will terminate



98
99
100
101
102
103
104
105
106
# File 'lib/discordrb/voice/network.rb', line 98

def send_heartbeat
  millis = Time.now.strftime('%s%L').to_i
  @bot.debug("Sending voice heartbeat at #{millis}")

  @client.send({
    'op' => 3,
    'd' => nil
  }.to_json)
end

#send_init(server_id, bot_user_id, session_id, token) ⇒ Object

Send a connection init packet (op 0)



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/discordrb/voice/network.rb', line 70

def send_init(server_id, bot_user_id, session_id, token)
  @client.send({
    op: 0,
    d: {
      server_id: server_id,
      user_id: bot_user_id,
      session_id: session_id,
      token: token
    }
  }.to_json)
end

#send_speaking(value) ⇒ Object

Send a speaking packet (op 5). This determines the green circle around the avatar in the voice channel



109
110
111
112
113
114
115
116
117
118
# File 'lib/discordrb/voice/network.rb', line 109

def send_speaking(value)
  @bot.debug("Speaking: #{value}")
  @client.send({
    op: 5,
    d: {
      speaking: value,
      delay: 0
    }
  }.to_json)
end

#send_udp_connection(ip, port, mode) ⇒ Object

Sends the UDP connection packet (op 1)



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

def send_udp_connection(ip, port, mode)
  @client.send({
    op: 1,
    d: {
      protocol: 'udp',
      data: {
        address: ip,
        port: port,
        mode: mode
      }
    }
  }.to_json)
end

#websocket_message(msg) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/discordrb/voice/network.rb', line 126

def websocket_message(msg)
  @bot.debug("Received VWS message! #{msg}")
  packet = JSON.parse(msg)

  case packet['op']
  when 2
    # Opcode 2 contains data to initialize the UDP connection
    @ws_data = packet['d']

    @heartbeat_interval = @ws_data['heartbeat_interval']
    @ssrc = @ws_data['ssrc']
    @port = @ws_data['port']
    @udp_mode = @ws_data['modes'][0]

    @udp.connect(@endpoint, @port, @ssrc)
    @udp.send_discovery
  when 4
    # I'm not 100% sure what this packet does, but I'm keeping it for future compatibility.
    @ws_data = packet['d']
    @ready = true
    @mode = @ws_data['mode']
  end
end

#websocket_openObject

Event handlers; public for websocket-simple to work correctly



121
122
123
124
# File 'lib/discordrb/voice/network.rb', line 121

def websocket_open
  # Send the init packet
  send_init(@channel.server.id, @bot.bot_user.id, @session, @token)
end