diff --git a/docs/topics/voice.md b/docs/topics/voice.md index 22f5c93de366..6a39f5a3f8b9 100644 --- a/docs/topics/voice.md +++ b/docs/topics/voice.md @@ -70,10 +70,13 @@ We can also pass in options when we first play the stream: ```js const dispatcher = connection.play('/home/discord/audio.mp3', { - volume: 0.5 + volume: 0.5, + passes: 3 }); ``` +These are just a subset of the options available (consult documentation for a full list). Most users may be interested in the `passes` option, however. As audio is sent over UDP, there is a chance packets may not arrive. Increasing the number of passes, e.g. to `3` gives you a better chance that your packets reach your recipients, at the cost of triple the bandwidth. We recommend not going over 5 passes. + ### What can I play? Discord.js allows you to play a lot of things: diff --git a/src/client/voice/dispatcher/StreamDispatcher.js b/src/client/voice/dispatcher/StreamDispatcher.js index 2923eb61e387..0a3f5220ae92 100644 --- a/src/client/voice/dispatcher/StreamDispatcher.js +++ b/src/client/voice/dispatcher/StreamDispatcher.js @@ -33,9 +33,9 @@ const nonce = Buffer.alloc(24); class StreamDispatcher extends Writable { constructor( player, - { seek = 0, volume = 1, fec, plp, bitrate = 96, highWaterMark = 12 } = {}, + { seek = 0, volume = 1, passes = 1, fec, plp, bitrate = 96, highWaterMark = 12 } = {}, streams) { - const streamOptions = { seek, volume, fec, plp, bitrate, highWaterMark }; + const streamOptions = { seek, volume, passes, fec, plp, bitrate, highWaterMark }; super(streamOptions); /** * The Audio Player that controls this dispatcher @@ -289,21 +289,24 @@ class StreamDispatcher extends Writable { } _sendPacket(packet) { + let repeats = this.streamOptions.passes; /** * Emitted whenever the dispatcher has debug information. * @event StreamDispatcher#debug * @param {string} info The debug info */ this._setSpeaking(1); - if (!this.player.voiceConnection.sockets.udp) { - this.emit('debug', 'Failed to send a packet - no UDP socket'); - return; + while (repeats--) { + if (!this.player.voiceConnection.sockets.udp) { + this.emit('debug', 'Failed to send a packet - no UDP socket'); + return; + } + this.player.voiceConnection.sockets.udp.send(packet) + .catch(e => { + this._setSpeaking(0); + this.emit('debug', `Failed to send a packet - ${e}`); + }); } - this.player.voiceConnection.sockets.udp.send(packet) - .catch(e => { - this._setSpeaking(0); - this.emit('debug', `Failed to send a packet - ${e}`); - }); } _setSpeaking(value) { diff --git a/src/client/voice/util/PlayInterface.js b/src/client/voice/util/PlayInterface.js index 6f1ba018ff16..873cd81e9435 100644 --- a/src/client/voice/util/PlayInterface.js +++ b/src/client/voice/util/PlayInterface.js @@ -11,6 +11,7 @@ const { Error } = require('../../../errors'); * @property {number} [seek=0] The time to seek to, will be ignored when playing `ogg/opus` or `webm/opus` streams * @property {number|boolean} [volume=1] The volume to play at. Set this to false to disable volume transforms for * this stream to improve performance. + * @property {number} [passes=1] How many times to send the voice packet to reduce packet loss * @property {number} [plp] Expected packet loss percentage * @property {boolean} [fec] Enabled forward error correction * @property {number|string} [bitrate=96] The bitrate (quality) of the audio in kbps. diff --git a/typings/index.d.ts b/typings/index.d.ts index c6a69c9118ac..72ee1e893010 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -2514,6 +2514,7 @@ declare module 'discord.js' { type?: StreamType; seek?: number; volume?: number | boolean; + passes?: number; plp?: number; fec?: boolean; bitrate?: number | 'auto';