Search code examples
javamavenbotsdiscord-jda

What could be causing my Java Discord bot using Lavaplayer and Maven to not play music?


I am writing a music bot for discord. The program successfully finds and downloads music, but does not play it. No code works, even completely copied from a manual, whose author has similar versions, and his code performs its function. Further study of the problem led to the fact that the program hangs on the line (after stacktrace): player.startTrack(track, false); Hanging also happens if you replace the line above with: player.playTrack(track);

I found information published a few years ago that some platforms restricted access to downloads from them for bots. The guide I tested the code for was released in February of this year. I think the problem is on my side.

Also, when using /play, I tried to enter links to different platforms and tracks on them, but nothing helps. Maybe i should specify some intentions in the code?

Code:

  • Main
public static void main(String[] args) throws Exception {
        JDA jda = JDABuilder.createDefault(TOKEN).setChunkingFilter(ChunkingFilter.ALL)
                .setMemberCachePolicy(MemberCachePolicy.ALL).enableIntents(GatewayIntent.GUILD_MEMBERS,
                        GatewayIntent.GUILD_MESSAGES,
                        GatewayIntent.GUILD_VOICE_STATES).build();
        jda.addEventListener(new checker()); 
    }  
  • AudioSendHandler
public class AudioForwarder implements AudioSendHandler {

   private final AudioPlayer player;
   private final Guild guild;
   private final ByteBuffer buffer = ByteBuffer.allocate(1024);
   private final MutableAudioFrame frame = new MutableAudioFrame();
   private int time;

   public AudioForwarder(AudioPlayer player, Guild guild) {
       this.player = player;
       this.guild = guild;
       frame.setBuffer(buffer);
   }

   @Override
   public boolean canProvide() {
       boolean canProvide = player.provide(frame);
       if(!canProvide) {
           time += 20;
           if (time >= 300000) {
               time = 0;
               System.out.println("timeout");
               guild.getAudioManager().closeAudioConnection();
           }
       } else {
           time = 0;
       }
       return canProvide;
   }

   @Nullable
   @Override
   public ByteBuffer provide20MsAudio() {
       final Buffer tmp = ((Buffer) buffer).flip();

       return (ByteBuffer) tmp;
   }

   @Override
   public boolean isOpus() {
       return true;
   }
}
  • TrackScheduler
public class TrackScheduler extends AudioEventAdapter {

    private final AudioPlayer player;
    private final BlockingQueue<AudioTrack> queue = new LinkedBlockingQueue<>();
    private boolean isRepeat = false;

    public TrackScheduler(AudioPlayer player) {
        this.player = player;
    }

    @Override
    public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
        if(isRepeat) {
            System.out.println("6");
            player.startTrack(track.makeClone(), false);
            System.out.println("7");
        } else {
            System.out.println("8");
            player.startTrack(queue.poll(), false);
            System.out.println("9");
        }
    }

    public void queue(AudioTrack track) {
        if(!player.startTrack(track, true)) {
            System.out.println("1");
            queue.offer(track);
            System.out.println("2");
        } else {
            System.out.println("3");
            StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
            for (StackTraceElement element:stackTraceElements) {
                System.out.println(element.getMethodName());
            }
            player.startTrack(track, false);
            System.out.println("4");
        }
    }

    public AudioPlayer getPlayer() {
        return player;
    }

    public BlockingQueue<AudioTrack> getQueue() {
        return queue;
    }

    public boolean isRepeat() {
        return isRepeat;
    }

    public void setRepeat(boolean repeat) {
        isRepeat = repeat;
    }
}
  • GuildMusicManager
public class GuildMusicManager {

    private TrackScheduler trackScheduler;
    private AudioForwarder audioForwarder;

    public GuildMusicManager(AudioPlayerManager manager, Guild guild) {
        AudioPlayer player = manager.createPlayer();
        trackScheduler = new TrackScheduler(player);
        player.addListener(trackScheduler);
        audioForwarder = new AudioForwarder(player, guild);
    }

