feat: improve webcam recording startup reliability

- Add longer wait time (5s) for SSRC mapping establishment
- Add camera detection retry logic with 10s timeout
- Add webcam stream creation retry mechanism
- Enhance debug voice command with SSRC mapping information
- Better error handling and user feedback during setup
This commit is contained in:
Mikolaj Wojciech Gorski 2025-07-26 16:32:36 +02:00
parent b904653535
commit 1886ea7c94
3 changed files with 82 additions and 8 deletions

@ -1 +1 @@
Subproject commit 654454e68decd7aaff3d7eea14c769a3eca8839a Subproject commit 094176414b94e6f01c9460c060834d4bee3be4d7

View file

@ -338,6 +338,30 @@ class CommandHandler {
voiceChannel.guild?.voiceStates.cache.get(msg.author.id) || voiceChannel.guild?.voiceStates.cache.get(msg.author.id) ||
context.client.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 = [ const debugInfo = [
"🔍 **Voice State Debug Info**", "🔍 **Voice State Debug Info**",
`📍 Channel: ${voiceChannel.name} (${voiceChannel.id})`, `📍 Channel: ${voiceChannel.name} (${voiceChannel.id})`,
@ -359,6 +383,7 @@ class CommandHandler {
const otherState = voiceChannel.guild?.voiceStates.cache.get(m.id); const otherState = voiceChannel.guild?.voiceStates.cache.get(m.id);
return `${m.user.tag}: selfVideo=${otherState?.selfVideo}, streaming=${otherState?.streaming}`; return `${m.user.tag}: selfVideo=${otherState?.selfVideo}, streaming=${otherState?.streaming}`;
}), }),
...ssrcInfo,
].join("\n"); ].join("\n");
msg.channel.send(debugInfo); msg.channel.send(debugInfo);

View file

@ -54,16 +54,65 @@ class WebcamRecordingService {
`[Docker] Successfully joined voice channel for webcam recording` `[Docker] Successfully joined voice channel for webcam recording`
); );
// Wait for connection to be fully established // Wait longer for connection and SSRC mapping to be fully established
await new Promise((resolve) => setTimeout(resolve, 2000)); 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}`); console.log(`[Docker] Creating webcam stream for user ${user.id}`);
// Create webcam stream directly through voice connection receiver // Create webcam stream with retry logic
const webcamStream = connection.receiver.createWebcamStream( let webcamStream;
let streamRetries = 0;
const maxStreamRetries = 3;
while (streamRetries < maxStreamRetries) {
try {
webcamStream = connection.receiver.createWebcamStream(
user.id, user.id,
createWriteStream(webcamPath) 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 // Set up webcam stream event handlers
this._setupWebcamStreamHandlers( this._setupWebcamStreamHandlers(