voice: audit + noise suppression toggle + stability fixes

Gateway:
- transmitter.ts: cap backpressure queue at 500 chunks (prevents memory leak)
- transmitter.ts: fix Redis race — assign redisSub AFTER subscribe completes
- voice.handler.ts: static import Redis instead of dynamic (cleaner, no eval)

Frontend:
- mic-transmit.ts: MicAccessError with specific reasons (permission-denied, no-mic, timeout)
- mic-transmit.ts: noiseSuppression option in getUserMedia constraints
- mic-transmit.ts: proper DOMException handling for all getUserMedia failure modes
- use-voice.ts: noiseSuppression state + toggleNoiseSuppression exposed
- use-voice.ts: cleanup on unmount (stops transmitter, clears refs)
- voice/view.tsx: noise suppression toggle button (ShieldCheck/ShieldOff icons)
- voice/view.tsx: improved mic error toasts (permission denied / no mic specific)
- voice/view.tsx: NS status in codec footer (NS_ACTIVE when enabled)
This commit is contained in:
asepharyana
2026-08-26 23:32:37 +07:00
parent 4f4f92706c
commit 7e0d0d5123
5 changed files with 214 additions and 31 deletions
@@ -1,4 +1,5 @@
import type { Client } from "discord.js-selfbot-v13";
import Redis from "ioredis";
import { config } from "../../shared/config/config.js";
import type { CommandMessage, CommandReply } from "../../shared/index.js";
import { createChildLogger } from "../../shared/logger/index.js";
@@ -157,8 +158,7 @@ export class VoiceHandler {
// .subscribe() which converts the connection to subscriber mode. Reusing
// the publish connection from CommandHandler would corrupt it and break
// every command reply + status update.
const { default: IORedis } = await import("ioredis");
const transmitRedis = new IORedis(config.REDIS_URL);
const transmitRedis = new Redis(config.REDIS_URL);
await voiceTransmitter.start(transmitRedis);
const status = voiceTransmitter.getStatus();