Fix: Reuse voice connection when switching radio stations
Instead of destroying and recreating the voice connection on every station change, now checks if the bot is already in the target channel. If same channel: only stops ffmpeg/player, spawns new stream, reuses the existing connection (no reconnect flicker). If different channel: full disconnect + reconnect as before. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
63afc55836
commit
b821ad9615
1 changed files with 45 additions and 19 deletions
|
|
@ -70,13 +70,20 @@ function setFavorites(favs: Favorite[]): void {
|
|||
}
|
||||
|
||||
// ── Streaming ──
|
||||
function stopStream(guildId: string): void {
|
||||
|
||||
/** Stop only audio (ffmpeg + player), keep voice connection alive */
|
||||
function stopAudio(guildId: string): void {
|
||||
const state = guildRadioState.get(guildId);
|
||||
if (!state) return;
|
||||
try { state.ffmpeg.kill('SIGKILL'); } catch {}
|
||||
try { state.player.stop(true); } catch {}
|
||||
try { getVoiceConnection(guildId, 'radio')?.destroy(); } catch {}
|
||||
guildRadioState.delete(guildId);
|
||||
}
|
||||
|
||||
/** Full stop: audio + voice connection + broadcast */
|
||||
function stopStream(guildId: string): void {
|
||||
stopAudio(guildId);
|
||||
try { getVoiceConnection(guildId, 'radio')?.destroy(); } catch {}
|
||||
connectedSince.delete(guildId);
|
||||
broadcastState(guildId);
|
||||
console.log(`[Radio] Stopped stream in guild ${guildId}`);
|
||||
|
|
@ -86,12 +93,23 @@ async function startStream(
|
|||
ctx: PluginContext, guildId: string, voiceChannelId: string,
|
||||
stationId: string, stationName: string, placeName: string, country: string,
|
||||
): Promise<{ ok: boolean; error?: string }> {
|
||||
// Stoppe laufenden Stream in diesem Guild
|
||||
stopStream(guildId);
|
||||
// Check if we can reuse the existing voice connection
|
||||
const prev = guildRadioState.get(guildId);
|
||||
const existingConn = getVoiceConnection(guildId, 'radio');
|
||||
const sameChannel = prev && existingConn && prev.channelId === voiceChannelId
|
||||
&& existingConn.state.status === VoiceConnectionStatus.Ready;
|
||||
|
||||
// Stop only audio (keep connection if same channel)
|
||||
stopAudio(guildId);
|
||||
|
||||
// Stream-URL auflösen
|
||||
const streamUrl = await resolveStreamUrl(stationId);
|
||||
if (!streamUrl) return { ok: false, error: 'Stream-URL konnte nicht aufgelöst werden' };
|
||||
if (!streamUrl) {
|
||||
// No stream → full disconnect if nothing playing
|
||||
if (!sameChannel) try { existingConn?.destroy(); } catch {}
|
||||
broadcastState(guildId);
|
||||
return { ok: false, error: 'Stream-URL konnte nicht aufgelöst werden' };
|
||||
}
|
||||
|
||||
// Guild + Channel finden
|
||||
const guild = ctx.client.guilds.cache.get(guildId);
|
||||
|
|
@ -99,8 +117,14 @@ async function startStream(
|
|||
const channel = guild.channels.cache.get(voiceChannelId) as VoiceBasedChannel | undefined;
|
||||
if (!channel) return { ok: false, error: 'Voice Channel nicht gefunden' };
|
||||
|
||||
// Voice-Channel joinen
|
||||
const connection = joinVoiceChannel({
|
||||
// Reuse or create voice connection
|
||||
let connection = sameChannel ? existingConn! : null;
|
||||
if (!connection) {
|
||||
// Different channel or no connection → full join
|
||||
try { existingConn?.destroy(); } catch {}
|
||||
connectedSince.delete(guildId);
|
||||
|
||||
connection = joinVoiceChannel({
|
||||
channelId: voiceChannelId,
|
||||
guildId,
|
||||
adapterCreator: guild.voiceAdapterCreator,
|
||||
|
|
@ -114,6 +138,7 @@ async function startStream(
|
|||
connection.destroy();
|
||||
return { ok: false, error: 'Voice-Verbindung fehlgeschlagen' };
|
||||
}
|
||||
}
|
||||
|
||||
// ffmpeg spawnen – Radio-Stream → raw PCM
|
||||
const ffmpeg = spawn('ffmpeg', [
|
||||
|
|
@ -138,6 +163,7 @@ async function startStream(
|
|||
console.log(`[Radio] ffmpeg exited (code ${code}), cleaning up`);
|
||||
guildRadioState.delete(guildId);
|
||||
try { getVoiceConnection(guildId, 'radio')?.destroy(); } catch {}
|
||||
connectedSince.delete(guildId);
|
||||
broadcastState(guildId);
|
||||
}
|
||||
});
|
||||
|
|
@ -169,7 +195,7 @@ async function startStream(
|
|||
});
|
||||
|
||||
broadcastState(guildId);
|
||||
console.log(`[Radio] ▶ "${stationName}" (${placeName}, ${country}) → ${guild.name}/#${channelName}`);
|
||||
console.log(`[Radio] ${sameChannel ? '\u{1F504}' : '\u25B6'} "${stationName}" (${placeName}, ${country}) → ${guild.name}/#${channelName}`);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue