Resilience to abusers of the API

For some reason there's a way to join text channels via the Discord API but not the Discord Client, so this commit
prevents the Client from crashing by checking to see if the channels are voice channels.
This commit is contained in:
Amish Shah
2015-12-26 18:32:46 +00:00
parent f9f7a568fc
commit 8d0fc8e0a6
27 changed files with 5052 additions and 241 deletions

View File

@@ -1,3 +1,143 @@
"use strict";exports.__esModule = true;function _interopRequireDefault(obj){return obj && obj.__esModule?obj:{"default":obj};}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}var _child_process=require("child_process");var _child_process2=_interopRequireDefault(_child_process);var opus;try{opus = require("node-opus");}catch(e) { // no opus!
}var AudioEncoder=(function(){function AudioEncoder(){_classCallCheck(this,AudioEncoder);if(opus){this.opus = new opus.OpusEncoder(48000,2);}this.choice = false;}AudioEncoder.prototype.opusBuffer = function opusBuffer(buffer){return this.opus.encode(buffer,1920);};AudioEncoder.prototype.getCommand = function getCommand(force){if(this.choice && force)return choice;var choices=["avconv","ffmpeg"];for(var _iterator=choices,_isArray=Array.isArray(_iterator),_i=0,_iterator=_isArray?_iterator:_iterator[Symbol.iterator]();;) {var _ref;if(_isArray){if(_i >= _iterator.length)break;_ref = _iterator[_i++];}else {_i = _iterator.next();if(_i.done)break;_ref = _i.value;}var choice=_ref;var p=_child_process2["default"].spawnSync(choice);if(!p.error){this.choice = choice;return choice;}}return "help";};AudioEncoder.prototype.encodeStream = function encodeStream(stream,options){var self=this;return new Promise(function(resolve,reject){var enc=_child_process2["default"].spawn(self.getCommand(),['-loglevel','0','-i','-','-f','s16le','-ar','48000','-ac',2,'pipe:1','-af','volume=' + (options.volume || 1)],{stdio:['pipe','pipe','ignore']});stream.pipe(enc.stdin);enc.stdout.once("readable",function(){resolve({proc:enc,stream:enc.stdout,instream:stream,channels:2});});enc.stdout.on("end",function(){reject("end");});enc.stdout.on("close",function(){reject("close");});});};AudioEncoder.prototype.encodeFile = function encodeFile(file,options){var self=this;return new Promise(function(resolve,reject){var enc=_child_process2["default"].spawn(self.getCommand(),['-loglevel','0','-i',file,'-f','s16le','-ar','48000','-ac',2,'pipe:1','-af','"volume=' + (options.volume || 1) + '"'],{stdio:['pipe','pipe','ignore']});enc.stdout.once("readable",function(){resolve({proc:enc,stream:enc.stdout,channels:2});});enc.stdout.on("end",function(){reject("end");});enc.stdout.on("close",function(){reject("close");});});};AudioEncoder.prototype.encodeArbitraryFFmpeg = function encodeArbitraryFFmpeg(ffmpegOptions){var self=this;return new Promise(function(resolve,reject){ // add options discord.js needs
var options=ffmpegOptions.concat(['-loglevel','0','-f','s16le','-ar','48000','-ac',2,'pipe:1']);var enc=_child_process2["default"].spawn(self.getCommand(),options,{stdio:['pipe','pipe','ignore']});enc.stdout.once("readable",function(){resolve({proc:enc,stream:enc.stdout,channels:2});});enc.stdout.on("end",function(){reject("end");});enc.stdout.on("close",function(){reject("close");});});};return AudioEncoder;})();exports["default"] = AudioEncoder;module.exports = exports["default"];
"use strict";
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var _child_process = require("child_process");
var _child_process2 = _interopRequireDefault(_child_process);
var opus;
try {
opus = require("node-opus");
} catch (e) {
// no opus!
}
var AudioEncoder = (function () {
function AudioEncoder() {
_classCallCheck(this, AudioEncoder);
if (opus) {
this.opus = new opus.OpusEncoder(48000, 2);
}
this.choice = false;
}
AudioEncoder.prototype.opusBuffer = function opusBuffer(buffer) {
return this.opus.encode(buffer, 1920);
};
AudioEncoder.prototype.getCommand = function getCommand(force) {
if (this.choice && force) return choice;
var choices = ["avconv", "ffmpeg"];
for (var _iterator = choices, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var choice = _ref;
var p = _child_process2["default"].spawnSync(choice);
if (!p.error) {
this.choice = choice;
return choice;
}
}
return "help";
};
AudioEncoder.prototype.encodeStream = function encodeStream(stream, options) {
var self = this;
return new Promise(function (resolve, reject) {
var enc = _child_process2["default"].spawn(self.getCommand(), ['-loglevel', '0', '-i', '-', '-f', 's16le', '-ar', '48000', '-ac', 2, 'pipe:1', '-af', 'volume=' + (options.volume || 1)], { stdio: ['pipe', 'pipe', 'ignore'] });
stream.pipe(enc.stdin);
enc.stdout.once("readable", function () {
resolve({
proc: enc,
stream: enc.stdout,
instream: stream,
channels: 2
});
});
enc.stdout.on("end", function () {
reject("end");
});
enc.stdout.on("close", function () {
reject("close");
});
});
};
AudioEncoder.prototype.encodeFile = function encodeFile(file, options) {
var self = this;
return new Promise(function (resolve, reject) {
var enc = _child_process2["default"].spawn(self.getCommand(), ['-loglevel', '0', '-i', file, '-f', 's16le', '-ar', '48000', '-ac', 2, 'pipe:1', '-af', '"volume=' + (options.volume || 1) + '"'], { stdio: ['pipe', 'pipe', 'ignore'] });
enc.stdout.once("readable", function () {
resolve({
proc: enc,
stream: enc.stdout,
channels: 2
});
});
enc.stdout.on("end", function () {
reject("end");
});
enc.stdout.on("close", function () {
reject("close");
});
});
};
AudioEncoder.prototype.encodeArbitraryFFmpeg = function encodeArbitraryFFmpeg(ffmpegOptions) {
var self = this;
return new Promise(function (resolve, reject) {
// add options discord.js needs
var options = ffmpegOptions.concat(['-loglevel', '0', '-f', 's16le', '-ar', '48000', '-ac', 2, 'pipe:1']);
var enc = _child_process2["default"].spawn(self.getCommand(), options, { stdio: ['pipe', 'pipe', 'ignore'] });
enc.stdout.once("readable", function () {
resolve({
proc: enc,
stream: enc.stdout,
channels: 2
});
});
enc.stdout.on("end", function () {
reject("end");
});
enc.stdout.on("close", function () {
reject("close");
});
});
};
return AudioEncoder;
})();
exports["default"] = AudioEncoder;
module.exports = exports["default"];

View File

@@ -1,2 +1,28 @@
"use strict"; // represents an intent of streaming music
exports.__esModule = true;function _interopRequireDefault(obj){return obj && obj.__esModule?obj:{"default":obj};}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _inherits(subClass,superClass){if(typeof superClass !== "function" && superClass !== null){throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);}subClass.prototype = Object.create(superClass && superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__ = superClass;}var _events=require("events");var _events2=_interopRequireDefault(_events);var StreamIntent=(function(_EventEmitter){_inherits(StreamIntent,_EventEmitter);function StreamIntent(){_classCallCheck(this,StreamIntent);_EventEmitter.call(this);}return StreamIntent;})(_events2["default"]);exports["default"] = StreamIntent;module.exports = exports["default"];
"use strict";
// represents an intent of streaming music
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _events = require("events");
var _events2 = _interopRequireDefault(_events);
var StreamIntent = (function (_EventEmitter) {
_inherits(StreamIntent, _EventEmitter);
function StreamIntent() {
_classCallCheck(this, StreamIntent);
_EventEmitter.call(this);
}
return StreamIntent;
})(_events2["default"]);
exports["default"] = StreamIntent;
module.exports = exports["default"];

View File

@@ -1,17 +1,408 @@
"use strict"; /*
"use strict";
/*
Major credit to izy521 who is the creator of
https://github.com/izy521/discord.io,
without his help voice chat in discord.js would not have
been possible!
*/exports.__esModule = true;function _interopRequireDefault(obj){return obj && obj.__esModule?obj:{"default":obj};}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}function _inherits(subClass,superClass){if(typeof superClass !== "function" && superClass !== null){throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);}subClass.prototype = Object.create(superClass && superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__ = superClass;}var _ws=require("ws");var _ws2=_interopRequireDefault(_ws);var _dns=require("dns");var _dns2=_interopRequireDefault(_dns);var _dgram=require("dgram");var _dgram2=_interopRequireDefault(_dgram);var _AudioEncoder=require("./AudioEncoder");var _AudioEncoder2=_interopRequireDefault(_AudioEncoder);var _VoicePacket=require("./VoicePacket");var _VoicePacket2=_interopRequireDefault(_VoicePacket);var _StreamIntent=require("./StreamIntent");var _StreamIntent2=_interopRequireDefault(_StreamIntent);var _events=require("events");var _events2=_interopRequireDefault(_events);var _unpipe=require("unpipe");var _unpipe2=_interopRequireDefault(_unpipe);var VoiceConnection=(function(_EventEmitter){_inherits(VoiceConnection,_EventEmitter);function VoiceConnection(channel,client,session,token,server,endpoint){_classCallCheck(this,VoiceConnection);_EventEmitter.call(this);this.id = channel.id;this.voiceChannel = channel;this.client = client;this.session = session;this.token = token;this.server = server;this.endpoint = endpoint.split(":")[0];this.vWS = null; // vWS means voice websocket
this.ready = false;this.vWSData = {};this.encoder = new _AudioEncoder2["default"]();this.udp = null;this.playingIntent = null;this.playing = false;this.streamTime = 0;this.streamProc = null;this.KAI = null;this.timestamp = 0;this.sequence = 0;this.init();}VoiceConnection.prototype.destroy = function destroy(){this.stopPlaying();if(this.KAI)clearInterval(this.KAI);this.vWS.close();this.udp.close();this.client.internal.sendWS({op:4,d:{guild_id:null,channel_id:null,self_mute:true,self_deaf:false}});};VoiceConnection.prototype.stopPlaying = function stopPlaying(){this.playing = false;this.playingIntent = null;if(this.instream){ //not all streams implement these...
//and even file stream don't seem to implement them properly...
_unpipe2["default"](this.instream);if(this.instream.end){this.instream.end();}if(this.instream.destroy){this.instream.destroy();}this.instream = null;}if(this.streamProc){this.streamProc.stdin.pause();this.streamProc.kill("SIGINT");this.streamProc = null;}};VoiceConnection.prototype.playStream = function playStream(stream){var channels=arguments.length <= 1 || arguments[1] === undefined?2:arguments[1];var self=this;var startTime=Date.now();var count=0;var length=20;self.playing = true;var retStream=new _StreamIntent2["default"]();var onWarning=false;self.playingIntent = retStream;function send(){if(!self.playingIntent || !self.playing){self.setSpeaking(false);retStream.emit("end"); //console.log("ending 1");
return;}try{var buffer=stream.read(1920 * channels);if(!buffer){if(onWarning){retStream.emit("end");self.setSpeaking(false); //console.log("ending 2");
return;}else {onWarning = true;setTimeout(send,length * 10); // give chance for some data in 200ms to appear
return;}}if(buffer.length !== 1920 * channels){var newBuffer=new Buffer(1920 * channels).fill(0);buffer.copy(newBuffer);buffer = newBuffer;}count++;self.sequence + 1 < 65535?self.sequence += 1:self.sequence = 0;self.timestamp + 960 < 4294967295?self.timestamp += 960:self.timestamp = 0;self.sendBuffer(buffer,self.sequence,self.timestamp,function(e){});var nextTime=startTime + count * length;self.streamTime = count * length;setTimeout(send,length + (nextTime - Date.now()));if(!self.playing)self.setSpeaking(true);retStream.emit("time",self.streamTime);}catch(e) {retStream.emit("error",e);}}self.setSpeaking(true);send();return retStream;};VoiceConnection.prototype.setSpeaking = function setSpeaking(value){this.playing = value;if(this.vWS.readyState === _ws2["default"].OPEN)this.vWS.send(JSON.stringify({op:5,d:{speaking:value,delay:0}}));};VoiceConnection.prototype.sendPacket = function sendPacket(packet){var callback=arguments.length <= 1 || arguments[1] === undefined?function(err){}:arguments[1];var self=this;self.playing = true;try{if(self.vWS.readyState === _ws2["default"].OPEN)self.udp.send(packet,0,packet.length,self.vWSData.port,self.endpoint,callback);}catch(e) {self.playing = false;callback(e);return false;}};VoiceConnection.prototype.sendBuffer = function sendBuffer(rawbuffer,sequence,timestamp,callback){var self=this;self.playing = true;try{if(!self.encoder.opus){self.playing = false;self.emit("error","No Opus!");self.client.emit("debug","Tried to use node-opus, but opus not available - install it!");return;}var buffer=self.encoder.opusBuffer(rawbuffer);var packet=new _VoicePacket2["default"](buffer,sequence,timestamp,self.vWSData.ssrc);return self.sendPacket(packet,callback);}catch(e) {self.playing = false;self.emit("error",e);return false;}};VoiceConnection.prototype.playFile = function playFile(stream){var _this=this;var options=arguments.length <= 1 || arguments[1] === undefined?false:arguments[1];var callback=arguments.length <= 2 || arguments[2] === undefined?function(err,str){}:arguments[2];var self=this;self.stopPlaying();if(typeof options === "function"){ // options is the callback
callback = options;options = {};}return new Promise(function(resolve,reject){_this.encoder.encodeFile(stream,options)["catch"](error).then(function(data){self.streamProc = data.proc;var intent=self.playStream(data.stream,2);resolve(intent);callback(null,intent);});function error(){var e=arguments.length <= 0 || arguments[0] === undefined?true:arguments[0];reject(e);callback(e);}});};VoiceConnection.prototype.playRawStream = function playRawStream(stream){var _this2=this;var options=arguments.length <= 1 || arguments[1] === undefined?false:arguments[1];var callback=arguments.length <= 2 || arguments[2] === undefined?function(err,str){}:arguments[2];var self=this;self.stopPlaying();if(typeof options === "function"){ // options is the callback
callback = options;options = {};}return new Promise(function(resolve,reject){_this2.encoder.encodeStream(stream,options)["catch"](error).then(function(data){self.streamProc = data.proc;self.instream = data.instream;var intent=self.playStream(data.stream);resolve(intent);callback(null,intent);});function error(){var e=arguments.length <= 0 || arguments[0] === undefined?true:arguments[0];reject(e);callback(e);}});};VoiceConnection.prototype.playArbitraryFFmpeg = function playArbitraryFFmpeg(ffmpegOptions){var _this3=this;var callback=arguments.length <= 1 || arguments[1] === undefined?function(err,str){}:arguments[1];var self=this;self.stopPlaying();if(typeof options === "function"){ // options is the callback
callback = options;options = {};}return new Promise(function(resolve,reject){_this3.encoder.encodeArbitraryFFmpeg(ffmpegOptions)["catch"](error).then(function(data){self.streamProc = data.proc;self.instream = data.instream;var intent=self.playStream(data.stream);resolve(intent);callback(null,intent);});function error(){var e=arguments.length <= 0 || arguments[0] === undefined?true:arguments[0];reject(e);callback(e);}});};VoiceConnection.prototype.init = function init(){var _this4=this;var self=this;_dns2["default"].lookup(this.endpoint,function(err,address,family){var vWS=self.vWS = new _ws2["default"]("wss://" + _this4.endpoint,null,{rejectUnauthorized:false});_this4.endpoint = address;var udpClient=self.udp = _dgram2["default"].createSocket("udp4");var firstPacket=true;var discordIP="",discordPort="";udpClient.bind({exclusive:true});udpClient.on('message',function(msg,rinfo){var buffArr=JSON.parse(JSON.stringify(msg)).data;if(firstPacket === true){for(var i=4;i < buffArr.indexOf(0,i);i++) {discordIP += String.fromCharCode(buffArr[i]);}discordPort = msg.readUIntLE(msg.length - 2,2).toString(10);var wsDiscPayload={"op":1,"d":{"protocol":"udp","data":{"address":discordIP,"port":Number(discordPort),"mode":self.vWSData.modes[0] //Plain
}}};vWS.send(JSON.stringify(wsDiscPayload));firstPacket = false;}});vWS.on("open",function(){vWS.send(JSON.stringify({op:0,d:{server_id:self.server.id,user_id:self.client.internal.user.id,session_id:self.session,token:self.token}}));});var KAI;vWS.on("message",function(msg){var data=JSON.parse(msg);switch(data.op){case 2:self.vWSData = data.d;self.KAI = KAI = self.client.internal.intervals.misc["voiceKAI"] = setInterval(function(){if(vWS && vWS.readyState === _ws2["default"].OPEN)vWS.send(JSON.stringify({op:3,d:null}));},data.d.heartbeat_interval);var udpPacket=new Buffer(70);udpPacket.writeUIntBE(data.d.ssrc,0,4);udpClient.send(udpPacket,0,udpPacket.length,data.d.port,self.endpoint,function(err){if(err)self.emit("error",err);});break;case 4:self.ready = true;self.mode = data.d.mode;self.emit("ready",self);break;}});});};return VoiceConnection;})(_events2["default"]);exports["default"] = VoiceConnection;module.exports = exports["default"];
*/
exports.__esModule = true;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _ws = require("ws");
var _ws2 = _interopRequireDefault(_ws);
var _dns = require("dns");
var _dns2 = _interopRequireDefault(_dns);
var _dgram = require("dgram");
var _dgram2 = _interopRequireDefault(_dgram);
var _AudioEncoder = require("./AudioEncoder");
var _AudioEncoder2 = _interopRequireDefault(_AudioEncoder);
var _VoicePacket = require("./VoicePacket");
var _VoicePacket2 = _interopRequireDefault(_VoicePacket);
var _StreamIntent = require("./StreamIntent");
var _StreamIntent2 = _interopRequireDefault(_StreamIntent);
var _events = require("events");
var _events2 = _interopRequireDefault(_events);
var _unpipe = require("unpipe");
var _unpipe2 = _interopRequireDefault(_unpipe);
var VoiceConnection = (function (_EventEmitter) {
_inherits(VoiceConnection, _EventEmitter);
function VoiceConnection(channel, client, session, token, server, endpoint) {
_classCallCheck(this, VoiceConnection);
_EventEmitter.call(this);
this.id = channel.id;
this.voiceChannel = channel;
this.client = client;
this.session = session;
this.token = token;
this.server = server;
this.endpoint = endpoint.split(":")[0];
this.vWS = null; // vWS means voice websocket
this.ready = false;
this.vWSData = {};
this.encoder = new _AudioEncoder2["default"]();
this.udp = null;
this.playingIntent = null;
this.playing = false;
this.streamTime = 0;
this.streamProc = null;
this.KAI = null;
this.timestamp = 0;
this.sequence = 0;
this.init();
}
VoiceConnection.prototype.destroy = function destroy() {
this.stopPlaying();
if (this.KAI) clearInterval(this.KAI);
this.vWS.close();
this.udp.close();
this.client.internal.sendWS({
op: 4,
d: {
guild_id: null,
channel_id: null,
self_mute: true,
self_deaf: false
}
});
};
VoiceConnection.prototype.stopPlaying = function stopPlaying() {
this.playing = false;
this.playingIntent = null;
if (this.instream) {
//not all streams implement these...
//and even file stream don't seem to implement them properly...
_unpipe2["default"](this.instream);
if (this.instream.end) {
this.instream.end();
}
if (this.instream.destroy) {
this.instream.destroy();
}
this.instream = null;
}
if (this.streamProc) {
this.streamProc.stdin.pause();
this.streamProc.kill("SIGINT");
this.streamProc = null;
}
};
VoiceConnection.prototype.playStream = function playStream(stream) {
var channels = arguments.length <= 1 || arguments[1] === undefined ? 2 : arguments[1];
var self = this;
var startTime = Date.now();
var count = 0;
var length = 20;
self.playing = true;
var retStream = new _StreamIntent2["default"]();
var onWarning = false;
self.playingIntent = retStream;
function send() {
if (!self.playingIntent || !self.playing) {
self.setSpeaking(false);
retStream.emit("end");
//console.log("ending 1");
return;
}
try {
var buffer = stream.read(1920 * channels);
if (!buffer) {
if (onWarning) {
retStream.emit("end");
self.setSpeaking(false);
//console.log("ending 2");
return;
} else {
onWarning = true;
setTimeout(send, length * 10); // give chance for some data in 200ms to appear
return;
}
}
if (buffer.length !== 1920 * channels) {
var newBuffer = new Buffer(1920 * channels).fill(0);
buffer.copy(newBuffer);
buffer = newBuffer;
}
count++;
self.sequence + 1 < 65535 ? self.sequence += 1 : self.sequence = 0;
self.timestamp + 960 < 4294967295 ? self.timestamp += 960 : self.timestamp = 0;
self.sendBuffer(buffer, self.sequence, self.timestamp, function (e) {});
var nextTime = startTime + count * length;
self.streamTime = count * length;
setTimeout(send, length + (nextTime - Date.now()));
if (!self.playing) self.setSpeaking(true);
retStream.emit("time", self.streamTime);
} catch (e) {
retStream.emit("error", e);
}
}
self.setSpeaking(true);
send();
return retStream;
};
VoiceConnection.prototype.setSpeaking = function setSpeaking(value) {
this.playing = value;
if (this.vWS.readyState === _ws2["default"].OPEN) this.vWS.send(JSON.stringify({
op: 5,
d: {
speaking: value,
delay: 0
}
}));
};
VoiceConnection.prototype.sendPacket = function sendPacket(packet) {
var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err) {} : arguments[1];
var self = this;
self.playing = true;
try {
if (self.vWS.readyState === _ws2["default"].OPEN) self.udp.send(packet, 0, packet.length, self.vWSData.port, self.endpoint, callback);
} catch (e) {
self.playing = false;
callback(e);
return false;
}
};
VoiceConnection.prototype.sendBuffer = function sendBuffer(rawbuffer, sequence, timestamp, callback) {
var self = this;
self.playing = true;
try {
if (!self.encoder.opus) {
self.playing = false;
self.emit("error", "No Opus!");
self.client.emit("debug", "Tried to use node-opus, but opus not available - install it!");
return;
}
var buffer = self.encoder.opusBuffer(rawbuffer);
var packet = new _VoicePacket2["default"](buffer, sequence, timestamp, self.vWSData.ssrc);
return self.sendPacket(packet, callback);
} catch (e) {
self.playing = false;
self.emit("error", e);
return false;
}
};
VoiceConnection.prototype.playFile = function playFile(stream) {
var _this = this;
var options = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, str) {} : arguments[2];
var self = this;
self.stopPlaying();
if (typeof options === "function") {
// options is the callback
callback = options;
options = {};
}
return new Promise(function (resolve, reject) {
_this.encoder.encodeFile(stream, options)["catch"](error).then(function (data) {
self.streamProc = data.proc;
var intent = self.playStream(data.stream, 2);
resolve(intent);
callback(null, intent);
});
function error() {
var e = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
reject(e);
callback(e);
}
});
};
VoiceConnection.prototype.playRawStream = function playRawStream(stream) {
var _this2 = this;
var options = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? function (err, str) {} : arguments[2];
var self = this;
self.stopPlaying();
if (typeof options === "function") {
// options is the callback
callback = options;
options = {};
}
return new Promise(function (resolve, reject) {
_this2.encoder.encodeStream(stream, options)["catch"](error).then(function (data) {
self.streamProc = data.proc;
self.instream = data.instream;
var intent = self.playStream(data.stream);
resolve(intent);
callback(null, intent);
});
function error() {
var e = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
reject(e);
callback(e);
}
});
};
VoiceConnection.prototype.playArbitraryFFmpeg = function playArbitraryFFmpeg(ffmpegOptions) {
var _this3 = this;
var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, str) {} : arguments[1];
var self = this;
self.stopPlaying();
if (typeof options === "function") {
// options is the callback
callback = options;
options = {};
}
return new Promise(function (resolve, reject) {
_this3.encoder.encodeArbitraryFFmpeg(ffmpegOptions)["catch"](error).then(function (data) {
self.streamProc = data.proc;
self.instream = data.instream;
var intent = self.playStream(data.stream);
resolve(intent);
callback(null, intent);
});
function error() {
var e = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];
reject(e);
callback(e);
}
});
};
VoiceConnection.prototype.init = function init() {
var _this4 = this;
var self = this;
_dns2["default"].lookup(this.endpoint, function (err, address, family) {
var vWS = self.vWS = new _ws2["default"]("wss://" + _this4.endpoint, null, { rejectUnauthorized: false });
_this4.endpoint = address;
var udpClient = self.udp = _dgram2["default"].createSocket("udp4");
var firstPacket = true;
var discordIP = "",
discordPort = "";
udpClient.bind({ exclusive: true });
udpClient.on('message', function (msg, rinfo) {
var buffArr = JSON.parse(JSON.stringify(msg)).data;
if (firstPacket === true) {
for (var i = 4; i < buffArr.indexOf(0, i); i++) {
discordIP += String.fromCharCode(buffArr[i]);
}
discordPort = msg.readUIntLE(msg.length - 2, 2).toString(10);
var wsDiscPayload = {
"op": 1,
"d": {
"protocol": "udp",
"data": {
"address": discordIP,
"port": Number(discordPort),
"mode": self.vWSData.modes[0] //Plain
}
}
};
vWS.send(JSON.stringify(wsDiscPayload));
firstPacket = false;
}
});
vWS.on("open", function () {
vWS.send(JSON.stringify({
op: 0,
d: {
server_id: self.server.id,
user_id: self.client.internal.user.id,
session_id: self.session,
token: self.token
}
}));
});
var KAI;
vWS.on("message", function (msg) {
var data = JSON.parse(msg);
switch (data.op) {
case 2:
self.vWSData = data.d;
self.KAI = KAI = self.client.internal.intervals.misc["voiceKAI"] = setInterval(function () {
if (vWS && vWS.readyState === _ws2["default"].OPEN) vWS.send(JSON.stringify({
op: 3,
d: null
}));
}, data.d.heartbeat_interval);
var udpPacket = new Buffer(70);
udpPacket.writeUIntBE(data.d.ssrc, 0, 4);
udpClient.send(udpPacket, 0, udpPacket.length, data.d.port, self.endpoint, function (err) {
if (err) self.emit("error", err);
});
break;
case 4:
self.ready = true;
self.mode = data.d.mode;
self.emit("ready", self);
break;
}
});
});
};
return VoiceConnection;
})(_events2["default"]);
exports["default"] = VoiceConnection;
module.exports = exports["default"];

