diff --git a/dave/bot.mjs b/dave/bot.mjs index e256688..4932055 100644 --- a/dave/bot.mjs +++ b/dave/bot.mjs @@ -167,9 +167,11 @@ client.once('clientReady', async () => { }); try { - await entersState(connection, VoiceConnectionStatus.Ready, 20_000); + // The DAVE/MLS handshake here cycles signalling<->connecting several times + // and can take ~25s, so give it a generous ceiling before declaring failure. + await entersState(connection, VoiceConnectionStatus.Ready, 40_000); } catch (e) { - log(`FATAL: voice connection did not become Ready in 20s (${e.message})`); + log(`FATAL: voice connection did not become Ready in 40s (${e.message})`); return leaveAndExit(1); } log(`✅ JOINED & READY. channel=${CHANNEL_ID} — staying connected, listening for speakers…`); @@ -196,6 +198,10 @@ client.once('clientReady', async () => { const decoder = new prism.opus.Decoder({ rate: 48000, channels: 2, frameSize: 960 }); const chunks = []; opusStream.on('data', () => { perUser.get(userId).opusPackets++; }); + // A receive-stream error (e.g. a DAVE decrypt/UDP GenericFailure on one + // packet) must NOT crash the process — log it and free the slot so the + // next utterance still works. + opusStream.on('error', (e) => { log(`recv stream error user=${userId}: ${e.message}`); active.delete(userId); }); opusStream.pipe(decoder); decoder.on('data', (d) => { chunks.push(d);