Complete voice connection

This commit is contained in:
Amish Shah
2016-08-23 20:59:03 +01:00
parent f713f52841
commit e370ccf806
5 changed files with 97 additions and 4 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,17 +1,23 @@
const VoiceConnectionWebSocket = require('./VoiceConnectionWebSocket');
const VoiceConnectionUDPClient = require('./VoiceConnectionUDPClient');
const EventEmitter = require('events').EventEmitter;
class VoiceConnection extends EventEmitter {
constructor(manager, serverID, token, sessionID, endpoint) {
super();
this.manager = manager;
this.endpoint = endpoint;
this.websocket = new VoiceConnectionWebSocket(this, serverID, token, sessionID, endpoint);
this.ready = false;
this.bindListeners();
}
bindListeners() {
this.websocket.on('ready-for-udp', data => {
console.log(data);
this.udp = new VoiceConnectionUDPClient(this, data);
});
this.websocket.on('ready', () => {
this.ready = true;
});
}
}

View File

@@ -1,4 +1,73 @@
class VoiceConnectionUDPClient {
const udp = require('dgram');
const dns = require('dns');
const Constants = require('../../util/Constants');
const EventEmitter = require('events').EventEmitter;
class VoiceConnectionUDPClient extends EventEmitter {
constructor(voiceConnection, data) {
super();
this.voiceConnection = voiceConnection;
this.count = 0;
this.data = data;
this.dnsLookup();
}
dnsLookup() {
dns.lookup(this.voiceConnection.endpoint, (err, address) => {
if (err) {
return this.emit('error', err);
}
this.connectUDP(address);
});
}
send(packet) {
if (this.udpSocket) {
try {
this.udpSocket.send(packet, 0, packet.length, this.data.port, this.udpIP);
} catch (err) {
return this.emit('error', err);
}
}
}
connectUDP(address) {
this.udpIP = address;
this.udpSocket = udp.createSocket('udp4');
// finding local IP
// https://discordapp.com/developers/docs/topics/voice-connections#ip-discovery
this.udpSocket.once('message', message => {
const packet = new Buffer(message);
this.localIP = '';
for (let i = 4; i < packet.indexOf(0, i); i++) {
this.localIP += String.fromCharCode(packet[i]);
}
this.localPort = parseInt(packet.readUIntLE(packet.length - 2, 2).toString(10), 10);
this.voiceConnection.websocket.send({
op: Constants.VoiceOPCodes.SELECT_PROTOCOL,
d: {
protocol: 'udp',
data: {
address: this.localIP,
port: this.localPort,
mode: 'xsalsa20_poly1305',
},
},
});
});
this.udpSocket.on('error', (error, message) => {
this.emit('error', { error, message });
});
const blankMessage = new Buffer(70);
blankMessage.writeUIntBE(this.data.ssrc, 0, 4);
this.send(blankMessage);
}
}

View File

@@ -45,10 +45,19 @@ class VoiceConnectionWebSocket extends EventEmitter {
}
switch (packet.op) {
case 2:
case Constants.VoiceOPCodes.READY:
this.emit('ready-for-udp', packet.d);
break;
case Constants.VoiceOPCodes.SESSION_DESCRIPTION:
this.encryptionMode = packet.d.mode;
this.secretKey = new Uint8Array(new ArrayBuffer(packet.d.secret_key.length));
for (const index in packet.d.secret_key) {
this.secretKey[index] = packet.d.secret_key[index];
}
this.emit('ready');
break;
default:
this.emit('unknown', packet);
break;
}
}

View File

@@ -120,6 +120,15 @@ exports.OPCodes = {
INVALID_SESSION: 9,
};
exports.VoiceOPCodes = {
IDENTIFY: 0,
SELECT_PROTOCOL: 1,
READY: 2,
HEARTBEAT: 3,
SESSION_DESCRIPTION: 4,
SPEAKING: 5,
};
exports.Events = {
READY: 'ready',
GUILD_CREATE: 'guildCreate',