View File

@@ -1 +1,29 @@
"use strict";exports.__esModule = true;function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError("Cannot call a class as a function");}}var VoicePacket=function VoicePacket(data,sequence,time,ssrc){_classCallCheck(this,VoicePacket);var audioBuffer=data,returnBuffer=new Buffer(audioBuffer.length + 12);returnBuffer.fill(0);returnBuffer[0] = 0x80;returnBuffer[1] = 0x78;returnBuffer.writeUIntBE(sequence,2,2);returnBuffer.writeUIntBE(time,4,4);returnBuffer.writeUIntBE(ssrc,8,4);for(var i=0;i < audioBuffer.length;i++) {returnBuffer[i + 12] = audioBuffer[i];}return returnBuffer;};exports["default"] = VoicePacket;module.exports = exports["default"];
"use strict";
exports.__esModule = true;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var VoicePacket = function VoicePacket(data, sequence, time, ssrc) {
_classCallCheck(this, VoicePacket);
var audioBuffer = data,
returnBuffer = new Buffer(audioBuffer.length + 12);
returnBuffer.fill(0);
returnBuffer[0] = 0x80;
returnBuffer[1] = 0x78;
returnBuffer.writeUIntBE(sequence, 2, 2);
returnBuffer.writeUIntBE(time, 4, 4);
returnBuffer.writeUIntBE(ssrc, 8, 4);
for (var i = 0; i < audioBuffer.length; i++) {
returnBuffer[i + 12] = audioBuffer[i];
}
return returnBuffer;
};
exports["default"] = VoicePacket;
module.exports = exports["default"];