mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 02:53:31 +01:00
voice: allow for streaming silence to avoid audio glitches with repeated pausing/resuming (#2354)
This commit is contained in:
@@ -2,6 +2,7 @@ const VolumeInterface = require('../util/VolumeInterface');
|
|||||||
const { Writable } = require('stream');
|
const { Writable } = require('stream');
|
||||||
|
|
||||||
const secretbox = require('../util/Secretbox');
|
const secretbox = require('../util/Secretbox');
|
||||||
|
const Silence = require('../util/Silence');
|
||||||
|
|
||||||
const FRAME_LENGTH = 20;
|
const FRAME_LENGTH = 20;
|
||||||
const CHANNELS = 2;
|
const CHANNELS = 2;
|
||||||
@@ -41,6 +42,7 @@ class StreamDispatcher extends Writable {
|
|||||||
this.player = player;
|
this.player = player;
|
||||||
this.streamOptions = streamOptions;
|
this.streamOptions = streamOptions;
|
||||||
this.streams = streams;
|
this.streams = streams;
|
||||||
|
this.streams.silence = new Silence();
|
||||||
|
|
||||||
this._nonce = 0;
|
this._nonce = 0;
|
||||||
this._nonceBuffer = Buffer.alloc(24);
|
this._nonceBuffer = Buffer.alloc(24);
|
||||||
@@ -59,6 +61,7 @@ class StreamDispatcher extends Writable {
|
|||||||
this.broadcast = this.streams.broadcast;
|
this.broadcast = this.streams.broadcast;
|
||||||
|
|
||||||
this._pausedTime = 0;
|
this._pausedTime = 0;
|
||||||
|
this._silentPausedTime = 0;
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
|
|
||||||
this.on('finish', () => {
|
this.on('finish', () => {
|
||||||
@@ -119,12 +122,17 @@ class StreamDispatcher extends Writable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses playback
|
* Pauses playback
|
||||||
|
* @param {boolean} [silence=false] Whether to play silence while paused to prevent audio glitches
|
||||||
*/
|
*/
|
||||||
pause() {
|
pause(silence = false) {
|
||||||
if (this.paused) return;
|
if (this.paused) return;
|
||||||
if (this.streams.opus) this.streams.opus.unpipe(this);
|
if (this.streams.opus) this.streams.opus.unpipe(this);
|
||||||
if (this._writeCallback) this._writeCallback();
|
if (silence) {
|
||||||
this._setSpeaking(false);
|
this.streams.silence.pipe(this);
|
||||||
|
this._silence = true;
|
||||||
|
} else {
|
||||||
|
this._setSpeaking(false);
|
||||||
|
}
|
||||||
this.pausedSince = Date.now();
|
this.pausedSince = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,15 +146,23 @@ class StreamDispatcher extends Writable {
|
|||||||
* Total time that this dispatcher has been paused
|
* Total time that this dispatcher has been paused
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
get pausedTime() { return this._pausedTime + (this.paused ? Date.now() - this.pausedSince : 0); }
|
get pausedTime() {
|
||||||
|
return this._silentPausedTime + this._pausedTime + (this.paused ? Date.now() - this.pausedSince : 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumes playback
|
* Resumes playback
|
||||||
*/
|
*/
|
||||||
resume() {
|
resume() {
|
||||||
if (!this.pausedSince) return;
|
if (!this.pausedSince) return;
|
||||||
|
this.streams.silence.unpipe(this);
|
||||||
if (this.streams.opus) this.streams.opus.pipe(this);
|
if (this.streams.opus) this.streams.opus.pipe(this);
|
||||||
this._pausedTime += Date.now() - this.pausedSince;
|
if (this._silence) {
|
||||||
|
this._silentPausedTime += Date.now() - this.pausedSince;
|
||||||
|
this._silence = false;
|
||||||
|
} else {
|
||||||
|
this._pausedTime += Date.now() - this.pausedSince;
|
||||||
|
}
|
||||||
this.pausedSince = null;
|
this.pausedSince = null;
|
||||||
if (typeof this._writeCallback === 'function') this._writeCallback();
|
if (typeof this._writeCallback === 'function') this._writeCallback();
|
||||||
}
|
}
|
||||||
@@ -207,11 +223,10 @@ class StreamDispatcher extends Writable {
|
|||||||
this._writeCallback = null;
|
this._writeCallback = null;
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
if (this.pausedSince) return;
|
|
||||||
if (!this.streams.broadcast) {
|
if (!this.streams.broadcast) {
|
||||||
const next = FRAME_LENGTH + (this.count * FRAME_LENGTH) - (Date.now() - this.startTime - this.pausedTime);
|
const next = FRAME_LENGTH + (this.count * FRAME_LENGTH) - (Date.now() - this.startTime - this._pausedTime);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.pausedSince && this._writeCallback) this._writeCallback();
|
if ((!this.pausedSince || this._silence) && this._writeCallback) this._writeCallback();
|
||||||
}, next);
|
}, next);
|
||||||
}
|
}
|
||||||
this._sdata.sequence++;
|
this._sdata.sequence++;
|
||||||
|
|||||||
11
src/client/voice/util/Silence.js
Normal file
11
src/client/voice/util/Silence.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const { Readable } = require('stream');
|
||||||
|
|
||||||
|
const SILENCE_FRAME = Buffer.from([0xF8, 0xFF, 0xFE]);
|
||||||
|
|
||||||
|
class Silence extends Readable {
|
||||||
|
_read() {
|
||||||
|
this.push(SILENCE_FRAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Silence;
|
||||||
Reference in New Issue
Block a user