    public TrackScheduler getTrackScheduler() {
        return trackScheduler;
    }

    public AudioForwarder getAudioForwarder() {
        return audioForwarder;
    }
}
  • PlayerManager
public class PlayerManager {

    private static PlayerManager INSTANCE;
    private final Map<Long, GuildMusicManager> guildMusicManagers = new HashMap<>();
    private final AudioPlayerManager audioPlayerManager = new DefaultAudioPlayerManager();

    private PlayerManager() {
        AudioSourceManagers.registerRemoteSources(audioPlayerManager);
        AudioSourceManagers.registerLocalSource(audioPlayerManager);
    }

    public static PlayerManager get() {
        if(INSTANCE == null) {
            INSTANCE = new PlayerManager();
        }
        return INSTANCE;
    }

    public GuildMusicManager getGuildMusicManager(Guild guild) {
        return guildMusicManagers.computeIfAbsent(guild.getIdLong(), (guildId) -> {
            GuildMusicManager musicManager = new GuildMusicManager(audioPlayerManager, guild);

            guild.getAudioManager().setSendingHandler(musicManager.getAudioForwarder());

            return musicManager;
        });
    }

    public void play(Guild guild, String trackURL) {
        GuildMusicManager guildMusicManager = getGuildMusicManager(guild);
        audioPlayerManager.loadItemOrdered(guildMusicManager, trackURL, new AudioLoadResultHandler() {
            @Override
            public void trackLoaded(AudioTrack track) {
                System.out.println("0");
                guildMusicManager.getTrackScheduler().queue(track);
                System.out.println("5");
            }

            @Override
            public void playlistLoaded(AudioPlaylist playlist) {
                System.out.println("0.1");
                guildMusicManager.getTrackScheduler().queue(playlist.getTracks().get(0));
                System.out.println("5.1");
            }

            @Override
            public void noMatches() {
                System.out.println("no_matches");
            }

            @Override
            public void loadFailed(FriendlyException exception) {
                System.out.println("failed");
            }
        });
    }
}
  • /play
public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) {
     if (event.getName().equals("play")) {
                event.getGuild().getAudioManager().openAudioConnection(event.getMember().getVoiceState().getChannel());

                String name = event.getOption("name").getAsString();
                try {
                    new URI(name);
                } catch (URISyntaxException e) {
                    name = name + "ytsearch:";
                }
                PlayerManager playerManager = PlayerManager.get();
                event.reply("Playing").setEphemeral(true).submit();
                playerManager.play(event.getGuild(), name);
        }
}

Console output

After using /play, the bot successfully connects to the voice channel, but immediately starts reconnecting to it every few seconds without playing music.

On the discord developer portal, all intents are enabled, on the test server the bot has administrator rights, the role of the bot is prioritized above all others.

My versions:

JDA 5.0.0-alpha.11

lavaplayer 1.3.77

P.S. updated: Moved to version of JDA 5.0.0-beta.9. The hanging is gone, but the program still doesn't play sound, and this time I don't understand what's going on there. Updated code above and screenshot of console output.

If you move the stacktrace to the place where the code reaches during /play:

Console output 2


Solution

  • After I upgraded to the latest version of JDA, the problem was due to incorrect program logic. Remove the else block in the question code:

    Instead of:

        public void queue(AudioTrack track) {
            if(!player.startTrack(track, true)) {
                System.out.println("1");
                queue.offer(track);
                System.out.println("2");
            } else {
                System.out.println("3");
                StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
                for (StackTraceElement element:stackTraceElements) {
                    System.out.println(element.getMethodName());
                }
                player.startTrack(track, false);
                System.out.println("4");
            }
        }
    

    This:

        public void queue(AudioTrack track) {
            if(!player.startTrack(track, true)) {
                queue.offer(track);
            }
        }