mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-09 16:13:31 +01:00
get voice sort of working
This commit is contained in:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
41
src/client/voice/player/AudioPlayer.js
Normal file
41
src/client/voice/player/AudioPlayer.js
Normal 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;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user