diff --git a/discord.js-selfbot-v13 b/discord.js-selfbot-v13 index 654454e..0941764 160000 --- a/discord.js-selfbot-v13 +++ b/discord.js-selfbot-v13 @@ -1 +1 @@ -Subproject commit 654454e68decd7aaff3d7eea14c769a3eca8839a +Subproject commit 094176414b94e6f01c9460c060834d4bee3be4d7 diff --git a/src/services/commandHandler.js b/src/services/commandHandler.js index e8a114f..06dd863 100644 --- a/src/services/commandHandler.js +++ b/src/services/commandHandler.js @@ -338,6 +338,30 @@ class CommandHandler { voiceChannel.guild?.voiceStates.cache.get(msg.author.id) || context.client.voiceStates.cache.get(msg.author.id); + // Get voice connection and SSRC info if available + const voiceConnection = context.client.voice.connections.get( + voiceChannel.guild.id + ); + let ssrcInfo = []; + + if (voiceConnection && voiceConnection.ssrcMap) { + ssrcInfo = [ + "", + "**🔊 SSRC Mapping:**", + `• Connection status: ${voiceConnection.status}`, + `• Total mapped SSRCs: ${voiceConnection.ssrcMap.size}`, + ...Array.from(voiceConnection.ssrcMap.entries()).map( + ([ssrc, data]) => { + const streamType = data.streamType + ? ` (${data.streamType})` + : ""; + const quality = data.quality ? ` Q:${data.quality}` : ""; + return `• SSRC ${ssrc}: ${data.userId}${streamType}${quality}`; + } + ), + ]; + } + const debugInfo = [ "🔍 **Voice State Debug Info**", `📍 Channel: ${voiceChannel.name} (${voiceChannel.id})`, @@ -359,6 +383,7 @@ class CommandHandler { const otherState = voiceChannel.guild?.voiceStates.cache.get(m.id); return `• ${m.user.tag}: selfVideo=${otherState?.selfVideo}, streaming=${otherState?.streaming}`; }), + ...ssrcInfo, ].join("\n"); msg.channel.send(debugInfo); diff --git a/src/services/webcamRecording.js b/src/services/webcamRecording.js index 5e843c7..f0a7284 100644 --- a/src/services/webcamRecording.js +++ b/src/services/webcamRecording.js @@ -54,16 +54,65 @@ class WebcamRecordingService { `[Docker] Successfully joined voice channel for webcam recording` ); - // Wait for connection to be fully established - await new Promise((resolve) => setTimeout(resolve, 2000)); + // Wait longer for connection and SSRC mapping to be fully established + await new Promise((resolve) => setTimeout(resolve, 5000)); + + // Wait for user's camera to be detected in voice state + let retries = 0; + const maxRetries = 10; + while (retries < maxRetries) { + const voiceState = voiceChannel.guild?.voiceStates.cache.get(user.id); + if (voiceState && voiceState.selfVideo) { + console.log( + `[Docker] Camera detected for user ${user.id} after ${retries} retries` + ); + break; + } + console.log( + `[Docker] Waiting for camera to be detected for user ${user.id}... (${ + retries + 1 + }/${maxRetries})` + ); + await new Promise((resolve) => setTimeout(resolve, 1000)); + retries++; + } + + if (retries === maxRetries) { + console.log( + `[Docker] Camera not detected after ${maxRetries} retries, proceeding anyway...` + ); + } console.log(`[Docker] Creating webcam stream for user ${user.id}`); - // Create webcam stream directly through voice connection receiver - const webcamStream = connection.receiver.createWebcamStream( - user.id, - createWriteStream(webcamPath) - ); + // Create webcam stream with retry logic + let webcamStream; + let streamRetries = 0; + const maxStreamRetries = 3; + + while (streamRetries < maxStreamRetries) { + try { + webcamStream = connection.receiver.createWebcamStream( + user.id, + createWriteStream(webcamPath) + ); + console.log(`[Docker] Webcam stream created successfully`); + break; + } catch (error) { + streamRetries++; + console.log( + `[Docker] Failed to create webcam stream (attempt ${streamRetries}/${maxStreamRetries}):`, + error.message + ); + + if (streamRetries === maxStreamRetries) { + throw error; + } + + // Wait before retry + await new Promise((resolve) => setTimeout(resolve, 2000)); + } + } // Set up webcam stream event handlers this._setupWebcamStreamHandlers(