fix(gateway): establish selfbot voice connection eagerly so video (camera/screen-share) capture works
Video capture (camera + screen share) recorded ZERO frames because the selfbot ClientVoiceManager.connection was created LAZILY — only when a user started streaming. At that point the bot is already connected via @discordjs/voice, so the selfbot re-join never gets a fresh VOICE_SERVER_UPDATE and times out with VOICE_CONNECTION_TIMEOUT after 15s. joinStreamConnection (STREAM_WATCH) + receiver.createVideoStream both need that selfbot VoiceConnection CONNECTED. Fix: establish the selfbot VoiceConnection eagerly in recorder.startRecording, BEFORE joinVoiceChannel, so it rides the bot's fresh join (Discord emits VOICE_SERVER_UPDATE → selfbot authenticates). videoRecorder reuses the cached connection per guild, tears it down on voice stop/destroy. Best-effort — never blocks audio recording. Verified: typecheck + build + biome (src/) green; 9/9 videoRecorder tests.
This commit is contained in:
1 parent
6738279bad
commit
6aeebe7826
3 files changed
+196
-28
No files matched your search
@@ -1,5 +1,8 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
__resetVideoRecorderState,
|
||||
destroyGuildSelfbotVoice,
|
||||
ensureSelfbotVoice,
|
||||
setVideoRecorderClient,
|
||||
setVideoRecordingsDir,
|
||||
startVideoRecording,
|
||||
@@ -14,14 +17,17 @@ function makeVoiceManager() {
|
||||
on: vi.fn(),
|
||||
destroy: vi.fn(),
|
||||
};
|
||||
const watchConn = { sendSignalScreenshare: vi.fn(async () => {}) };
|
||||
const voiceConn = {
|
||||
status: 0, // VoiceStatus.CONNECTED
|
||||
disconnect: vi.fn(),
|
||||
receiver: {
|
||||
createVideoStream: vi.fn(() => recorder),
|
||||
},
|
||||
joinStreamConnection: vi.fn(async () => watchConn),
|
||||
};
|
||||
const watchConn = { sendSignalScreenshare: vi.fn(async () => {}) };
|
||||
return { voiceConn, watchConn, recorder, joinChannel: async () => voiceConn };
|
||||
const joinChannel = vi.fn(async () => voiceConn);
|
||||
return { voiceConn, watchConn, recorder, joinChannel };
|
||||
}
|
||||
|
||||
function makeChannel(guildId = "g1", channelId = "c1") {
|
||||
@@ -46,6 +52,7 @@ function makeUser() {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
__resetVideoRecorderState();
|
||||
setVideoRecordingsDir("/tmp/gmw-vidrec-test");
|
||||
});
|
||||
|
||||
@@ -117,4 +124,38 @@ describe("videoRecorder", () => {
|
||||
untrackChannel("g1");
|
||||
expect(client.voice.recorder.destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("ensureSelfbotVoice establishes and caches the selfbot connection (join once)", async () => {
|
||||
const client = makeClient();
|
||||
setVideoRecorderClient(client);
|
||||
const ch = makeChannel();
|
||||
const r1 = await ensureSelfbotVoice(ch);
|
||||
expect(r1?.status).toBe(0);
|
||||
expect(client.voice.joinChannel).toHaveBeenCalledTimes(1);
|
||||
// Second call reuses the cached CONNECTED connection — no re-join.
|
||||
const r2 = await ensureSelfbotVoice(makeChannel());
|
||||
expect(client.voice.joinChannel).toHaveBeenCalledTimes(1);
|
||||
expect(r2?.status).toBe(0);
|
||||
});
|
||||
|
||||
it("untrackChannel destroys the cached selfbot voice connection", async () => {
|
||||
const client = makeClient();
|
||||
setVideoRecorderClient(client);
|
||||
await ensureSelfbotVoice(makeChannel("g1", "c1"));
|
||||
const other = makeClient();
|
||||
setVideoRecorderClient(other);
|
||||
await ensureSelfbotVoice(makeChannel("g2", "c2"));
|
||||
untrackChannel("g1");
|
||||
expect(client.voice.voiceConn.disconnect).toHaveBeenCalled();
|
||||
// g2 connection untouched by g1 teardown
|
||||
expect(other.voice.voiceConn.disconnect).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("destroyGuildSelfbotVoice disconnects the selfbot connection", async () => {
|
||||
const client = makeClient();
|
||||
setVideoRecorderClient(client);
|
||||
await ensureSelfbotVoice(makeChannel());
|
||||
destroyGuildSelfbotVoice("g1");
|
||||
expect(client.voice.voiceConn.disconnect).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user