diff --git a/lib/Voice/AudioEncoder.js b/lib/Voice/AudioEncoder.js index bb4b92aad..01e0fb638 100644 --- a/lib/Voice/AudioEncoder.js +++ b/lib/Voice/AudioEncoder.js @@ -26,13 +26,48 @@ var AudioEncoder = (function () { return this.opus.encode(buffer, 1920); }; + AudioEncoder.prototype.encodeStream = function encodeStream(stream) { + var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, buffer) {} : arguments[1]; + + var self = this; + return new Promise(function (resolve, reject) { + var enc = cpoc.spawn("ffmpeg", ["-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. + "-af", "volume=1", "pipe:1", "-i", "-"]); + + stream.pipe(enc.stdin); + + enc.stdout.once("readable", function () { + callback(null, { + proc: enc, + stream: enc.stdout, + instream: stream + }); + resolve({ + proc: enc, + stream: enc.stdout, + instream: stream + }); + }); + + enc.stdout.on("end", function () { + callback("end"); + reject("end"); + }); + + enc.stdout.on("close", function () { + callback("close"); + reject("close"); + }); + }); + }; + AudioEncoder.prototype.encodeFile = function encodeFile(file) { var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, buffer) {} : arguments[1]; var self = this; return new Promise(function (resolve, reject) { - var enc = cpoc.spawn("ffmpeg", ["-i", file, "-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. - "-af", "volume=1", "pipe:1"]); + var enc = cpoc.spawn("ffmpeg", ["-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. + "-af", "volume=1", "pipe:1", "-i", file]); enc.stdout.once("readable", function () { callback(null, { diff --git a/lib/Voice/VoiceConnection.js b/lib/Voice/VoiceConnection.js index 08393fc32..226527f33 100644 --- a/lib/Voice/VoiceConnection.js +++ b/lib/Voice/VoiceConnection.js @@ -57,7 +57,10 @@ var VoiceConnection = (function (_EventEmitter) { VoiceConnection.prototype.stopPlaying = function stopPlaying() { this.playing = false; this.playingIntent = null; - if (this.streamProc) this.streamProc.kill(); + if (this.instream) { + console.log(this.instream); + this.instream.unpipe(this.streamProc); + }if (this.streamProc) this.streamProc.destroy(); }; VoiceConnection.prototype.playRawStream = function playRawStream(stream) { @@ -80,14 +83,15 @@ var VoiceConnection = (function (_EventEmitter) { self.playingIntent = retStream; function send() { + if (!self.playingIntent || !self.playing) { self.setSpeaking(false); retStream.emit("end"); + self; return; } try { var buffer = stream.read(1920); - if (!buffer) { setTimeout(send, length * 10); // give chance for some data in 200ms to appear return; @@ -162,7 +166,7 @@ var VoiceConnection = (function (_EventEmitter) { if (!self.encoder.opus) { self.playing = false; self.emit("error", "No Opus!"); - self.emit("debug", "Tried to use node-opus, but opus not available - install it!"); + self.client.emit("debug", "Tried to use node-opus, but opus not available - install it!"); return; } var buffer = self.encoder.opusBuffer(rawbuffer); @@ -199,6 +203,31 @@ var VoiceConnection = (function (_EventEmitter) { function error() { var e = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; + console.log(e); + reject(e); + callback(e); + } + }); + }; + + VoiceConnection.prototype.playStream = function playStream(stream) { + var _this2 = this; + + var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err, str) {} : arguments[1]; + + var self = this; + return new Promise(function (resolve, reject) { + _this2.encoder.encodeStream(stream)["catch"](error).then(function (data) { + self.streamProc = data.proc; + self.instream = data.instream; + var intent = self.playRawStream(data.stream); + resolve(intent); + callback(null, intent); + }); + function error() { + var e = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; + + console.log(e); reject(e); callback(e); } @@ -206,12 +235,12 @@ var VoiceConnection = (function (_EventEmitter) { }; VoiceConnection.prototype.init = function init() { - var _this2 = this; + var _this3 = this; var self = this; dns.lookup(this.endpoint, function (err, address, family) { self.endpoint = address; - var vWS = self.vWS = new WebSocket("wss://" + _this2.endpoint, null, { rejectUnauthorized: false }); + var vWS = self.vWS = new WebSocket("wss://" + _this3.endpoint, null, { rejectUnauthorized: false }); var udpClient = self.udp = udp.createSocket("udp4"); var firstPacket = true; diff --git a/src/Voice/AudioEncoder.js b/src/Voice/AudioEncoder.js index ae7b9f6bf..7293d5ef1 100644 --- a/src/Voice/AudioEncoder.js +++ b/src/Voice/AudioEncoder.js @@ -23,16 +23,55 @@ class AudioEncoder{ } - encodeFile(file, callback=function(err, buffer){}){ + encodeStream(stream, callback=function(err, buffer){}){ var self = this; return new Promise((resolve, reject) => { var enc = cpoc.spawn("ffmpeg" , [ - "-i", file, "-f", "s16le", "-ar", "48000", "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. "-af", "volume=1", - "pipe:1" + "pipe:1", + "-i", "-" + ]); + + stream.pipe(enc.stdin); + + enc.stdout.once("readable", function() { + callback(null, { + proc : enc, + stream : enc.stdout, + instream : stream + }); + resolve({ + proc : enc, + stream : enc.stdout, + instream : stream + }); + }); + + enc.stdout.on("end", function() { + callback("end"); + reject("end"); + }); + + enc.stdout.on("close", function() { + callback("close"); + reject("close"); + }); + }); + } + + encodeFile(file, callback=function(err, buffer){}){ + var self = this; + return new Promise((resolve, reject) => { + var enc = cpoc.spawn("ffmpeg" , [ + "-f", "s16le", + "-ar", "48000", + "-ac", "1", // this can be 2 but there's no point, discord makes it mono on playback, wasted bandwidth. + "-af", "volume=1", + "pipe:1", + "-i", file ]); enc.stdout.once("readable", function() { @@ -45,7 +84,7 @@ class AudioEncoder{ stream : enc.stdout }); }); - + enc.stdout.on("end", function() { callback("end"); reject("end"); diff --git a/src/Voice/VoiceConnection.js b/src/Voice/VoiceConnection.js index fb02af894..a4b829bca 100644 --- a/src/Voice/VoiceConnection.js +++ b/src/Voice/VoiceConnection.js @@ -50,8 +50,11 @@ class VoiceConnection extends EventEmitter { stopPlaying() { this.playing = false; this.playingIntent = null; - if (this.streamProc) - this.streamProc.kill(); + if(this.instream){ + console.log(this.instream); + this.instream.unpipe(this.streamProc); + }if (this.streamProc) + this.streamProc.destroy(); } playRawStream(stream) { @@ -74,14 +77,15 @@ class VoiceConnection extends EventEmitter { self.playingIntent = retStream; function send() { + if (!self.playingIntent || !self.playing) { self.setSpeaking(false); retStream.emit("end"); + self return; } try { var buffer = stream.read(1920); - if (!buffer) { setTimeout(send, length * 10); // give chance for some data in 200ms to appear return; @@ -159,7 +163,7 @@ class VoiceConnection extends EventEmitter { if(!self.encoder.opus){ self.playing=false; self.emit("error", "No Opus!"); - self.emit("debug", "Tried to use node-opus, but opus not available - install it!"); + self.client.emit("debug", "Tried to use node-opus, but opus not available - install it!"); return; } var buffer = self.encoder.opusBuffer(rawbuffer); @@ -196,6 +200,29 @@ class VoiceConnection extends EventEmitter { }); function error(e = true) { + console.log(e); + reject(e); + callback(e); + } + }) + } + + playStream(stream, callback = function (err, str) { }) { + var self = this; + return new Promise((resolve, reject) => { + this.encoder + .encodeStream(stream) + .catch(error) + .then(data => { + self.streamProc = data.proc; + self.instream = data.instream; + var intent = self.playRawStream(data.stream); + resolve(intent); + callback(null, intent); + + }); + function error(e = true) { + console.log(e); reject(e); callback(e); } diff --git a/test/bot.1.js b/test/bot.1.js index e597d6edc..c15b05e5d 100644 --- a/test/bot.1.js +++ b/test/bot.1.js @@ -1,40 +1,55 @@ var Discord = require("../"); var client = new Discord.Client(); -client.on("debug", (m) => console.log("[debug]",m)); +var request = require("superagent"); +client.on("debug", (m) => console.log("[debug]", m)); client.on("warn", (m) => console.log("[warn]", m)); var start = Date.now(); client.on("message", m => { - if(m.content === "&init"){ - for(var channel of m.channel.server.channels){ - if(channel instanceof Discord.VoiceChannel){ + if (m.content === "&init") { + for (var channel of m.channel.server.channels) { + if (channel instanceof Discord.VoiceChannel) { client.joinVoiceChannel(channel).catch(error); break; } } } - if(m.content.startsWith("$$$ stop")){ - if(client.internal.voiceConnection){ + if (m.content.startsWith("$$$ stop")) { + if (client.internal.voiceConnection) { client.internal.voiceConnection.stopPlaying(); } return; } - if(m.content.startsWith("$$$")){ + if (m.content.startsWith("$$$")) { var chan; var rest = m.content.split(" "); rest.splice(0, 1); rest = rest.join(" "); - if(client.internal.voiceConnection){ + if (client.internal.voiceConnection) { client.reply(m, "ok, I'll play that for you"); var connection = client.internal.voiceConnection; - connection.playFile("C:/users/amish/desktop/"+rest); + connection.playFile("C:/users/amish/desktop/" + rest); + } + } if (m.content.startsWith("$pipebitch")) { + var chan; + var rest = m.content.split(" "); + rest.splice(0, 1); + rest = rest.join(" "); + + if (client.internal.voiceConnection) { + client.reply(m, "ok, I'll play that for you " + rest); + var connection = client.internal.voiceConnection; + + var request = require("request"); + + connection.playStream(request(rest)); } } }); -function error(e){ +function error(e) { console.log(e.stack); process.exit(0); } -client.login(process.env["discordEmail"], process.env["discordPass"]).catch((e)=>console.log(e)); \ No newline at end of file +client.login(process.env["discordEmail"], process.env["discordPass"]).catch((e) => console.log(e)); \ No newline at end of file