From fa5a6aab8f974b889d32afebcb40737346c0b793 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Mon, 13 Jul 2026 00:06:22 +0200 Subject: [PATCH] fix: JDAVoiceUpdateListener null channel race drops voice server update The local copy of JDAVoiceUpdateListener.onVoiceServerUpdate() checked if the bot's cached voice channel was null and returned early, silently dropping the voice server update. Discord often sends the voice server update BEFORE the voice state update is processed by JDA, so the channel was always null on first attempt -> Lavalink never received the update -> voice connection never established -> timeout. Fix: pass null channelId to Lavalink's VoiceState instead of aborting. This matches the Kotlin original library code. --- .../loki/feature/radio/RadioManager.java | 18 ++---------------- .../libraries/jda/JDAVoiceUpdateListener.java | 4 ++-- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/main/java/creator/loki/feature/radio/RadioManager.java b/src/main/java/creator/loki/feature/radio/RadioManager.java index f37716a..0c672c1 100644 --- a/src/main/java/creator/loki/feature/radio/RadioManager.java +++ b/src/main/java/creator/loki/feature/radio/RadioManager.java @@ -97,22 +97,8 @@ public class RadioManager { logger.warn("Radio: self member is null for guild {}", guildId); return; } - logger.debug( - "Radio: initial voice state for guild {}: inAudioChannel={}", - guildId, - self.getVoiceState().inAudioChannel()); - for (int i = 0; i < 25; i++) { - if (self.getVoiceState().inAudioChannel()) break; - logger.debug( - "Radio: waiting for voice state in guild {} (attempt {})", guildId, i + 1); - try { - Thread.sleep(200); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } - if (!self.getVoiceState().inAudioChannel()) { + if (!VoiceHelper.waitForCondition( + () -> self.getVoiceState().inAudioChannel(), VOICE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { logger.warn( "Radio: voice connection timeout for guild {} (channel: {})", guildId, diff --git a/src/main/java/dev/arbjerg/lavalink/libraries/jda/JDAVoiceUpdateListener.java b/src/main/java/dev/arbjerg/lavalink/libraries/jda/JDAVoiceUpdateListener.java index 56b1909..62e2ca9 100644 --- a/src/main/java/dev/arbjerg/lavalink/libraries/jda/JDAVoiceUpdateListener.java +++ b/src/main/java/dev/arbjerg/lavalink/libraries/jda/JDAVoiceUpdateListener.java @@ -27,9 +27,9 @@ public class JDAVoiceUpdateListener implements VoiceDispatchInterceptor { if (selfMember == null) return; AudioChannel channel = selfMember.getVoiceState().getChannel(); - if (channel == null) return; + String channelId = channel != null ? String.valueOf(channel.getId()) : null; - VoiceState state = new VoiceState(token, endpoint, sessionId, channel.getId()); + VoiceState state = new VoiceState(token, endpoint, sessionId, channelId); VoiceRegion region = VoiceRegion.Companion.fromEndpoint(endpoint); lavalink.getOrCreateLink(guild.getIdLong(), region).onVoiceServerUpdate(state); }