safeness-sb-new 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/package.json +96 -0
- package/src/WebSocket.js +39 -0
- package/src/client/BaseClient.js +86 -0
- package/src/client/Client.js +836 -0
- package/src/client/WebhookClient.js +61 -0
- package/src/client/actions/Action.js +120 -0
- package/src/client/actions/ActionsManager.js +78 -0
- package/src/client/actions/ApplicationCommandPermissionsUpdate.js +34 -0
- package/src/client/actions/AutoModerationActionExecution.js +27 -0
- package/src/client/actions/AutoModerationRuleCreate.js +28 -0
- package/src/client/actions/AutoModerationRuleDelete.js +32 -0
- package/src/client/actions/AutoModerationRuleUpdate.js +30 -0
- package/src/client/actions/ChannelCreate.js +23 -0
- package/src/client/actions/ChannelDelete.js +39 -0
- package/src/client/actions/ChannelUpdate.js +43 -0
- package/src/client/actions/GuildAuditLogEntryCreate.js +29 -0
- package/src/client/actions/GuildBanAdd.js +20 -0
- package/src/client/actions/GuildBanRemove.js +25 -0
- package/src/client/actions/GuildChannelsPositionUpdate.js +21 -0
- package/src/client/actions/GuildDelete.js +65 -0
- package/src/client/actions/GuildEmojiCreate.js +20 -0
- package/src/client/actions/GuildEmojiDelete.js +21 -0
- package/src/client/actions/GuildEmojiUpdate.js +20 -0
- package/src/client/actions/GuildEmojisUpdate.js +34 -0
- package/src/client/actions/GuildIntegrationsUpdate.js +19 -0
- package/src/client/actions/GuildMemberRemove.js +33 -0
- package/src/client/actions/GuildMemberUpdate.js +44 -0
- package/src/client/actions/GuildRoleCreate.js +25 -0
- package/src/client/actions/GuildRoleDelete.js +31 -0
- package/src/client/actions/GuildRoleUpdate.js +39 -0
- package/src/client/actions/GuildRolesPositionUpdate.js +21 -0
- package/src/client/actions/GuildScheduledEventCreate.js +27 -0
- package/src/client/actions/GuildScheduledEventDelete.js +31 -0
- package/src/client/actions/GuildScheduledEventUpdate.js +30 -0
- package/src/client/actions/GuildScheduledEventUserAdd.js +32 -0
- package/src/client/actions/GuildScheduledEventUserRemove.js +32 -0
- package/src/client/actions/GuildStickerCreate.js +20 -0
- package/src/client/actions/GuildStickerDelete.js +21 -0
- package/src/client/actions/GuildStickerUpdate.js +20 -0
- package/src/client/actions/GuildStickersUpdate.js +34 -0
- package/src/client/actions/GuildUpdate.js +33 -0
- package/src/client/actions/InviteCreate.js +28 -0
- package/src/client/actions/InviteDelete.js +30 -0
- package/src/client/actions/MessageCreate.js +46 -0
- package/src/client/actions/MessageDelete.js +32 -0
- package/src/client/actions/MessageDeleteBulk.js +46 -0
- package/src/client/actions/MessageReactionAdd.js +56 -0
- package/src/client/actions/MessageReactionRemove.js +45 -0
- package/src/client/actions/MessageReactionRemoveAll.js +33 -0
- package/src/client/actions/MessageReactionRemoveEmoji.js +28 -0
- package/src/client/actions/MessageUpdate.js +26 -0
- package/src/client/actions/PresenceUpdate.js +46 -0
- package/src/client/actions/StageInstanceCreate.js +28 -0
- package/src/client/actions/StageInstanceDelete.js +33 -0
- package/src/client/actions/StageInstanceUpdate.js +30 -0
- package/src/client/actions/ThreadCreate.js +24 -0
- package/src/client/actions/ThreadDelete.js +32 -0
- package/src/client/actions/ThreadListSync.js +59 -0
- package/src/client/actions/ThreadMemberUpdate.js +30 -0
- package/src/client/actions/ThreadMembersUpdate.js +34 -0
- package/src/client/actions/TypingStart.js +29 -0
- package/src/client/actions/UserUpdate.js +35 -0
- package/src/client/actions/VoiceStateUpdate.js +57 -0
- package/src/client/actions/WebhooksUpdate.js +20 -0
- package/src/client/voice/ClientVoiceManager.js +150 -0
- package/src/client/voice/VoiceConnection.js +849 -0
- package/src/client/voice/dispatcher/AnnexBDispatcher.js +120 -0
- package/src/client/voice/dispatcher/AudioDispatcher.js +115 -0
- package/src/client/voice/dispatcher/BaseDispatcher.js +405 -0
- package/src/client/voice/dispatcher/VPxDispatcher.js +52 -0
- package/src/client/voice/dispatcher/VideoDispatcher.js +31 -0
- package/src/client/voice/networking/VoiceUDPClient.js +188 -0
- package/src/client/voice/networking/VoiceWebSocket.js +280 -0
- package/src/client/voice/player/MediaPlayer.js +294 -0
- package/src/client/voice/player/processing/AnnexBNalSplitter.js +244 -0
- package/src/client/voice/player/processing/IvfSplitter.js +106 -0
- package/src/client/voice/receiver/PacketHandler.js +170 -0
- package/src/client/voice/receiver/Receiver.js +82 -0
- package/src/client/voice/receiver/video/IvfJoinner.js +106 -0
- package/src/client/voice/util/Function.js +14 -0
- package/src/client/voice/util/PlayInterface.js +122 -0
- package/src/client/voice/util/Secretbox.js +42 -0
- package/src/client/voice/util/Silence.js +16 -0
- package/src/client/voice/util/Socket.js +62 -0
- package/src/client/voice/util/VolumeInterface.js +104 -0
- package/src/client/websocket/WebSocketManager.js +392 -0
- package/src/client/websocket/WebSocketShard.js +906 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_CREATE.js +18 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_DELETE.js +20 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_PERMISSIONS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/APPLICATION_COMMAND_UPDATE.js +20 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_ACTION_EXECUTION.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_CREATE.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_DELETE.js +5 -0
- package/src/client/websocket/handlers/AUTO_MODERATION_RULE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/CALL_CREATE.js +14 -0
- package/src/client/websocket/handlers/CALL_DELETE.js +11 -0
- package/src/client/websocket/handlers/CALL_UPDATE.js +11 -0
- package/src/client/websocket/handlers/CHANNEL_CREATE.js +5 -0
- package/src/client/websocket/handlers/CHANNEL_DELETE.js +5 -0
- package/src/client/websocket/handlers/CHANNEL_PINS_UPDATE.js +22 -0
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +19 -0
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +16 -0
- package/src/client/websocket/handlers/CHANNEL_UPDATE.js +16 -0
- package/src/client/websocket/handlers/GUILD_AUDIT_LOG_ENTRY_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_BAN_ADD.js +5 -0
- package/src/client/websocket/handlers/GUILD_BAN_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_CREATE.js +52 -0
- package/src/client/websocket/handlers/GUILD_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_EMOJIS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_INTEGRATIONS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_MEMBERS_CHUNK.js +39 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +20 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_MEMBER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_ROLE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_CREATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_DELETE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_ADD.js +5 -0
- package/src/client/websocket/handlers/GUILD_SCHEDULED_EVENT_USER_REMOVE.js +5 -0
- package/src/client/websocket/handlers/GUILD_STICKERS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/GUILD_UPDATE.js +5 -0
- package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +12 -0
- package/src/client/websocket/handlers/INVITE_CREATE.js +5 -0
- package/src/client/websocket/handlers/INVITE_DELETE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_CREATE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_DELETE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_DELETE_BULK.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_ADD.js +22 -0
- package/src/client/websocket/handlers/MESSAGE_POLL_VOTE_REMOVE.js +12 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_ADD.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_ALL.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_REACTION_REMOVE_EMOJI.js +5 -0
- package/src/client/websocket/handlers/MESSAGE_UPDATE.js +16 -0
- package/src/client/websocket/handlers/PRESENCE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/READY.js +120 -0
- package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +19 -0
- package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +17 -0
- package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +41 -0
- package/src/client/websocket/handlers/RESUMED.js +14 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_CREATE.js +5 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_DELETE.js +5 -0
- package/src/client/websocket/handlers/STAGE_INSTANCE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_CREATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_DELETE.js +5 -0
- package/src/client/websocket/handlers/THREAD_LIST_SYNC.js +5 -0
- package/src/client/websocket/handlers/THREAD_MEMBERS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_MEMBER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/THREAD_UPDATE.js +16 -0
- package/src/client/websocket/handlers/TYPING_START.js +5 -0
- package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +6 -0
- package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
- package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/USER_UPDATE.js +5 -0
- package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
- package/src/client/websocket/handlers/VOICE_SERVER_UPDATE.js +6 -0
- package/src/client/websocket/handlers/VOICE_STATE_UPDATE.js +5 -0
- package/src/client/websocket/handlers/WEBHOOKS_UPDATE.js +5 -0
- package/src/client/websocket/handlers/index.js +83 -0
- package/src/errors/DJSError.js +61 -0
- package/src/errors/Messages.js +208 -0
- package/src/errors/index.js +4 -0
- package/src/index.js +159 -0
- package/src/managers/ApplicationCommandManager.js +264 -0
- package/src/managers/ApplicationCommandPermissionsManager.js +417 -0
- package/src/managers/AutoModerationRuleManager.js +296 -0
- package/src/managers/BaseGuildEmojiManager.js +80 -0
- package/src/managers/BaseManager.js +19 -0
- package/src/managers/BillingManager.js +66 -0
- package/src/managers/CachedManager.js +71 -0
- package/src/managers/ChannelManager.js +138 -0
- package/src/managers/ClientUserSettingManager.js +372 -0
- package/src/managers/DataManager.js +61 -0
- package/src/managers/GuildBanManager.js +204 -0
- package/src/managers/GuildChannelManager.js +488 -0
- package/src/managers/GuildEmojiManager.js +171 -0
- package/src/managers/GuildEmojiRoleManager.js +118 -0
- package/src/managers/GuildForumThreadManager.js +108 -0
- package/src/managers/GuildInviteManager.js +213 -0
- package/src/managers/GuildManager.js +304 -0
- package/src/managers/GuildMemberManager.js +597 -0
- package/src/managers/GuildMemberRoleManager.js +191 -0
- package/src/managers/GuildScheduledEventManager.js +296 -0
- package/src/managers/GuildSettingManager.js +155 -0
- package/src/managers/GuildStickerManager.js +179 -0
- package/src/managers/GuildTextThreadManager.js +98 -0
- package/src/managers/InteractionManager.js +39 -0
- package/src/managers/MessageManager.js +391 -0
- package/src/managers/PermissionOverwriteManager.js +166 -0
- package/src/managers/PresenceManager.js +58 -0
- package/src/managers/ReactionManager.js +67 -0
- package/src/managers/ReactionUserManager.js +71 -0
- package/src/managers/RelationshipManager.js +265 -0
- package/src/managers/RoleManager.js +352 -0
- package/src/managers/StageInstanceManager.js +162 -0
- package/src/managers/ThreadManager.js +174 -0
- package/src/managers/ThreadMemberManager.js +186 -0
- package/src/managers/UserManager.js +146 -0
- package/src/managers/UserNoteManager.js +53 -0
- package/src/managers/VoiceStateManager.js +37 -0
- package/src/rest/APIRequest.js +159 -0
- package/src/rest/APIRouter.js +53 -0
- package/src/rest/DiscordAPIError.js +104 -0
- package/src/rest/HTTPError.js +62 -0
- package/src/rest/RESTManager.js +62 -0
- package/src/rest/RateLimitError.js +55 -0
- package/src/rest/RequestHandler.js +444 -0
- package/src/sharding/Shard.js +443 -0
- package/src/sharding/ShardClientUtil.js +275 -0
- package/src/sharding/ShardingManager.js +318 -0
- package/src/structures/AnonymousGuild.js +98 -0
- package/src/structures/ApplicationCommand.js +593 -0
- package/src/structures/ApplicationRoleConnectionMetadata.js +48 -0
- package/src/structures/AutoModerationActionExecution.js +89 -0
- package/src/structures/AutoModerationRule.js +294 -0
- package/src/structures/AutocompleteInteraction.js +107 -0
- package/src/structures/Base.js +43 -0
- package/src/structures/BaseCommandInteraction.js +211 -0
- package/src/structures/BaseGuild.js +116 -0
- package/src/structures/BaseGuildEmoji.js +56 -0
- package/src/structures/BaseGuildTextChannel.js +191 -0
- package/src/structures/BaseGuildVoiceChannel.js +241 -0
- package/src/structures/BaseMessageComponent.js +114 -0
- package/src/structures/ButtonInteraction.js +11 -0
- package/src/structures/CallState.js +63 -0
- package/src/structures/CategoryChannel.js +85 -0
- package/src/structures/Channel.js +270 -0
- package/src/structures/ClientPresence.js +77 -0
- package/src/structures/ClientUser.js +450 -0
- package/src/structures/CommandInteraction.js +41 -0
- package/src/structures/CommandInteractionOptionResolver.js +276 -0
- package/src/structures/ContextMenuInteraction.js +65 -0
- package/src/structures/DMChannel.js +217 -0
- package/src/structures/DirectoryChannel.js +20 -0
- package/src/structures/Emoji.js +148 -0
- package/src/structures/ForumChannel.js +261 -0
- package/src/structures/GroupDMChannel.js +387 -0
- package/src/structures/Guild.js +1608 -0
- package/src/structures/GuildAuditLogs.js +729 -0
- package/src/structures/GuildBan.js +59 -0
- package/src/structures/GuildBoost.js +108 -0
- package/src/structures/GuildChannel.js +468 -0
- package/src/structures/GuildEmoji.js +161 -0
- package/src/structures/GuildMember.js +568 -0
- package/src/structures/GuildPreview.js +191 -0
- package/src/structures/GuildPreviewEmoji.js +27 -0
- package/src/structures/GuildScheduledEvent.js +441 -0
- package/src/structures/GuildTemplate.js +236 -0
- package/src/structures/Integration.js +188 -0
- package/src/structures/IntegrationApplication.js +96 -0
- package/src/structures/Interaction.js +290 -0
- package/src/structures/InteractionCollector.js +248 -0
- package/src/structures/InteractionWebhook.js +43 -0
- package/src/structures/Invite.js +358 -0
- package/src/structures/InviteGuild.js +23 -0
- package/src/structures/InviteStageInstance.js +86 -0
- package/src/structures/Message.js +1227 -0
- package/src/structures/MessageActionRow.js +103 -0
- package/src/structures/MessageAttachment.js +204 -0
- package/src/structures/MessageButton.js +165 -0
- package/src/structures/MessageCollector.js +146 -0
- package/src/structures/MessageComponentInteraction.js +120 -0
- package/src/structures/MessageContextMenuInteraction.js +20 -0
- package/src/structures/MessageEmbed.js +586 -0
- package/src/structures/MessageMentions.js +273 -0
- package/src/structures/MessagePayload.js +318 -0
- package/src/structures/MessagePoll.js +238 -0
- package/src/structures/MessageReaction.js +171 -0
- package/src/structures/MessageSelectMenu.js +140 -0
- package/src/structures/Modal.js +161 -0
- package/src/structures/ModalSubmitFieldsResolver.js +53 -0
- package/src/structures/ModalSubmitInteraction.js +119 -0
- package/src/structures/NewsChannel.js +32 -0
- package/src/structures/OAuth2Guild.js +28 -0
- package/src/structures/PermissionOverwrites.js +196 -0
- package/src/structures/Presence.js +1131 -0
- package/src/structures/ReactionCollector.js +229 -0
- package/src/structures/ReactionEmoji.js +31 -0
- package/src/structures/Role.js +531 -0
- package/src/structures/SelectMenuInteraction.js +21 -0
- package/src/structures/StageChannel.js +104 -0
- package/src/structures/StageInstance.js +208 -0
- package/src/structures/Sticker.js +310 -0
- package/src/structures/StickerPack.js +95 -0
- package/src/structures/StoreChannel.js +56 -0
- package/src/structures/Team.js +118 -0
- package/src/structures/TeamMember.js +71 -0
- package/src/structures/TextChannel.js +33 -0
- package/src/structures/TextInputComponent.js +131 -0
- package/src/structures/ThreadChannel.js +607 -0
- package/src/structures/ThreadMember.js +105 -0
- package/src/structures/Typing.js +74 -0
- package/src/structures/User.js +543 -0
- package/src/structures/UserContextMenuInteraction.js +29 -0
- package/src/structures/VoiceChannel.js +110 -0
- package/src/structures/VoiceRegion.js +53 -0
- package/src/structures/VoiceState.js +345 -0
- package/src/structures/WebEmbed.js +373 -0
- package/src/structures/Webhook.js +467 -0
- package/src/structures/WelcomeChannel.js +60 -0
- package/src/structures/WelcomeScreen.js +48 -0
- package/src/structures/Widget.js +87 -0
- package/src/structures/WidgetMember.js +99 -0
- package/src/structures/interfaces/Application.js +313 -0
- package/src/structures/interfaces/Collector.js +300 -0
- package/src/structures/interfaces/InteractionResponses.js +313 -0
- package/src/structures/interfaces/TextBasedChannel.js +719 -0
- package/src/util/ActivityFlags.js +44 -0
- package/src/util/ApplicationFlags.js +76 -0
- package/src/util/AttachmentFlags.js +38 -0
- package/src/util/BitField.js +170 -0
- package/src/util/ChannelFlags.js +45 -0
- package/src/util/Constants.js +1815 -0
- package/src/util/DataResolver.js +145 -0
- package/src/util/Formatters.js +228 -0
- package/src/util/GuildMemberFlags.js +43 -0
- package/src/util/Intents.js +74 -0
- package/src/util/InviteFlags.js +29 -0
- package/src/util/LimitedCollection.js +131 -0
- package/src/util/MessageFlags.js +54 -0
- package/src/util/Options.js +336 -0
- package/src/util/Permissions.js +202 -0
- package/src/util/PremiumUsageFlags.js +31 -0
- package/src/util/PurchasedFlags.js +33 -0
- package/src/util/RemoteAuth.js +382 -0
- package/src/util/RoleFlags.js +37 -0
- package/src/util/SnowflakeUtil.js +92 -0
- package/src/util/Speaking.js +33 -0
- package/src/util/Sweepers.js +466 -0
- package/src/util/SystemChannelFlags.js +55 -0
- package/src/util/ThreadMemberFlags.js +30 -0
- package/src/util/UserFlags.js +104 -0
- package/src/util/Util.js +889 -0
- package/typings/enums.d.ts +297 -0
- package/typings/index.d.ts +7670 -0
- package/typings/index.test-d.ts +0 -0
- package/typings/rawDataTypes.d.ts +342 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EventEmitter = require('events');
|
|
4
|
+
const { Buffer } = require('node:buffer');
|
|
5
|
+
const { setTimeout } = require('node:timers');
|
|
6
|
+
const { IvfJoinner } = require('./video/IvfJoinner');
|
|
7
|
+
const Speaking = require('../../../util/Speaking');
|
|
8
|
+
const secretbox = require('../util/Secretbox');
|
|
9
|
+
const { SILENCE_FRAME } = require('../util/Silence');
|
|
10
|
+
|
|
11
|
+
// The delay between packets when a user is considered to have stopped speaking
|
|
12
|
+
// https://github.com/discordjs/discord.js/issues/3524#issuecomment-540373200
|
|
13
|
+
const DISCORD_SPEAKING_DELAY = 250;
|
|
14
|
+
|
|
15
|
+
class Readable extends require('stream').Readable {
|
|
16
|
+
_read() {} // eslint-disable-line no-empty-function
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class PacketHandler extends EventEmitter {
|
|
20
|
+
constructor(receiver) {
|
|
21
|
+
super();
|
|
22
|
+
this.nonce = Buffer.alloc(24);
|
|
23
|
+
this.receiver = receiver;
|
|
24
|
+
this.streams = new Map();
|
|
25
|
+
this.videoStreams = new Map();
|
|
26
|
+
this.speakingTimeouts = new Map();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get connection() {
|
|
30
|
+
return this.receiver.connection;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_stoppedSpeaking(userId) {
|
|
34
|
+
const streamInfo = this.streams.get(userId);
|
|
35
|
+
if (streamInfo && streamInfo.end === 'silence') {
|
|
36
|
+
this.streams.delete(userId);
|
|
37
|
+
streamInfo.stream.push(null);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
makeStream(user, end) {
|
|
42
|
+
if (this.streams.has(user)) return this.streams.get(user).stream;
|
|
43
|
+
const stream = new Readable();
|
|
44
|
+
stream.on('end', () => this.streams.delete(user));
|
|
45
|
+
this.streams.set(user, { stream, end });
|
|
46
|
+
return stream;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
makeVideoStream(user) {
|
|
50
|
+
if (this.videoStreams.has(user)) return this.videoStreams.get(user);
|
|
51
|
+
const stream = new IvfJoinner('VP8'); // Test VP8 ok
|
|
52
|
+
stream.stream.on('end', () => this.videoStreams.delete(user));
|
|
53
|
+
this.videoStreams.set(user, stream);
|
|
54
|
+
return stream;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
parseBuffer(buffer) {
|
|
58
|
+
const { secret_key, mode } = this.receiver.connection.authentication;
|
|
59
|
+
|
|
60
|
+
// Choose correct nonce depending on encryption
|
|
61
|
+
let end;
|
|
62
|
+
if (mode === 'xsalsa20_poly1305_lite') {
|
|
63
|
+
buffer.copy(this.nonce, 0, buffer.length - 4);
|
|
64
|
+
end = buffer.length - 4;
|
|
65
|
+
} else if (mode === 'xsalsa20_poly1305_suffix') {
|
|
66
|
+
buffer.copy(this.nonce, 0, buffer.length - 24);
|
|
67
|
+
end = buffer.length - 24;
|
|
68
|
+
} else {
|
|
69
|
+
buffer.copy(this.nonce, 0, 0, 12);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Open packet
|
|
73
|
+
if (!secret_key) return new Error('secret_key cannot be null or undefined');
|
|
74
|
+
let packet = secretbox.methods.open(buffer.slice(12, end), this.nonce, secret_key);
|
|
75
|
+
if (!packet) return new Error('Failed to decrypt voice packet');
|
|
76
|
+
packet = Buffer.from(packet);
|
|
77
|
+
|
|
78
|
+
// Strip RTP Header Extensions (one-byte only)
|
|
79
|
+
if (packet[0] === 0xbe && packet[1] === 0xde) {
|
|
80
|
+
const headerExtensionLength = packet.readUInt16BE(2);
|
|
81
|
+
packet = packet.subarray(4 + 4 * headerExtensionLength);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Ex VP8
|
|
85
|
+
// <Buffer 90 80 80 00 30 b7 01 9d 01 2a 80 07 38 04 0b c7 08 85 85 88 99 84 88 3f 82 00 06 16 04 f7 06 81 64 9f 6b db 9b 27 38 7b 27 38 7b 27 38 7b 27 38 7b 27 ... 1154 more bytes>
|
|
86
|
+
// 90 80: payloadDescriptorBuf (90 80 if first frame | 80 80 else)
|
|
87
|
+
// 80 00: pictureIdBuf
|
|
88
|
+
// n bytes: chunk raw (Ivf splitter)
|
|
89
|
+
|
|
90
|
+
return packet;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
push(buffer) {
|
|
94
|
+
const ssrc = buffer.readUInt32BE(8);
|
|
95
|
+
const userStat = this.connection.ssrcMap.get(ssrc) || this.connection.ssrcMap.get(ssrc - 1); // Maybe vidoe_ssrc ?
|
|
96
|
+
|
|
97
|
+
if (!userStat) return;
|
|
98
|
+
|
|
99
|
+
let opusPacket;
|
|
100
|
+
const streamInfo = this.streams.get(userStat.userId);
|
|
101
|
+
const videoStreamInfo = this.videoStreams.get(userStat.userId);
|
|
102
|
+
|
|
103
|
+
// If the user is in video, we need to check if the packet is just silence
|
|
104
|
+
if (userStat.hasVideo) {
|
|
105
|
+
opusPacket = this.parseBuffer(buffer);
|
|
106
|
+
if (opusPacket instanceof Error) {
|
|
107
|
+
// Only emit an error if we were actively receiving packets from this user
|
|
108
|
+
if (streamInfo || videoStreamInfo) {
|
|
109
|
+
this.emit('error', opusPacket);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (SILENCE_FRAME.equals(opusPacket)) {
|
|
114
|
+
// If this is a silence frame, pretend we never received it
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let speakingTimeout = this.speakingTimeouts.get(ssrc);
|
|
120
|
+
// Only for voice... idk
|
|
121
|
+
if (this.connection.ssrcMap.has(ssrc)) {
|
|
122
|
+
if (typeof speakingTimeout === 'undefined') {
|
|
123
|
+
// Ensure at least the speaking bit is set.
|
|
124
|
+
// As the object is by reference, it's only needed once per client re-connect.
|
|
125
|
+
if (userStat.speaking === 0) {
|
|
126
|
+
userStat.speaking = Speaking.FLAGS.SPEAKING;
|
|
127
|
+
}
|
|
128
|
+
this.connection.onSpeaking({ user_id: userStat.userId, ssrc: ssrc, speaking: userStat.speaking });
|
|
129
|
+
speakingTimeout = setTimeout(() => {
|
|
130
|
+
try {
|
|
131
|
+
this.connection.onSpeaking({ user_id: userStat.userId, ssrc: ssrc, speaking: 0 });
|
|
132
|
+
clearTimeout(speakingTimeout);
|
|
133
|
+
this.speakingTimeouts.delete(ssrc);
|
|
134
|
+
} catch {
|
|
135
|
+
// Connection already closed, ignore
|
|
136
|
+
}
|
|
137
|
+
}, DISCORD_SPEAKING_DELAY).unref();
|
|
138
|
+
this.speakingTimeouts.set(ssrc, speakingTimeout);
|
|
139
|
+
} else {
|
|
140
|
+
speakingTimeout.refresh();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (streamInfo) {
|
|
145
|
+
const { stream } = streamInfo;
|
|
146
|
+
if (!opusPacket) {
|
|
147
|
+
opusPacket = this.parseBuffer(buffer);
|
|
148
|
+
if (opusPacket instanceof Error) {
|
|
149
|
+
this.emit('error', opusPacket);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
stream.push(opusPacket);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (videoStreamInfo) {
|
|
157
|
+
const stream = videoStreamInfo;
|
|
158
|
+
if (!opusPacket) {
|
|
159
|
+
opusPacket = this.parseBuffer(buffer);
|
|
160
|
+
if (opusPacket instanceof Error) {
|
|
161
|
+
this.emit('error', opusPacket);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
stream.push(opusPacket); // VP8 ? idk
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = PacketHandler;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const EventEmitter = require('events');
|
|
4
|
+
const prism = require('prism-media');
|
|
5
|
+
const PacketHandler = require('./PacketHandler');
|
|
6
|
+
const { Error } = require('../../../errors');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Receives audio packets from a voice connection.
|
|
10
|
+
* @example
|
|
11
|
+
* const receiver = connection.createReceiver();
|
|
12
|
+
* // opusStream is a ReadableStream - that means you could play it back to a voice channel if you wanted to!
|
|
13
|
+
* const opusStream = receiver.createStream(user);
|
|
14
|
+
*/
|
|
15
|
+
class VoiceReceiver extends EventEmitter {
|
|
16
|
+
constructor(connection) {
|
|
17
|
+
super();
|
|
18
|
+
this.connection = connection;
|
|
19
|
+
this.packets = new PacketHandler(this);
|
|
20
|
+
/**
|
|
21
|
+
* Emitted whenever there is a warning
|
|
22
|
+
* @event VoiceReceiver#debug
|
|
23
|
+
* @param {Error|string} error The error or message to debug
|
|
24
|
+
*/
|
|
25
|
+
this.packets.on('error', err => this.emit('debug', err));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Options passed to `VoiceReceiver#createStream`.
|
|
30
|
+
* @typedef {Object} ReceiveStreamOptions
|
|
31
|
+
* @property {string} [mode='opus'] The mode for audio output. This defaults to opus, meaning discord.js won't decode
|
|
32
|
+
* the packets for you. You can set this to 'pcm' so that the stream's output will be 16-bit little-endian stereo
|
|
33
|
+
* audio
|
|
34
|
+
* @property {string} [end='silence'] When the stream should be destroyed. If `silence`, this will be when the user
|
|
35
|
+
* stops talking. Otherwise, if `manual`, this should be handled by you.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new audio receiving stream. If a stream already exists for a user, then that stream will be returned
|
|
40
|
+
* rather than generating a new one.
|
|
41
|
+
* @param {UserResolvable} user The user to start listening to.
|
|
42
|
+
* @param {ReceiveStreamOptions} options Options.
|
|
43
|
+
* @returns {ReadableStream}
|
|
44
|
+
*/
|
|
45
|
+
createStream(user, { mode = 'opus', end = 'silence' } = {}) {
|
|
46
|
+
user = this.connection.client.users.resolve(user);
|
|
47
|
+
if (!user) throw new Error('VOICE_USER_MISSING');
|
|
48
|
+
const stream = this.packets.makeStream(user.id, end);
|
|
49
|
+
if (mode === 'pcm') {
|
|
50
|
+
const decoder = new prism.opus.Decoder({ channels: 2, rate: 48000, frameSize: 960 });
|
|
51
|
+
stream.pipe(decoder);
|
|
52
|
+
return decoder;
|
|
53
|
+
}
|
|
54
|
+
return stream;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new video receiving stream. If a stream already exists for a user, then that stream will be returned
|
|
59
|
+
* rather than generating a new one.
|
|
60
|
+
* @param {UserResolvable} user The user to start listening to.
|
|
61
|
+
* @returns {IvfJoinner}
|
|
62
|
+
* @deprecated Only support VP8
|
|
63
|
+
* @example
|
|
64
|
+
* const video = connection.receiver.createVideoStream('1071734918972985395');
|
|
65
|
+
* video.stream.pipe(fs.createWriteStream('test.ivf'));
|
|
66
|
+
* setTimeout(() => {
|
|
67
|
+
* video.stop();
|
|
68
|
+
* video.createFinalFile(
|
|
69
|
+
* fs.createReadStream('test.ivf'),
|
|
70
|
+
* fs.createWriteStream('final.ivf'),
|
|
71
|
+
* );
|
|
72
|
+
* }, 10_000);
|
|
73
|
+
*/
|
|
74
|
+
createVideoStream(user) {
|
|
75
|
+
user = this.connection.client.users.resolve(user);
|
|
76
|
+
if (!user) throw new Error('VOICE_USER_MISSING');
|
|
77
|
+
const stream = this.packets.makeVideoStream(user.id);
|
|
78
|
+
return stream;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = VoiceReceiver;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Buffer } = require('buffer');
|
|
4
|
+
const { setTimeout } = require('timers');
|
|
5
|
+
|
|
6
|
+
class Readable extends require('stream').Readable {
|
|
7
|
+
_read() {} // eslint-disable-line no-empty-function
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Receives video packets from a voice connection.
|
|
12
|
+
*/
|
|
13
|
+
class IvfJoinner {
|
|
14
|
+
constructor(codec = 'VP8') {
|
|
15
|
+
this.codec = codec;
|
|
16
|
+
this.ivfHeader = this.getHeaderIvf();
|
|
17
|
+
this.count = 0;
|
|
18
|
+
/**
|
|
19
|
+
* Readable stream
|
|
20
|
+
* @type {Readable}
|
|
21
|
+
*/
|
|
22
|
+
this.stream = new Readable();
|
|
23
|
+
this._tempBuffer = null;
|
|
24
|
+
this._fps = 0;
|
|
25
|
+
this.timeConvert = null;
|
|
26
|
+
this.lastConvert = null;
|
|
27
|
+
this.firstFrame = Buffer.from([0x90, 0x80]);
|
|
28
|
+
this._timeoutFps = null;
|
|
29
|
+
}
|
|
30
|
+
getHeaderIvf() {
|
|
31
|
+
const ivfHeader = Buffer.alloc(32);
|
|
32
|
+
ivfHeader.write('DKIF'); // Signature
|
|
33
|
+
ivfHeader.writeUInt16LE(0, 4); // Version
|
|
34
|
+
ivfHeader.writeUInt16LE(32, 6); // Header length
|
|
35
|
+
ivfHeader.write(`${this.codec}0`, 8); // Codec FourCC
|
|
36
|
+
ivfHeader.writeUInt16LE(0, 12); // Width
|
|
37
|
+
ivfHeader.writeUInt16LE(0, 14); // Height
|
|
38
|
+
ivfHeader.writeUInt32LE(this._fps, 16); // Frame rate
|
|
39
|
+
ivfHeader.writeUInt32LE(1, 20); // Framerate denominator
|
|
40
|
+
ivfHeader.writeUInt32LE(this.count + 1, 24); // Frame count
|
|
41
|
+
return ivfHeader;
|
|
42
|
+
}
|
|
43
|
+
getFramedata() {
|
|
44
|
+
const frameHeader = Buffer.alloc(12);
|
|
45
|
+
frameHeader.writeUInt32LE(this._tempBuffer.length, 0); // Frame size
|
|
46
|
+
frameHeader.writeUInt32LE(this.count, 4); // Timestamp
|
|
47
|
+
return frameHeader;
|
|
48
|
+
}
|
|
49
|
+
push(bufferRaw) {
|
|
50
|
+
if (!this._timeoutFps) {
|
|
51
|
+
this._timeoutFps = setTimeout(() => {
|
|
52
|
+
if (this.stream.destroyed) return;
|
|
53
|
+
this._fps = Math.round((this.lastConvert - this.timeConvert) / this.count);
|
|
54
|
+
// ! Todo: need improved
|
|
55
|
+
this._timeoutFps = null;
|
|
56
|
+
}, 500).unref();
|
|
57
|
+
}
|
|
58
|
+
if (!this.timeConvert) {
|
|
59
|
+
this.timeConvert = performance.now();
|
|
60
|
+
}
|
|
61
|
+
// Ex VP8
|
|
62
|
+
// <Buffer 90 80 80 00 30 b7 01 9d 01 2a 80 07 38 04 0b c7 08 85 85 88 99 84 88 3f 82 00 06 16 04 f7 06 81 64 9f 6b db 9b 27 38 7b 27 38 7b 27 38 7b 27 38 7b 27 ... 1154 more bytes>
|
|
63
|
+
// 90 80: payloadDescriptorBuf (90 80 if first frame | 80 80 else)
|
|
64
|
+
// 80 00: pictureIdBuf
|
|
65
|
+
// n bytes: chunk raw (Ivf splitter)
|
|
66
|
+
const payloadDescriptorBuf = bufferRaw.slice(0, 2);
|
|
67
|
+
const data = bufferRaw.slice(4);
|
|
68
|
+
const isFirstFrame = Buffer.compare(payloadDescriptorBuf, this.firstFrame) === 0;
|
|
69
|
+
if (isFirstFrame && this._tempBuffer) {
|
|
70
|
+
this.count++;
|
|
71
|
+
this.lastConvert = performance.now();
|
|
72
|
+
this.stream.push(Buffer.concat([this.getFramedata(), this._tempBuffer]));
|
|
73
|
+
this._tempBuffer = null;
|
|
74
|
+
}
|
|
75
|
+
if (!this._tempBuffer) {
|
|
76
|
+
this._tempBuffer = data;
|
|
77
|
+
} else {
|
|
78
|
+
this._tempBuffer = Buffer.concat([this._tempBuffer, data]);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Force stop stream
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
stop() {
|
|
86
|
+
this.stream.push(null);
|
|
87
|
+
this.stream.emit('end'); // Force close stream;
|
|
88
|
+
this.stream.destroy();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convert partial file to full file
|
|
92
|
+
* @param {Readable} readable File created by stream (Raw)
|
|
93
|
+
* @param {Writable} writeable Output (Ivf)
|
|
94
|
+
* @returns {void}
|
|
95
|
+
*/
|
|
96
|
+
createFinalFile(readable, writeable) {
|
|
97
|
+
if (this.stream.destroyed) {
|
|
98
|
+
writeable.write(this.getHeaderIvf());
|
|
99
|
+
readable.pipe(writeable);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
module.exports = {
|
|
105
|
+
IvfJoinner,
|
|
106
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function parseStreamKey(key) {
|
|
4
|
+
const Arr = key.split(':');
|
|
5
|
+
const type = Arr[0];
|
|
6
|
+
const guildId = type == 'guild' ? Arr[1] : null;
|
|
7
|
+
const channelId = type == 'guild' ? Arr[2] : Arr[1];
|
|
8
|
+
const userId = type == 'guild' ? Arr[3] : Arr[2];
|
|
9
|
+
return { type, guildId, channelId, userId };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
parseStreamKey,
|
|
14
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Readable } = require('stream');
|
|
4
|
+
const prism = require('prism-media');
|
|
5
|
+
const { Error } = require('../../../errors');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options that can be passed to stream-playing methods:
|
|
9
|
+
* @typedef {Object} StreamOptions
|
|
10
|
+
* @property {StreamType} [type='unknown'] The type of stream.
|
|
11
|
+
* @property {number} [seek=0] The time to seek to, will be ignored when playing `ogg/opus` or `webm/opus` streams
|
|
12
|
+
* @property {number|boolean} [volume=1] The volume to play at. Set this to false to disable volume transforms for
|
|
13
|
+
* this stream to improve performance.
|
|
14
|
+
* @property {number} [plp] Expected packet loss percentage
|
|
15
|
+
* @property {boolean} [fec] Enabled forward error correction
|
|
16
|
+
* @property {number|string} [bitrate=96] The bitrate (quality) of the audio in kbps.
|
|
17
|
+
* If set to 'auto', the voice channel's bitrate will be used
|
|
18
|
+
* @property {number} [highWaterMark=12] The maximum number of opus packets to make and store before they are
|
|
19
|
+
* actually needed. See https://nodejs.org/en/docs/guides/backpressuring-in-streams/. Setting this value to
|
|
20
|
+
* 1 means that changes in volume will be more instant.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* An option passed as part of `StreamOptions` specifying the type of the stream.
|
|
25
|
+
* * `unknown`: The default type, streams/input will be passed through to ffmpeg before encoding.
|
|
26
|
+
* Will play most streams.
|
|
27
|
+
* * `converted`: Play a stream of 16bit signed stereo PCM data, skipping ffmpeg.
|
|
28
|
+
* * `opus`: Play a stream of opus packets, skipping ffmpeg. You lose the ability to alter volume.
|
|
29
|
+
* * `ogg/opus`: Play an ogg file with the opus encoding, skipping ffmpeg. You lose the ability to alter volume.
|
|
30
|
+
* * `webm/opus`: Play a webm file with opus audio, skipping ffmpeg. You lose the ability to alter volume.
|
|
31
|
+
* @typedef {string} StreamType
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* An interface class to allow you to play audio over VoiceConnections.
|
|
36
|
+
*/
|
|
37
|
+
class PlayInterface {
|
|
38
|
+
constructor(player) {
|
|
39
|
+
this.player = player;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Play an audio resource.
|
|
44
|
+
* @param {ReadableStream|string} resource The resource to play.
|
|
45
|
+
* @param {StreamOptions} [options] The options to play.
|
|
46
|
+
* @example
|
|
47
|
+
* // Play a local audio file
|
|
48
|
+
* connection.playAudio('/home/hydrabolt/audio.mp3', { volume: 0.5 });
|
|
49
|
+
* @example
|
|
50
|
+
* // Play a ReadableStream
|
|
51
|
+
* connection.playAudio(ytdl('https://www.youtube.com/watch?v=ZlAU_w7-Xp8', { quality: 'highestaudio' }));
|
|
52
|
+
* @example
|
|
53
|
+
* // Using different protocols: https://ffmpeg.org/ffmpeg-protocols.html
|
|
54
|
+
* connection.playAudio('http://www.sample-videos.com/audio/mp3/wave.mp3');
|
|
55
|
+
* @returns {AudioDispatcher}
|
|
56
|
+
*/
|
|
57
|
+
playAudio(resource, options = {}) {
|
|
58
|
+
if (resource instanceof Readable || typeof resource === 'string') {
|
|
59
|
+
const type = options.type || 'unknown';
|
|
60
|
+
if (type === 'unknown') {
|
|
61
|
+
return this.player.playUnknown(resource, options);
|
|
62
|
+
} else if (type === 'converted') {
|
|
63
|
+
return this.player.playPCMStream(resource, options);
|
|
64
|
+
} else if (type === 'opus') {
|
|
65
|
+
return this.player.playOpusStream(resource, options);
|
|
66
|
+
} else if (type === 'ogg/opus') {
|
|
67
|
+
if (!(resource instanceof Readable)) throw new Error('VOICE_PRISM_DEMUXERS_NEED_STREAM');
|
|
68
|
+
return this.player.playOpusStream(resource.pipe(new prism.opus.OggDemuxer()), options);
|
|
69
|
+
} else if (type === 'webm/opus') {
|
|
70
|
+
if (!(resource instanceof Readable)) throw new Error('VOICE_PRISM_DEMUXERS_NEED_STREAM');
|
|
71
|
+
return this.player.playOpusStream(resource.pipe(new prism.opus.WebmDemuxer()), options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new Error('VOICE_PLAY_INTERFACE_BAD_TYPE');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Options that can be passed to stream-playing methods:
|
|
79
|
+
* @typedef {Object} VideoOptions
|
|
80
|
+
* @property {number} [seek=0] The time to seek to, will be ignored when playing `ogg/opus` or `webm/opus` streams
|
|
81
|
+
* @property {number} [fps=30] Video fps
|
|
82
|
+
* @property {number} [highWaterMark=12] The maximum number of opus packets to make and store before they are
|
|
83
|
+
* actually needed. See https://nodejs.org/en/docs/guides/backpressuring-in-streams/. Setting this value to
|
|
84
|
+
* 1 means that changes in volume will be more instant.
|
|
85
|
+
* @property {'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow' | 'slower' | 'veryslow'} [presetH26x='veryfast'] ffmpeg preset h254 / h265
|
|
86
|
+
* @property {boolean} [hwAccel=false] Enables hardware accelerated video decoding. Enabling this option might result in an exception
|
|
87
|
+
* being thrown by Ffmpeg process if your system does not support hardware acceleration
|
|
88
|
+
* @property {string[]} [inputFFmpegArgs] input ffmpeg
|
|
89
|
+
* Ex: ['-config1', 'value1', '-config2', 'value2']
|
|
90
|
+
* @property {string[]} [outputFFmpegArgs] output ffmpeg
|
|
91
|
+
* Ex: ['-config1', 'value1', '-config2', 'value2']
|
|
92
|
+
* @property {number|'auto'} [bitrate=2000] The bitrate (quality) of the video in kbps.
|
|
93
|
+
* If set to 'auto', ffmpeg will automatically select
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Play an video resource.
|
|
98
|
+
* @param {ReadableStream|string} resource The resource to play.
|
|
99
|
+
* @param {VideoOptions} [options] The options to play.
|
|
100
|
+
* @example
|
|
101
|
+
* // Play a local video file
|
|
102
|
+
* connection.playVideo('/home/hydrabolt/video.mp4');
|
|
103
|
+
* @example
|
|
104
|
+
* // Using different protocols: https://ffmpeg.org/ffmpeg-protocols.html
|
|
105
|
+
* connection.playVideo('http://www.sample-videos.com/video/mp4/wave.mp4');
|
|
106
|
+
* @returns {VideoDispatcher}
|
|
107
|
+
*/
|
|
108
|
+
playVideo(resource, options = {}) {
|
|
109
|
+
if (resource instanceof Readable || typeof resource === 'string') {
|
|
110
|
+
return this.player.playUnknownVideo(resource, options);
|
|
111
|
+
}
|
|
112
|
+
throw new Error('VOICE_PLAY_INTERFACE_BAD_TYPE');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static applyToClass(structure) {
|
|
116
|
+
for (const prop of ['playAudio', 'playVideo']) {
|
|
117
|
+
Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(PlayInterface.prototype, prop));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = PlayInterface;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const libs = {
|
|
4
|
+
sodium: sodium => ({
|
|
5
|
+
open: sodium.api.crypto_secretbox_open_easy,
|
|
6
|
+
close: sodium.api.crypto_secretbox_easy,
|
|
7
|
+
random: n => sodium.randombytes_buf(n),
|
|
8
|
+
}),
|
|
9
|
+
'libsodium-wrappers': sodium => ({
|
|
10
|
+
open: sodium.crypto_secretbox_open_easy,
|
|
11
|
+
close: sodium.crypto_secretbox_easy,
|
|
12
|
+
random: n => sodium.randombytes_buf(n),
|
|
13
|
+
}),
|
|
14
|
+
tweetnacl: tweetnacl => ({
|
|
15
|
+
open: tweetnacl.secretbox.open,
|
|
16
|
+
close: tweetnacl.secretbox,
|
|
17
|
+
random: n => tweetnacl.randomBytes(n),
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function NoLib() {
|
|
22
|
+
throw new Error(
|
|
23
|
+
'Cannot play audio as no valid encryption package is installed.\n- Install sodium, libsodium-wrappers, or tweetnacl.',
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
exports.methods = {
|
|
28
|
+
open: NoLib,
|
|
29
|
+
close: NoLib,
|
|
30
|
+
random: NoLib,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
(async () => {
|
|
34
|
+
for (const libName of Object.keys(libs)) {
|
|
35
|
+
try {
|
|
36
|
+
const lib = require(libName);
|
|
37
|
+
if (libName === 'libsodium-wrappers' && lib.ready) await lib.ready; // eslint-disable-line no-await-in-loop
|
|
38
|
+
exports.methods = libs[libName](lib);
|
|
39
|
+
break;
|
|
40
|
+
} catch {} // eslint-disable-line no-empty
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { Buffer } = require('node:buffer');
|
|
4
|
+
const { Readable } = require('stream');
|
|
5
|
+
|
|
6
|
+
const SILENCE_FRAME = Buffer.from([0xf8, 0xff, 0xfe]);
|
|
7
|
+
|
|
8
|
+
class Silence extends Readable {
|
|
9
|
+
_read() {
|
|
10
|
+
this.push(SILENCE_FRAME);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
Silence.SILENCE_FRAME = SILENCE_FRAME;
|
|
15
|
+
|
|
16
|
+
module.exports = Silence;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
Credit: https://github.com/dank074/Discord-video-stream
|
|
5
|
+
The use of video streaming in this library is an incomplete implementation with many bugs, primarily aimed at lazy users.
|
|
6
|
+
The video streaming features in this library are sourced from https://github.com/dank074/Discord-video-stream.
|
|
7
|
+
|
|
8
|
+
Please use the @dank074/discord-video-stream library to access all advanced and professional features,
|
|
9
|
+
along with comprehensive support. I will not actively fix bugs related to streaming and encourage everyone to
|
|
10
|
+
use https://github.com/dank074/Discord-video-stream for stable and smooth streaming.
|
|
11
|
+
|
|
12
|
+
To reiterate: This is an incomplete implementation of the library https://github.com/dank074/Discord-video-stream.
|
|
13
|
+
|
|
14
|
+
Thanks to dank074 and longnguyen2004 for implementing new codecs (H264, H265).
|
|
15
|
+
Thanks to mrjvs for discovering how Discord transmits data and the VP8 codec.
|
|
16
|
+
|
|
17
|
+
Please use the @dank074/discord-video-stream library for the best support.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const net = require('net');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const process = require('process');
|
|
24
|
+
|
|
25
|
+
let counter = 0;
|
|
26
|
+
|
|
27
|
+
class UnixStream {
|
|
28
|
+
constructor(stream, onSocket) {
|
|
29
|
+
if (process.platform === 'win32') {
|
|
30
|
+
const pipePrefix = '\\\\.\\pipe\\';
|
|
31
|
+
const pipeName = `node-webrtc.${++counter}.sock`;
|
|
32
|
+
this.socketPath = path.join(pipePrefix, pipeName);
|
|
33
|
+
this.url = this.socketPath;
|
|
34
|
+
} else {
|
|
35
|
+
this.socketPath = `./${++counter}.sock`;
|
|
36
|
+
this.url = `unix:${this.socketPath}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
fs.statSync(this.socketPath);
|
|
41
|
+
fs.unlinkSync(this.socketPath);
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// Null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const server = net.createServer(onSocket);
|
|
47
|
+
stream.on('finish', () => {
|
|
48
|
+
server.close();
|
|
49
|
+
});
|
|
50
|
+
server.listen(this.socketPath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function StreamInput(stream) {
|
|
55
|
+
return new UnixStream(stream, socket => stream.pipe(socket));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function StreamOutput(stream) {
|
|
59
|
+
return new UnixStream(stream, socket => socket.pipe(stream));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { StreamOutput, StreamInput, UnixStream };
|