debug: add voice adapter wrapper to trace gateway communication
Logs sendPayload calls (op code, result), onVoiceServerUpdate and onVoiceStateUpdate to identify why connection stays at signalling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5faf5139ef
commit
cc5e21fe1c
1 changed files with 34 additions and 7 deletions
|
|
@ -238,7 +238,7 @@ async function ensureConnectionReady(connection: VoiceConnection, channelId: str
|
|||
try { connection.destroy(); } catch {}
|
||||
guildAudioState.delete(guildId);
|
||||
console.log(`${SB} Creating fresh connection (attempt 3)...`);
|
||||
const newConn = joinVoiceChannel({ channelId, guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const newConn = joinVoiceChannel({ channelId, guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
try { await entersState(newConn, VoiceConnectionStatus.Ready, 15_000); console.log(`${SB} Connection ready (fresh)`); return newConn; }
|
||||
catch (e) { console.error(`${SB} All 3 connection attempts failed: ${(e as Error)?.message ?? e}`); try { newConn.destroy(); } catch {} guildAudioState.delete(guildId); throw new Error('Voice connection failed after 3 attempts'); }
|
||||
}
|
||||
|
|
@ -267,13 +267,13 @@ function attachVoiceLifecycle(state: GuildAudioState, guild: any) {
|
|||
catch {
|
||||
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { reconnectAttempts++; console.log(`${SB} Rejoin attempt ${reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`); connection.rejoin({ channelId: state.channelId, selfDeaf: false, selfMute: false }); }
|
||||
else { reconnectAttempts = 0; console.log(`${SB} Max reconnect attempts reached, creating fresh connection`); try { connection.destroy(); } catch {}
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
state.connection = nc; nc.subscribe(state.player); attachVoiceLifecycle(state, guild); }
|
||||
}
|
||||
} else if (newS.status === VoiceConnectionStatus.Destroyed) {
|
||||
console.warn(`${SB} Connection destroyed, recreating...`);
|
||||
connectedSince.delete(state.guildId);
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
state.connection = nc; nc.subscribe(state.player); attachVoiceLifecycle(state, guild);
|
||||
} else if (newS.status === VoiceConnectionStatus.Connecting || newS.status === VoiceConnectionStatus.Signalling) {
|
||||
isReconnecting = true;
|
||||
|
|
@ -284,7 +284,7 @@ function attachVoiceLifecycle(state: GuildAudioState, guild: any) {
|
|||
console.warn(`${SB} Timeout waiting for Ready from ${newS.status} (attempt ${reconnectAttempts}): ${(e as Error)?.message ?? e}`);
|
||||
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) { await new Promise(r => setTimeout(r, reconnectAttempts * 2000)); isReconnecting = false; connection.rejoin({ channelId: state.channelId, selfDeaf: false, selfMute: false }); }
|
||||
else { reconnectAttempts = 0; isReconnecting = false; console.error(`${SB} Max attempts from ${newS.status}, fresh connection`); try { connection.destroy(); } catch {}
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const nc = joinVoiceChannel({ channelId: state.channelId, guildId: state.guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
state.connection = nc; nc.subscribe(state.player); attachVoiceLifecycle(state, guild); }
|
||||
}
|
||||
}
|
||||
|
|
@ -293,6 +293,33 @@ function attachVoiceLifecycle(state: GuildAudioState, guild: any) {
|
|||
(connection as any).__lifecycleAttached = true;
|
||||
}
|
||||
|
||||
// ── Debug adapter wrapper ──
|
||||
function debugAdapterCreator(guild: any): any {
|
||||
const original = guild.voiceAdapterCreator;
|
||||
return (methods: any) => {
|
||||
const wrappedMethods = {
|
||||
...methods,
|
||||
sendPayload(payload: any) {
|
||||
const result = methods.sendPayload(payload);
|
||||
console.log(`${SB} adapter.sendPayload op=${payload?.op ?? '?'} d.channel_id=${payload?.d?.channel_id ?? '?'} → ${result}`);
|
||||
return result;
|
||||
},
|
||||
};
|
||||
const adapter = original(wrappedMethods);
|
||||
const origVSU = adapter.onVoiceServerUpdate;
|
||||
const origVStU = adapter.onVoiceStateUpdate;
|
||||
adapter.onVoiceServerUpdate = (data: any) => {
|
||||
console.log(`${SB} adapter.onVoiceServerUpdate: token=${data?.token ? 'yes' : 'no'} endpoint=${data?.endpoint ?? 'none'}`);
|
||||
return origVSU(data);
|
||||
};
|
||||
adapter.onVoiceStateUpdate = (data: any) => {
|
||||
console.log(`${SB} adapter.onVoiceStateUpdate: session_id=${data?.session_id ? 'yes' : 'no'} channel_id=${data?.channel_id ?? 'none'}`);
|
||||
return origVStU(data);
|
||||
};
|
||||
return adapter;
|
||||
};
|
||||
}
|
||||
|
||||
// ── Playback ──
|
||||
let _pluginCtx: PluginContext | null = null;
|
||||
|
||||
|
|
@ -305,7 +332,7 @@ async function playFilePath(guildId: string, channelId: string, filePath: string
|
|||
let state = guildAudioState.get(guildId);
|
||||
if (!state) {
|
||||
console.log(`${SB} No existing audio state, creating new connection...`);
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
const player = createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
||||
connection.subscribe(player);
|
||||
state = { connection, player, guildId, channelId, currentVolume: getPersistedVolume(guildId) };
|
||||
|
|
@ -322,7 +349,7 @@ async function playFilePath(guildId: string, channelId: string, filePath: string
|
|||
const current = getVoiceConnection(guildId);
|
||||
if (current && current.joinConfig?.channelId !== channelId) {
|
||||
current.destroy();
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
const player = state.player ?? createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
||||
connection.subscribe(player);
|
||||
state = { connection, player, guildId, channelId, currentVolume: state.currentVolume ?? getPersistedVolume(guildId) };
|
||||
|
|
@ -333,7 +360,7 @@ async function playFilePath(guildId: string, channelId: string, filePath: string
|
|||
} catch {}
|
||||
|
||||
if (!getVoiceConnection(guildId)) {
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: guild.voiceAdapterCreator as any, selfMute: false, selfDeaf: false });
|
||||
const connection = joinVoiceChannel({ channelId, guildId, adapterCreator: debugAdapterCreator(guild), selfMute: false, selfDeaf: false });
|
||||
const player = state?.player ?? createAudioPlayer({ behaviors: { noSubscriber: NoSubscriberBehavior.Play } });
|
||||
connection.subscribe(player);
|
||||
state = { connection, player, guildId, channelId, currentVolume: state?.currentVolume ?? getPersistedVolume(guildId) };
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue