shadowsb
Version:
A unofficial discord.js fork for creating selfbots [Based on discord.js v13] (discord.js-selfbot-v13) for true version
146 lines (124 loc) • 4.17 kB
JavaScript
'use strict';
const BaseDispatcher = require('./BaseDispatcher');
const Util = require('../../../util/Util');
const Silence = require('../util/Silence');
const VolumeInterface = require('../util/VolumeInterface');
const CHANNELS = 2;
/**
* @external WritableStream
* @see {@link https://nodejs.org/api/stream.html#stream_class_stream_writable}
*/
/**
* The class that sends voice packet data to the voice connection.
* ```js
* // Obtained using:
* client.voice.joinChannel(channel).then(connection => {
* // You can play a file or a stream here:
* const dispatcher = connection.playAudio('/home/hydrabolt/audio.mp3');
* });
* ```
* @implements {VolumeInterface}
* @extends {BaseDispatcher}
*/
class AudioDispatcher extends BaseDispatcher {
constructor(player, { seek = 0, volume = 1, fec, plp, bitrate = 96, highWaterMark = 12 } = {}, streams) {
const streamOptions = { seek, volume, fec, plp, bitrate, highWaterMark };
super(player, highWaterMark, Util.getPayloadType('opus'), false, streams);
this.streamOptions = streamOptions;
this.streams.silence = new Silence();
this.setVolume(volume);
this.setBitrate(bitrate);
if (typeof fec !== 'undefined') this.setFEC(fec);
if (typeof plp !== 'undefined') this.setPLP(plp);
}
get TIMESTAMP_INC() {
return 480 * CHANNELS;
}
get FRAME_LENGTH() {
return 20;
}
/**
* Get the type of the dispatcher
* @returns {'audio'}
*/
getTypeDispatcher() {
return 'audio';
}
/**
* Set the bitrate of the current Opus encoder if using a compatible Opus stream.
* @param {number} value New bitrate, in kbps
* If set to 'auto', the voice channel's bitrate will be used
* @returns {boolean} true if the bitrate has been successfully changed.
*/
setBitrate(value) {
if (!value || !this.bitrateEditable) return false;
const bitrate = value === 'auto' ? this.player.voiceConnection.channel.bitrate : value;
this.streams.opus.setBitrate(bitrate * 1000);
return true;
}
/**
* Sets the expected packet loss percentage if using a compatible Opus stream.
* @param {number} value between 0 and 1
* @returns {boolean} Returns true if it was successfully set.
*/
setPLP(value) {
if (!this.bitrateEditable) return false;
this.streams.opus.setPLP(value);
return true;
}
/**
* Enables or disables forward error correction if using a compatible Opus stream.
* @param {boolean} enabled true to enable
* @returns {boolean} Returns true if it was successfully set.
*/
setFEC(enabled) {
if (!this.bitrateEditable) return false;
this.streams.opus.setFEC(enabled);
return true;
}
get volumeEditable() {
return Boolean(this.streams.volume);
}
/**
* Whether or not the Opus bitrate of this stream is editable
* @type {boolean}
* @readonly
*/
get bitrateEditable() {
return this.streams.opus && this.streams.opus.setBitrate;
}
// Volume
get volume() {
return this.streams.volume ? this.streams.volume.volume : 1;
}
setVolume(value) {
if (!this.streams.volume) return false;
/**
* Emitted when the volume of this dispatcher changes.
* @event AudioDispatcher#volumeChange
* @param {number} oldVolume The old volume of this dispatcher
* @param {number} newVolume The new volume of this dispatcher
*/
this.emit('volumeChange', this.volume, value);
this.streams.volume.setVolume(value);
return true;
}
/**
* Sync with another video dispatcher to ensure that the audio and video are played at the same time.
* @param {VideoDispatcher} otherDispatcher The video dispatcher to sync with
*/
setSyncVideoDispatcher(otherDispatcher) {
if (otherDispatcher.getTypeDispatcher() !== 'video') {
throw new Error('Dispatcher must be a video dispatcher');
}
this._syncDispatcher = otherDispatcher;
}
// Volume stubs for docs
/* eslint-disable no-empty-function*/
get volumeDecibels() {}
get volumeLogarithmic() {}
setVolumeDecibels() {}
setVolumeLogarithmic() {}
}
VolumeInterface.applyToClass(AudioDispatcher);
module.exports = AudioDispatcher;