diff --git a/src/client/voice/VoiceBroadcast.js b/src/client/voice/VoiceBroadcast.js index 92bbb414f..820902b53 100644 --- a/src/client/voice/VoiceBroadcast.js +++ b/src/client/voice/VoiceBroadcast.js @@ -267,38 +267,59 @@ class VoiceBroadcast extends EventEmitter { * Pauses the entire broadcast - all dispatchers also pause */ pause() { + this.paused = true; for (const container of this._dispatchers.values()) { for (const dispatcher of container.values()) { dispatcher.pause(); } } - clearInterval(this.tickInterval); } /** * Resumes the entire broadcast - all dispatchers also resume */ resume() { + this.paused = false; for (const container of this._dispatchers.values()) { for (const dispatcher of container.values()) { dispatcher.resume(); } } - this._startPlaying(); } _startPlaying() { if (this.tickInterval) clearInterval(this.tickInterval); - this.tickInterval = this.client.setInterval(this.tick.bind(this), 20); + // this.tickInterval = this.client.setInterval(this.tick.bind(this), 20); + this._startTime = Date.now(); + this._count = 0; + this._pausedTime = 0; + this._missed = 0; + this.tick(); } tick() { if (!this._playableStream) return; + if (this.paused) { + this._pausedTime += 20; + setTimeout(() => this.tick(), 20); + return; + } const stream = this._playableStream; const bufferLength = 1920 * 2; let buffer = stream.read(bufferLength); - if (!buffer) return; + if (!buffer) { + this._missed++; + if (this._missed < 5) { + this._pausedTime += 200; + setTimeout(() => this.tick(), 200); + } else { + this.end(); + } + return; + } + + this._missed = 0; if (buffer.length !== bufferLength) { const newBuffer = new Buffer(bufferLength).fill(0); @@ -309,14 +330,15 @@ class VoiceBroadcast extends EventEmitter { buffer = this.applyVolume(buffer); for (const x of this._dispatchers.entries()) { - setImmediate(() => { - const [volume, container] = x; - const opusPacket = this.opusEncoder.encode(this.applyVolume(buffer, volume)); - for (const dispatcher of container.values()) { - setImmediate(() => dispatcher.process(buffer, true, opusPacket)); - } - }); + const [volume, container] = x; + const opusPacket = this.opusEncoder.encode(this.applyVolume(buffer, volume)); + for (const dispatcher of container.values()) { + dispatcher.process(buffer, true, opusPacket); + } } + const next = 20 + (this._startTime + this._pausedTime + (this._count * 20) - Date.now()); + this._count++; + setTimeout(() => this.tick(), next); } /** diff --git a/src/client/voice/dispatcher/StreamDispatcher.js b/src/client/voice/dispatcher/StreamDispatcher.js index 5b14b88be..a2d15046c 100644 --- a/src/client/voice/dispatcher/StreamDispatcher.js +++ b/src/client/voice/dispatcher/StreamDispatcher.js @@ -158,13 +158,18 @@ class StreamDispatcher extends EventEmitter { sendBuffer(buffer, sequence, timestamp, opusPacket) { opusPacket = opusPacket || this.player.opusEncoder.encode(buffer); - let repeats = this.passes; const packet = this.createPacket(sequence, timestamp, opusPacket); + this.sendPacket(packet); + } + + sendPacket(packet) { + let repeats = this.passes; /** * Emitted whenever the dispatcher has debug information * @event StreamDispatcher#debug * @param {string} info the debug info */ + this.setSpeaking(true); while (repeats--) { this.player.voiceConnection.sockets.udp.send(packet) .catch(e => this.emit('debug', `Failed to send a packet ${e}`)); @@ -183,7 +188,6 @@ class StreamDispatcher extends EventEmitter { packetBuffer.copy(nonce, 0, 0, 12); buffer = NaCl.secretbox(buffer, nonce, this.player.voiceConnection.authentication.secretKey.key); - for (let i = 0; i < buffer.length; i++) packetBuffer[i + 12] = buffer[i]; return packetBuffer; @@ -231,8 +235,6 @@ class StreamDispatcher extends EventEmitter { return; } - this.setSpeaking(true); - if (!data.startTime) { /** * Emitted once the dispatcher starts streaming diff --git a/test/voice.js b/test/voice.js index 5a6ad1657..396bcc490 100644 --- a/test/voice.js +++ b/test/voice.js @@ -41,6 +41,13 @@ client.on('message', m => { } doQueue(connData); } + } else if (m.content.startsWith('/skip')) { + if (connections.has(m.guild.id)) { + const connData = connections.get(m.guild.id); + if (connData.dispatcher) { + connData.dispatcher.end(); + } + } } else if (m.content.startsWith('#eval') && m.author.id === '66564597481480192') { try { const com = eval(m.content.split(' ').slice(1).join(' ')); @@ -67,4 +74,5 @@ function doQueue(connData) { doQueue(connData); }); dispatcher.on('error', (...e) => console.log('dispatcher', ...e)); + connData.dispatcher = dispatcher; }