mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 11:03:30 +01:00
get voice sort of working
This commit is contained in:
@@ -241,7 +241,7 @@ class ClientVoiceManager {
|
|||||||
pendingConnection.on('pass', voiceConnection => {
|
pendingConnection.on('pass', voiceConnection => {
|
||||||
this.pending.delete(channel.guild.id);
|
this.pending.delete(channel.guild.id);
|
||||||
this.connections.set(channel.guild.id, voiceConnection);
|
this.connections.set(channel.guild.id, voiceConnection);
|
||||||
voiceConnection.once('ready', resolve);
|
voiceConnection.once('ready', () => resolve(voiceConnection));
|
||||||
voiceConnection.once('error', reject);
|
voiceConnection.once('error', reject);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ const VoiceWebSocket = require('./VoiceWebSocket');
|
|||||||
const VoiceUDP = require('./VoiceUDPClient');
|
const VoiceUDP = require('./VoiceUDPClient');
|
||||||
const VoiceReceiver = require('./receiver/VoiceReceiver');
|
const VoiceReceiver = require('./receiver/VoiceReceiver');
|
||||||
const Constants = require('../../util/Constants');
|
const Constants = require('../../util/Constants');
|
||||||
|
const AudioPlayer = require('./player/AudioPlayer');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const DefaultPlayer = require('./player/DefaultPlayer');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a connection to a Voice Channel in Discord.
|
* Represents a connection to a Voice Channel in Discord.
|
||||||
@@ -37,6 +37,8 @@ class VoiceConnection extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
this.authentication = pendingConnection.data;
|
this.authentication = pendingConnection.data;
|
||||||
|
|
||||||
|
this.player = new AudioPlayer(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that wraps contains the `ws` and `udp` sockets of this voice connection
|
* Object that wraps contains the `ws` and `udp` sockets of this voice connection
|
||||||
* @type {object}
|
* @type {object}
|
||||||
@@ -45,6 +47,18 @@ class VoiceConnection extends EventEmitter {
|
|||||||
this.connect();
|
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() {
|
connect() {
|
||||||
if (this.sockets.ws) {
|
if (this.sockets.ws) {
|
||||||
throw new Error('There is already an existing WebSocket connection!');
|
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.udp.on('error', e => this.emit('error', e));
|
||||||
this.sockets.ws.once('ready', d => {
|
this.sockets.ws.once('ready', d => {
|
||||||
this.authentication.port = d.port;
|
this.authentication.port = d.port;
|
||||||
|
this.authentication.ssrc = d.ssrc;
|
||||||
this.sockets.udp.findEndpointAddress()
|
this.sockets.udp.findEndpointAddress()
|
||||||
.then(address => {
|
.then(address => {
|
||||||
this.sockets.udp.createUDPSocket(address);
|
this.sockets.udp.createUDPSocket(address);
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class VoiceConnectionUDPClient extends EventEmitter {
|
|||||||
reject(new Error('malformed UDP address or port'));
|
reject(new Error('malformed UDP address or port'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// console.log('sendin', packet);
|
||||||
this.socket.send(packet, 0, packet.length, this.discordPort, this.discordAddress, error => {
|
this.socket.send(packet, 0, packet.length, this.discordPort, this.discordAddress, error => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ class VoiceWebSocket extends EventEmitter {
|
|||||||
send(data) {
|
send(data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
console.log('sending', data);
|
||||||
this.ws.send(data, null, error => {
|
this.ws.send(data, null, error => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
_sendBuffer(buffer, sequence, timestamp) {
|
_sendBuffer(buffer, sequence, timestamp) {
|
||||||
let repeats = this.passes;
|
let repeats = this.passes;
|
||||||
const packet = this._createPacket(sequence, timestamp, this.player.opusEncoder.encode(buffer));
|
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) {
|
_createPacket(sequence, timestamp, buffer) {
|
||||||
@@ -143,10 +143,10 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
|
|
||||||
packetBuffer.writeUIntBE(sequence, 2, 2);
|
packetBuffer.writeUIntBE(sequence, 2, 2);
|
||||||
packetBuffer.writeUIntBE(timestamp, 4, 4);
|
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);
|
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];
|
for (let i = 0; i < buffer.length; i++) packetBuffer[i + 12] = buffer[i];
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
if (this.paused) {
|
if (this.paused) {
|
||||||
// data.timestamp = data.timestamp + 4294967295 ? data.timestamp + 960 : 0;
|
// data.timestamp = data.timestamp + 4294967295 ? data.timestamp + 960 : 0;
|
||||||
data.pausedTime += data.length * 10;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
data.missed++;
|
data.missed++;
|
||||||
data.pausedTime += data.length * 10;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +224,8 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
this._sendBuffer(buffer, data.sequence, data.timestamp);
|
this._sendBuffer(buffer, data.sequence, data.timestamp);
|
||||||
|
|
||||||
const nextTime = data.length + (data.startTime + data.pausedTime + (data.count * data.length) - Date.now());
|
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) {
|
} catch (e) {
|
||||||
this._triggerTerminalState('error', e);
|
this._triggerTerminalState('error', e);
|
||||||
}
|
}
|
||||||
@@ -250,7 +251,7 @@ class StreamDispatcher extends EventEmitter {
|
|||||||
|
|
||||||
_triggerTerminalState(state, err) {
|
_triggerTerminalState(state, err) {
|
||||||
if (this._triggered) return;
|
if (this._triggered) return;
|
||||||
|
console.log(state, err);
|
||||||
/**
|
/**
|
||||||
* Emitted when the stream wants to give debug information.
|
* Emitted when the stream wants to give debug information.
|
||||||
* @event StreamDispatcher#debug
|
* @event StreamDispatcher#debug
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
const ConverterEngine = require('./ConverterEngine');
|
const ConverterEngine = require('./ConverterEngine');
|
||||||
const ChildProcess = require('child_process');
|
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 {
|
class FfmpegConverterEngine extends ConverterEngine {
|
||||||
constructor(player) {
|
constructor(player) {
|
||||||
@@ -24,10 +35,7 @@ class FfmpegConverterEngine extends ConverterEngine {
|
|||||||
'-ss', String(seek),
|
'-ss', String(seek),
|
||||||
'pipe:1',
|
'pipe:1',
|
||||||
], { stdio: ['pipe', 'pipe', 'ignore'] });
|
], { stdio: ['pipe', 'pipe', 'ignore'] });
|
||||||
encoder.on('error', e => this.handleError(encoder, e));
|
return new PCMConversionProcess(encoder);
|
||||||
encoder.stdin.on('error', e => this.handleError(encoder, e));
|
|
||||||
encoder.stdout.on('error', e => this.handleError(encoder, e));
|
|
||||||
return 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 => {
|
.then(conn => {
|
||||||
con = conn;
|
con = conn;
|
||||||
msg.reply('done');
|
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('debug', console.log);
|
||||||
conn.player.on('error', err => console.log(123, err));
|
conn.player.on('error', err => console.log(123, err));
|
||||||
disp.on('error', err => console.log(123, err));
|
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user