get voice sort of working

This commit is contained in:
Amish Shah
2016-10-24 14:26:24 +01:00
parent 9b3dd540ef
commit e13e2447d4
8 changed files with 81 additions and 15 deletions

View File

@@ -241,7 +241,7 @@ class ClientVoiceManager {
pendingConnection.on('pass', voiceConnection => {
this.pending.delete(channel.guild.id);
this.connections.set(channel.guild.id, voiceConnection);
voiceConnection.once('ready', resolve);
voiceConnection.once('ready', () => resolve(voiceConnection));
voiceConnection.once('error', reject);
});
});

View File

@@ -2,8 +2,8 @@ const VoiceWebSocket = require('./VoiceWebSocket');
const VoiceUDP = require('./VoiceUDPClient');
const VoiceReceiver = require('./receiver/VoiceReceiver');
const Constants = require('../../util/Constants');
const AudioPlayer = require('./player/AudioPlayer');
const EventEmitter = require('events').EventEmitter;
const DefaultPlayer = require('./player/DefaultPlayer');
/**
* Represents a connection to a Voice Channel in Discord.
@@ -37,6 +37,8 @@ class VoiceConnection extends EventEmitter {
*/
this.authentication = pendingConnection.data;
this.player = new AudioPlayer(this);
/**
* Object that wraps contains the `ws` and `udp` sockets of this voice connection
* @type {object}
@@ -45,6 +47,18 @@ class VoiceConnection extends EventEmitter {
this.connect();
}
setSpeaking(value) {
if (this.speaking === value) return;
this.speaking = value;
this.sockets.ws.sendPacket({
op: Constants.VoiceOPCodes.SPEAKING,
d: {
speaking: true,
delay: 0,
},
});
}
connect() {
if (this.sockets.ws) {
throw new Error('There is already an existing WebSocket connection!');
@@ -58,6 +72,7 @@ class VoiceConnection extends EventEmitter {
this.sockets.udp.on('error', e => this.emit('error', e));
this.sockets.ws.once('ready', d => {
this.authentication.port = d.port;
this.authentication.ssrc = d.ssrc;
this.sockets.udp.findEndpointAddress()
.then(address => {
this.sockets.udp.createUDPSocket(address);

View File

@@ -87,6 +87,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
reject(new Error('malformed UDP address or port'));
return;
}
// console.log('sendin', packet);
this.socket.send(packet, 0, packet.length, this.discordPort, this.discordAddress, error => {
if (error) {
reject(error);

View File

@@ -77,6 +77,7 @@ class VoiceWebSocket extends EventEmitter {
send(data) {
return new Promise((resolve, reject) => {
if (this.ws.readyState === WebSocket.OPEN) {
console.log('sending', data);
this.ws.send(data, null, error => {
if (error) {
reject(error);

View File

@@ -132,7 +132,7 @@ class StreamDispatcher extends EventEmitter {
_sendBuffer(buffer, sequence, timestamp) {
let repeats = this.passes;
const packet = this._createPacket(sequence, timestamp, this.player.opusEncoder.encode(buffer));
while (repeats--) this.player.connection.udp.send(packet);
while (repeats--) this.player.voiceConnection.sockets.udp.send(packet);
}
_createPacket(sequence, timestamp, buffer) {
@@ -143,10 +143,10 @@ class StreamDispatcher extends EventEmitter {
packetBuffer.writeUIntBE(sequence, 2, 2);
packetBuffer.writeUIntBE(timestamp, 4, 4);
packetBuffer.writeUIntBE(this.player.connection.data.ssrc, 8, 4);
packetBuffer.writeUIntBE(this.player.voiceConnection.authentication.ssrc, 8, 4);
packetBuffer.copy(nonce, 0, 0, 12);
buffer = NaCl.secretbox(buffer, nonce, this.player.connection.data.secret);
buffer = NaCl.secretbox(buffer, nonce, this.player.voiceConnection.authentication.secretKey.key);
for (let i = 0; i < buffer.length; i++) packetBuffer[i + 12] = buffer[i];
@@ -183,7 +183,7 @@ class StreamDispatcher extends EventEmitter {
if (this.paused) {
// data.timestamp = data.timestamp + 4294967295 ? data.timestamp + 960 : 0;
data.pausedTime += data.length * 10;
this.player.connection.manager.client.setTimeout(() => this._send(), data.length * 10);
this.player.voiceConnection.voiceManager.client.setTimeout(() => this._send(), data.length * 10);
return;
}
@@ -203,7 +203,7 @@ class StreamDispatcher extends EventEmitter {
if (!buffer) {
data.missed++;
data.pausedTime += data.length * 10;
this.player.connection.manager.client.setTimeout(() => this._send(), data.length * 10);
this.player.voiceConnection.voiceManager.client.setTimeout(() => this._send(), data.length * 10);
return;
}
@@ -224,7 +224,8 @@ class StreamDispatcher extends EventEmitter {
this._sendBuffer(buffer, data.sequence, data.timestamp);
const nextTime = data.length + (data.startTime + data.pausedTime + (data.count * data.length) - Date.now());
this.player.connection.manager.client.setTimeout(() => this._send(), nextTime);
console.log('again! in', nextTime);
this.player.voiceConnection.voiceManager.client.setTimeout(() => this._send(), nextTime);
} catch (e) {
this._triggerTerminalState('error', e);
}
@@ -250,7 +251,7 @@ class StreamDispatcher extends EventEmitter {
_triggerTerminalState(state, err) {
if (this._triggered) return;
console.log(state, err);
/**
* Emitted when the stream wants to give debug information.
* @event StreamDispatcher#debug

View File

@@ -1,5 +1,16 @@
const ConverterEngine = require('./ConverterEngine');
const ChildProcess = require('child_process');
const EventEmitter = require('events').EventEmitter;
class PCMConversionProcess extends EventEmitter {
constructor(process) {
super();
this.process = process;
this.process.on('error', e => this.emit('error', e));
}
}
class FfmpegConverterEngine extends ConverterEngine {
constructor(player) {
@@ -24,10 +35,7 @@ class FfmpegConverterEngine extends ConverterEngine {
'-ss', String(seek),
'pipe:1',
], { stdio: ['pipe', 'pipe', 'ignore'] });
encoder.on('error', e => this.handleError(encoder, e));
encoder.stdin.on('error', e => this.handleError(encoder, e));
encoder.stdout.on('error', e => this.handleError(encoder, e));
return encoder;
return new PCMConversionProcess(encoder);
}
}

View File

@@ -0,0 +1,41 @@
const PCMConverters = require('../pcm/ConverterEngineList');
const OpusEncoders = require('../opus/OpusEngineList');
const EventEmitter = require('events').EventEmitter;
const StreamDispatcher = require('../dispatcher/StreamDispatcher');
class AudioPlayer extends EventEmitter {
constructor(voiceConnection) {
super();
this.voiceConnection = voiceConnection;
this.audioToPCM = new (PCMConverters.fetch())();
this.opusEncoder = OpusEncoders.fetch();
this.audioToPCM.on('error', e => this.emit('error', e));
}
playUnknownStream(stream) {
const conversionProcess = this.audioToPCM.createConvertStream(0);
stream.pipe(conversionProcess.process.stdin, { end: false });
return this.playPCMStream(conversionProcess.process.stdout);
}
playPCMStream(stream) {
stream.on('error', e => this.emit('error', e));
const dispatcher = new StreamDispatcher(this, stream, {
channels: 2,
count: 0,
sequence: 0,
timestamp: 0,
pausedTime: 0,
}, {
volume: 1,
});
dispatcher.on('error', e => console.log('error', e));
dispatcher.on('end', e => console.log('end', e));
dispatcher.on('speaking', value => this.voiceConnection.setSpeaking(value));
}
}
module.exports = AudioPlayer;

View File

@@ -168,10 +168,9 @@ client.on('message', msg => {
.then(conn => {
con = conn;
msg.reply('done');
disp = conn.player.playStream(ytdl('https://www.youtube.com/watch?v=oQBiPwklN_Q', {filter : 'audioonly'}), { passes : 3 });
disp = conn.player.playUnknownStream(fs.createReadStream('C:/Users/Amish/Desktop/04 Out of the Woods.m4a'), { passes : 3 });
conn.player.on('debug', console.log);
conn.player.on('error', err => console.log(123, err));
disp.on('error', err => console.log(123, err));
})
.catch(console.error);
}