From 462f643d6fbd5f9282656696e01df60156de3a23 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Sun, 30 Aug 2026 21:15:04 +0700 Subject: [PATCH] feat(gateway): auto server-undeafen + unmute the bot itself on voice join A server-muted/server-deafened bot can't reliably receive/record members' audio (and definitely can't receive video/screen share). After the voice connection is Ready, force a REST guild-members PATCH (mute:false, deaf:false) on the self member so the bot is auto-unmuted & undeafened on every join/reconnect. Requires MUTE_MEMBERS + DEAFEN_MEMBERS permissions (user granted). Failure is logged as a warning and never breaks the voice join. --- .../src/modules/voice-recording/recorder.ts | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/services/discord-gateway/src/modules/voice-recording/recorder.ts b/services/discord-gateway/src/modules/voice-recording/recorder.ts index b69a8a0d..f82c82f6 100644 --- a/services/discord-gateway/src/modules/voice-recording/recorder.ts +++ b/services/discord-gateway/src/modules/voice-recording/recorder.ts @@ -7,7 +7,7 @@ import { type VoiceConnection, VoiceConnectionStatus, } from "@discordjs/voice"; -import type { Client, VoiceChannel } from "discord.js-selfbot-v13"; +import type { Client, Guild, VoiceChannel } from "discord.js-selfbot-v13"; import { createChildLogger } from "@/shared/logger/index"; import { retryWithBackoff } from "@/shared/utils/index"; import { config } from "../../shared/config/config.js"; @@ -31,6 +31,39 @@ export function setEventBroadcaster(broadcaster: EventBroadcaster | undefined) { _eventBroadcaster = broadcaster; } +/** + * Force the bot (self member) to be unmuted + undeafened at the SERVER level. + * + * Why: a server-muted / server-deafened bot cannot receive/record other + * members' audio properly (and definitely cannot receive their video/screen + * share). The bot's own voice state may be server-muted/deafened by an admin + * or by a prior state. This issues a REST guild-members PATCH with + * `mute:false, deaf:false`. + * + * Requires the `MUTE_MEMBERS` + `DEAFEN_MEMBERS` permissions on the bot + * (user has granted them). Failures are logged, never fatal — an unmute + * failure must not break the voice join/recording. + */ +async function forceSelfServerUnmuteUndeafen( + client: Client, + guild: Guild, +): Promise { + try { + const selfId = client.user?.id; + if (!selfId) return; + await guild.members.edit(selfId, { mute: false, deaf: false }); + logger.info({ guildId: guild.id }, "Forced bot server unmute + undeafen"); + } catch (err) { + logger.warn( + { + guildId: guild.id, + err: err instanceof Error ? err.message : String(err), + }, + "Could not force server unmute/undeafen (permissions not granted?)", + ); + } +} + let _pcmWsClient: VoicePcmWsClient | undefined; export function setPcmWsClient(client: VoicePcmWsClient | undefined) { @@ -115,6 +148,11 @@ export async function startRecording( ); logger.info("Connected to voice channel. Recording started"); + // Auto undeafen + unmute the bot itself at the server level (MUTE_MEMBERS / + // DEAFEN_MEMBERS permission granted). Server-muted/deafened bot can't + // receive others' audio/video. Fire-and-forget — never blocks recording. + void forceSelfServerUnmuteUndeafen(client, channel.guild); + // Create recording session after connection is ready const sessionStartTime = Date.now(); const session = createRecordingSession({