mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
AWESOME MAGIC
This commit is contained in:
48
lib/Voice/AudioEncoder.js
Normal file
48
lib/Voice/AudioEncoder.js
Normal file
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
var cpoc = require("child_process");
|
||||
var opus = require("node-opus");
|
||||
var VoicePacket = require("./VoicePacket.js");
|
||||
|
||||
var AudioEncoder = (function () {
|
||||
function AudioEncoder() {
|
||||
_classCallCheck(this, AudioEncoder);
|
||||
|
||||
this.opus = new opus.OpusEncoder(48000, 1);
|
||||
}
|
||||
|
||||
AudioEncoder.prototype.opusBuffer = function opusBuffer(buffer) {
|
||||
|
||||
return this.opus.encode(buffer, 1920);
|
||||
};
|
||||
|
||||
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", "-af", "volume=1", "pipe:1"]);
|
||||
|
||||
enc.stdout.on("readable", function () {
|
||||
callback(null, enc.stdout);
|
||||
resolve(enc.stdout);
|
||||
});
|
||||
|
||||
enc.stdout.on("end", function () {
|
||||
callback("end");
|
||||
reject("end");
|
||||
});
|
||||
|
||||
enc.stdout.on("close", function () {
|
||||
callback("close");
|
||||
reject("close");
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return AudioEncoder;
|
||||
})();
|
||||
|
||||
module.exports = AudioEncoder;
|
||||
@@ -9,23 +9,9 @@ var Lame = require("lame");
|
||||
var Opus = require('node-opus');
|
||||
var Wav = require('wav');
|
||||
var fs = require("fs");
|
||||
|
||||
function VoicePacket(packet, sequence, timestamp, ssrc) {
|
||||
var audioBuffer = packet;
|
||||
var retBuff = new Buffer(audioBuffer.length + 12);
|
||||
retBuff.fill(0);
|
||||
retBuff[0] = 0x80;
|
||||
retBuff[1] = 0x78;
|
||||
retBuff.writeUIntBE(sequence, 2, 2);
|
||||
retBuff.writeUIntBE(timestamp, 4, 4);
|
||||
retBuff.writeUIntBE(ssrc, 8, 4);
|
||||
|
||||
for (var i = 0; i < audioBuffer.length; i++) {
|
||||
retBuff[i + 12] = audioBuffer[i];
|
||||
}
|
||||
|
||||
return retBuff;
|
||||
}
|
||||
var ffmpeg = require('fluent-ffmpeg');
|
||||
var AudioEncoder = require("./AudioEncoder.js");
|
||||
var VoicePacket = require("./VoicePacket.js");
|
||||
|
||||
var VoiceConnection = (function () {
|
||||
function VoiceConnection(channel, client, session, token, server, endpoint) {
|
||||
@@ -40,69 +26,91 @@ var VoiceConnection = (function () {
|
||||
this.vWS = null; // vWS means voice websocket
|
||||
this.ready = false;
|
||||
this.vWSData = {};
|
||||
this.opus = new Opus.OpusEncoder(48000, 1);
|
||||
this.encoder = new AudioEncoder();
|
||||
this.udp = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
VoiceConnection.prototype.test = function test() {
|
||||
VoiceConnection.prototype.playRawStream = function playRawStream(stream) {
|
||||
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
|
||||
var startTime = Date.now();
|
||||
var cnt = 0;
|
||||
function sendAudio(sequence, timestamp, opusEncoder, wavOutput, udpClient, vWS) {
|
||||
cnt++;
|
||||
var buff = wavOutput.read(1920);
|
||||
if (buff && buff.length === 1920) {
|
||||
sequence + 20 < 65535 ? sequence += 1 : sequence = 0;
|
||||
timestamp + 9600 < 4294967295 ? timestamp += 960 : timestamp = 0;
|
||||
var sequence = 0;
|
||||
var time = 0;
|
||||
var count = 0;
|
||||
|
||||
var encoded = opusEncoder.encode(buff, 1920);
|
||||
var audioPacket = VoicePacket(encoded, sequence, timestamp, self.vWSData.ssrc);
|
||||
var length = 20;
|
||||
|
||||
var nextTime = startTime + cnt * 20;
|
||||
function send() {
|
||||
try {
|
||||
count++;
|
||||
sequence + 10 < 65535 ? sequence += 1 : sequence = 0;
|
||||
time + 9600 < 4294967295 ? time += 960 : time = 0;
|
||||
|
||||
self.sendBuffer(stream.read(1920), sequence, time, function (e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
var nextTime = startTime + count * length;
|
||||
|
||||
udpClient.send(audioPacket, 0, audioPacket.length, self.vWSData.port, self.endpoint, function (err) {});
|
||||
setTimeout(function () {
|
||||
sendAudio(sequence, timestamp, opusEncoder, wavOutput, udpClient, vWS);
|
||||
}, 20 + (nextTime - new Date().getTime()));
|
||||
} else {
|
||||
var speaking = {
|
||||
"op": 5,
|
||||
"d": {
|
||||
"speaking": false,
|
||||
"delay": 0
|
||||
}
|
||||
};
|
||||
vWS.send(JSON.stringify(speaking));
|
||||
}
|
||||
send();
|
||||
}, length + (nextTime - Date.now()));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
var speaking = {
|
||||
"op": 5,
|
||||
"d": {
|
||||
"speaking": true,
|
||||
"delay": 0
|
||||
self.vWS.send(JSON.stringify({
|
||||
op: 5,
|
||||
d: {
|
||||
speaking: true,
|
||||
delay: 0
|
||||
}
|
||||
};
|
||||
}));
|
||||
send();
|
||||
};
|
||||
|
||||
var vWS = self.vWS;
|
||||
var stream = fs.createReadStream("c:/users/amish/desktop/audio.wav");
|
||||
VoiceConnection.prototype.sendPacket = function sendPacket(packet) {
|
||||
var callback = arguments.length <= 1 || arguments[1] === undefined ? function (err) {} : arguments[1];
|
||||
|
||||
vWS.send(JSON.stringify(speaking));
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
try {
|
||||
self.udp.send(packet, 0, packet.length, self.vWSData.port, self.endpoint, callback);
|
||||
} catch (e) {
|
||||
self.playing = false;
|
||||
callback(e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var rate = 48000;
|
||||
var opusEncoder = new Opus.OpusEncoder(48000, 1);
|
||||
var wavReader = new Wav.Reader();
|
||||
wavReader.on('format', function (format) {
|
||||
console.log(format);
|
||||
});
|
||||
var wavOutput = stream.pipe(wavReader);
|
||||
|
||||
var sequence = 0;
|
||||
var timestamp = 0;
|
||||
|
||||
wavOutput.on('readable', function () {
|
||||
console.log("readable!");
|
||||
sendAudio(sequence, timestamp, opusEncoder, wavOutput, self.udp, vWS);
|
||||
VoiceConnection.prototype.sendBuffer = function sendBuffer(buffer, sequence, timestamp, callback) {
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
try {
|
||||
|
||||
var buffer = self.encoder.opusBuffer(buffer);
|
||||
var packet = new VoicePacket(buffer, sequence, timestamp, self.vWSData.ssrc);
|
||||
|
||||
return self.sendPacket(packet, callback);
|
||||
} catch (e) {
|
||||
self.playing = false;
|
||||
console.log("etype", e.stack);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
VoiceConnection.prototype.test = function test() {
|
||||
var self = this;
|
||||
this.encoder.encodeFile("C:/users/amish/desktop/audio.mp3")["catch"](error).then(function (stream) {
|
||||
|
||||
self.playRawStream(stream);
|
||||
});
|
||||
function error() {
|
||||
console.log("ERROR!");
|
||||
}
|
||||
};
|
||||
|
||||
VoiceConnection.prototype.init = function init() {
|
||||
|
||||
26
lib/Voice/VoicePacket.js
Normal file
26
lib/Voice/VoicePacket.js
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
module.exports = VoicePacket;
|
||||
48
src/Voice/AudioEncoder.js
Normal file
48
src/Voice/AudioEncoder.js
Normal file
@@ -0,0 +1,48 @@
|
||||
"use strict";
|
||||
|
||||
var cpoc = require("child_process");
|
||||
var opus = require("node-opus");
|
||||
var VoicePacket = require("./VoicePacket.js");
|
||||
|
||||
class AudioEncoder{
|
||||
constructor(){
|
||||
this.opus = new opus.OpusEncoder(48000, 1);
|
||||
}
|
||||
|
||||
opusBuffer(buffer){
|
||||
|
||||
return this.opus.encode(buffer, 1920);
|
||||
|
||||
}
|
||||
|
||||
encodeFile(file, 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",
|
||||
"-af", "volume=1",
|
||||
"pipe:1"
|
||||
]);
|
||||
|
||||
enc.stdout.on("readable", function() {
|
||||
callback(null, enc.stdout);
|
||||
resolve(enc.stdout)
|
||||
});
|
||||
|
||||
enc.stdout.on("end", function() {
|
||||
callback("end");
|
||||
reject("end");
|
||||
});
|
||||
|
||||
enc.stdout.on("close", function() {
|
||||
callback("close");
|
||||
reject("close");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AudioEncoder;
|
||||
@@ -7,23 +7,9 @@ var Lame = require("lame");
|
||||
var Opus = require('node-opus');
|
||||
var Wav = require('wav');
|
||||
var fs = require("fs");
|
||||
|
||||
function VoicePacket(packet, sequence, timestamp, ssrc) {
|
||||
var audioBuffer = packet;
|
||||
var retBuff = new Buffer(audioBuffer.length + 12);
|
||||
retBuff.fill(0);
|
||||
retBuff[0] = 0x80;
|
||||
retBuff[1] = 0x78;
|
||||
retBuff.writeUIntBE(sequence, 2, 2);
|
||||
retBuff.writeUIntBE(timestamp, 4, 4);
|
||||
retBuff.writeUIntBE(ssrc, 8, 4);
|
||||
|
||||
for (var i = 0; i < audioBuffer.length; i++) {
|
||||
retBuff[i + 12] = audioBuffer[i];
|
||||
}
|
||||
|
||||
return retBuff;
|
||||
}
|
||||
var ffmpeg = require('fluent-ffmpeg');
|
||||
var AudioEncoder = require("./AudioEncoder.js");
|
||||
var VoicePacket = require("./VoicePacket.js");
|
||||
|
||||
class VoiceConnection {
|
||||
constructor(channel, client, session, token, server, endpoint) {
|
||||
@@ -36,71 +22,100 @@ class VoiceConnection {
|
||||
this.vWS = null; // vWS means voice websocket
|
||||
this.ready = false;
|
||||
this.vWSData = {};
|
||||
this.opus = new Opus.OpusEncoder(48000, 1);
|
||||
this.encoder = new AudioEncoder();
|
||||
this.udp = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
playRawStream(stream){
|
||||
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
|
||||
var startTime = Date.now();
|
||||
var sequence = 0;
|
||||
var time = 0;
|
||||
var count = 0;
|
||||
|
||||
var length = 20;
|
||||
|
||||
function send(){
|
||||
try{
|
||||
count++;
|
||||
sequence + 10 < 65535 ? sequence += 1 : sequence = 0;
|
||||
time + 9600 < 4294967295 ? time += 960 : time = 0;
|
||||
|
||||
self.sendBuffer(stream.read(1920), sequence, time, (e) => {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
var nextTime = startTime + (count * length);
|
||||
|
||||
setTimeout(function() {
|
||||
send();
|
||||
}, length + (nextTime - Date.now()));
|
||||
|
||||
}catch(e){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
self.vWS.send(JSON.stringify({
|
||||
op : 5,
|
||||
d : {
|
||||
speaking : true,
|
||||
delay : 0
|
||||
}
|
||||
}));
|
||||
send();
|
||||
|
||||
|
||||
}
|
||||
|
||||
sendPacket(packet, callback=function(err){}){
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
try{
|
||||
self.udp.send(packet, 0, packet.length, self.vWSData.port, self.endpoint, callback);
|
||||
|
||||
}catch(e){
|
||||
self.playing = false;
|
||||
callback(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sendBuffer(buffer, sequence, timestamp, callback){
|
||||
var self = this;
|
||||
self.playing = true;
|
||||
try{
|
||||
|
||||
var buffer = self.encoder.opusBuffer(buffer);
|
||||
var packet = new VoicePacket(buffer, sequence, timestamp, self.vWSData.ssrc);
|
||||
|
||||
return self.sendPacket(packet, callback);
|
||||
|
||||
}catch(e){
|
||||
self.playing = false;
|
||||
console.log("etype", e.stack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
test() {
|
||||
var self = this;
|
||||
var startTime = Date.now();
|
||||
var cnt = 0;
|
||||
function sendAudio(sequence, timestamp, opusEncoder, wavOutput, udpClient, vWS) {
|
||||
cnt++;
|
||||
var buff = wavOutput.read(1920);
|
||||
if (buff && buff.length === 1920) {
|
||||
sequence + 20 < 65535 ? sequence += 1 : sequence = 0;
|
||||
timestamp + 9600 < 4294967295 ? timestamp += 960 : timestamp = 0;
|
||||
|
||||
var encoded = opusEncoder.encode(buff, 1920);
|
||||
var audioPacket = VoicePacket(encoded, sequence, timestamp, self.vWSData.ssrc);
|
||||
|
||||
var nextTime = startTime + cnt * 20;
|
||||
|
||||
udpClient.send(audioPacket, 0, audioPacket.length, self.vWSData.port, self.endpoint, function (err) { });
|
||||
setTimeout(function () {
|
||||
sendAudio(sequence, timestamp, opusEncoder, wavOutput, udpClient, vWS);
|
||||
}, 20 + (nextTime - new Date().getTime()));
|
||||
} else {
|
||||
var speaking = {
|
||||
"op": 5,
|
||||
"d": {
|
||||
"speaking": false,
|
||||
"delay": 0
|
||||
}
|
||||
}
|
||||
vWS.send(JSON.stringify(speaking));
|
||||
}
|
||||
this.encoder
|
||||
.encodeFile("C:/users/amish/desktop/audio.mp3")
|
||||
.catch(error)
|
||||
.then( stream => {
|
||||
|
||||
self.playRawStream(stream);
|
||||
|
||||
} );
|
||||
function error(){
|
||||
console.log("ERROR!");
|
||||
}
|
||||
|
||||
var speaking = {
|
||||
"op": 5,
|
||||
"d": {
|
||||
"speaking": true,
|
||||
"delay": 0
|
||||
}
|
||||
}
|
||||
|
||||
var vWS = self.vWS;
|
||||
var stream = fs.createReadStream("c:/users/amish/desktop/audio.wav");
|
||||
|
||||
vWS.send(JSON.stringify(speaking));
|
||||
|
||||
var rate = 48000;
|
||||
var opusEncoder = new Opus.OpusEncoder(48000, 1);
|
||||
var wavReader = new Wav.Reader();
|
||||
wavReader.on('format', function (format) {
|
||||
console.log(format);
|
||||
});
|
||||
var wavOutput = stream.pipe(wavReader);
|
||||
|
||||
var sequence = 0;
|
||||
var timestamp = 0;
|
||||
|
||||
wavOutput.on('readable', function () {
|
||||
console.log("readable!");
|
||||
sendAudio(sequence, timestamp, opusEncoder, wavOutput, self.udp, vWS);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
26
src/Voice/VoicePacket.js
Normal file
26
src/Voice/VoicePacket.js
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
|
||||
class VoicePacket{
|
||||
constructor(data, sequence, time, ssrc){
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VoicePacket;
|
||||
Reference in New Issue
Block a user