fix(bot): tolerate slow DAVE join + never crash on a receive-stream error

- Raise the voice-Ready ceiling 20s->40s: the DAVE/MLS handshake cycles
  signalling<->connecting and can take ~25s, so 20s spuriously failed the join.
- Handle AudioReceiveStream 'error' (e.g. a DAVE decrypt/UDP GenericFailure on
  one packet): log and free the speaker slot instead of letting the unhandled
  'error' event crash the whole bot process.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-08-18 22:05:57 +09:00
parent 0f94245d5f
commit 95e2d4472b

View File

@@ -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);