我正在尝试用 Java 创建一个Discord Bot,使用Javacord和Lavaplayer库在语音频道上播放音乐,但是我在 Raspberry 上部署我的应用程序时遇到问题,我不明白问题出在哪里。
当我从我的 Eclipse(在 Windows 10 上)运行应用程序时,机器人运行良好并在 Discord 上播放音乐(通过 YouTube URL - 硬编码),但是当我尝试从我的 Raspberry 使用它并询问相同的命令时,机器人连接语音频道但没有声音播放!
我自己尝试了几件事(比如,听说过 Native Library,所以我在类路径中添加了“/natives/linux-arm/libconnector.so”)。我也没有在日志中看到错误。我自己找不到原因,所以我需要帮助找出问题出在哪里:(
PS:我不知道问题是来自 Java 代码还是 Raspberry 配置/规范
项目来源:
应用程序.java
package fr.exec;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.javacord.api.DiscordApi;
import org.javacord.api.DiscordApiBuilder;
/**
* Classe Application
*
* @author Jo44
* @version 1.0
* @since 30/03/2021
*/
public class Application {
/**
* Attributs
*/
private static final Logger logger = LogManager.getLogger(Application.class);
// Application
public static void main(String[] args) {
// Launch Bot
@SuppressWarnings("unused")
DiscordApi api = new DiscordApiBuilder().addListener(new MessageListener())
.setToken([TOKEN]).login().join();
logger.info("Bot is online & ready");
}
}
消息监听器.java
package fr.exec;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.javacord.api.audio.AudioSource;
import org.javacord.api.entity.channel.ServerVoiceChannel;
import org.javacord.api.entity.user.User;
import org.javacord.api.event.message.MessageCreateEvent;
import org.javacord.api.listener.message.MessageCreateListener;
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager;
import com.sedmelluq.discord.lavaplayer.source.youtube.YoutubeAudioSourceManager;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
/**
* Classe MessageListener
*
* @author Jo44
* @version 1.0
* @since 30/03/2021
*/
public class MessageListener implements MessageCreateListener {
private static final Logger logger = LogManager.getLogger(MessageListener.class);
/**
* Message Listener
*
* @param event
*/
@Override
public void onMessageCreate(MessageCreateEvent event) {
String cmd = event.getMessageContent().toLowerCase();
if (cmd.equals("!ping")) {
// Ping-pong
cmdPing(event);
} else if (cmd.equals("!sound")) {
// Sound
cmdSound(event);
}
}
/**
* Commande !ping
*
* @param event
*/
private static void cmdPing(MessageCreateEvent event) {
// Message
String message = "Pong!";
// Return message
event.getChannel().sendMessage(message);
// Log
logger.info(message);
}
/**
* Commande !sound
*
* @param event
* @param cmd
*/
private static void cmdSound(MessageCreateEvent event) {
// Get User
User user = event.getMessage().getAuthor().asUser().get();
// Get VoiceChannel where User is
long userVoiceChannelId = 0;
List<ServerVoiceChannel> voiceChannels = event.getServer().get().getVoiceChannels();
for (ServerVoiceChannel chan : voiceChannels) {
if (user.isConnected(chan)) {
userVoiceChannelId = chan.getId();
}
}
// If User is connected
if (userVoiceChannelId != 0) {
try {
// Javacord Wiki Part :
// https://javacord.org/wiki/advanced-topics/playing-audio.html#playing-music
// Do stuff
ServerVoiceChannel channel = event.getApi().getServerVoiceChannelById(userVoiceChannelId).get();
channel.connect().thenAccept(audioConnection -> {
// Create a player manager
AudioPlayerManager playerManager = new DefaultAudioPlayerManager();
playerManager.registerSourceManager(new YoutubeAudioSourceManager());
AudioPlayer player = playerManager.createPlayer();
// Create an audio source and add it to the audio connection's queue
AudioSource source = new LavaplayerAudioSource(event.getApi(), player);
audioConnection.setAudioSource(source);
// You can now use the AudioPlayer like you would normally do with Lavaplayer, e.g.,
playerManager.loadItem("https://www.youtube.com/watch?v=GX8Hg6kWQYI", new AudioLoadResultHandler() {
@Override
public void trackLoaded(AudioTrack track) {
player.playTrack(track);
}
@Override
public void playlistLoaded(AudioPlaylist playlist) {
for (AudioTrack track : playlist.getTracks()) {
player.playTrack(track);
}
}
@Override
public void noMatches() {
// Notify the user that we've got nothing
}
@Override
public void loadFailed(FriendlyException throwable) {
// Notify the user that everything exploded
}
});
}).exceptionally(e -> {
// Failed to connect to voice channel (no permissions?)
e.printStackTrace();
return null;
});
} catch (Exception ex) {
logger.error(ex.getMessage());
logger.error(ex.getStackTrace());
}
}
}
}
LavaplayerAudioSource.java
package fr.exec;
import org.javacord.api.DiscordApi;
import org.javacord.api.audio.AudioSource;
import org.javacord.api.audio.AudioSourceBase;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.AudioFrame;
public class LavaplayerAudioSource extends AudioSourceBase {
private final AudioPlayer audioPlayer;
private AudioFrame lastFrame;
/**
* Creates a new lavaplayer audio source.
*
* @param api
* A discord api instance.
* @param audioPlayer
* An audio player from Lavaplayer.
*/
public LavaplayerAudioSource(DiscordApi api, AudioPlayer audioPlayer) {
super(api);
this.audioPlayer = audioPlayer;
}
@Override
public byte[] getNextFrame() {
if (lastFrame == null) {
return null;
}
return applyTransformers(lastFrame.getData());
}
@Override
public boolean hasFinished() {
return false;
}
@Override
public boolean hasNextFrame() {
lastFrame = audioPlayer.provide();
return lastFrame != null;
}
@Override
public AudioSource copy() {
return new LavaplayerAudioSource(getApi(), audioPlayer);
}
}
项目下载: https ://drive.google.com/file/d/10-AFPNdJBkPhpSH-PtgiINloNP9VFRio/view?usp=sharing
调试日志:
2021-03-30 10:04:28 | DEBUG | (PrivacyProtectionLogger.java:51) - Creating shard 1 of 1
2021-03-30 10:04:30 | DEBUG | (PrivacyProtectionLogger.java:51) - Trying to send GET request to https://discord.com/api/v6/gateway
2021-03-30 10:04:31 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent GET request to https://discord.com/api/v6/gateway and received status code 200 with body {"url": "wss://gateway.discord.gg"}
2021-03-30 10:04:31 | DEBUG | (PrivacyProtectionLogger.java:51) - Calculated an offset of -540 to the Discord time.
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Received HELLO packet
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending identify packet
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued lifecycle frame for sending with priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":0}")
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:48) - Queued lifecycle frame for sending without priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=252,Payload="{"op":2,"d":{"token":"Bot **********","compress":true,"large_threshold":250,"properties":{"$os":"Linux","$browser":"Javacord","$device":"Javacord","$referrer":"","$referring_domain":""},"intents":32509}}")
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: false, packet: {"op":1,"d":0})
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending priority lifecycle frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":0}")
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:48) - Sending frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=252,Payload="{"op":2,"d":{"token":"Bot **********","compress":true,"large_threshold":250,"properties":{"$os":"Linux","$browser":"Javacord","$device":"Javacord","$referrer":"","$referring_domain":""},"intents":32509}}")
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: false, packet: {"t":null,"s":null,"op":11,"d":null}). Took 125 ms to receive ACK
2021-03-30 10:04:32 | DEBUG | (PrivacyProtectionLogger.java:51) - Received READY packet
2021-03-30 10:04:33 | DEBUG | (PrivacyProtectionLogger.java:51) - Trying to send GET request to https://discord.com/api/v6/oauth2/applications/@me
2021-03-30 10:04:33 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent GET request to https://discord.com/api/v6/oauth2/applications/@me and received status code 200 with body {"id": "[BOT ID]", "name": "[BOT NAME]", "icon": null, "description": "", "summary": "", "hook": true, "bot_public": true, "bot_require_code_grant": false, "verify_key": "[KEY]", "owner": {"id": "[OWNER ID]", "username": "[OWNER NAME]", "avatar": "[AVATAR]", "discriminator": "7460", "public_flags": 0, "flags": 0}, "team": null}
2021-03-30 10:04:33 | DEBUG | (PrivacyProtectionLogger.java:51) - Calculated an offset of -366 to the Discord time.
2021-03-30 10:04:33 | INFO | (Application.java:29) - Bot is online & ready
2021-03-30 10:04:41 | DEBUG | (PrivacyProtectionLogger.java:51) - Trying to send POST request to https://discord.com/api/v6/channels/[CHAN_ID]/messages with body {"content":"Pong!","tts":false,"mentions":[]}
2021-03-30 10:04:41 | INFO | (MessageListener.java:60) - Pong!
2021-03-30 10:04:41 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent POST request to https://discord.com/api/v6/channels/[CHAN_ID]/messages and received status code 200 with body {"id": "[ID]", "type": 0, "content": "Pong!", "channel_id": "[CHAN ID]", "author": {"id": "[BOT ID]", "username": "[BOT NAME]", "avatar": null, "discriminator": "3473", "public_flags": 0, "bot": true}, "attachments": [], "embeds": [], "mentions": [], "mention_roles": [], "pinned": false, "mention_everyone": false, "tts": false, "timestamp": "2021-03-30T08:04:41.469000+00:00", "edited_timestamp": null, "flags": 0, "referenced_message": null}
2021-03-30 10:05:02 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending VOICE_STATE_UPDATE packet for ServerVoiceChannel (id: [CHAN ID], name: [CHAN NAME]) on Server (id: [SERVER ID], name: [SERVER NAME])
2021-03-30 10:05:02 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued non-lifecycle frame for sending without priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=116,Payload="{"op":4,"d":{"guild_id":"[GUILD ID]","channel_id":"[CHAN ID]","self_mute":false,"self_deaf":false}}")
2021-03-30 10:05:02 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=116,Payload="{"op":4,"d":{"guild_id":"[GUILD ID]","channel_id":"[CHAN ID]","self_mute":false,"self_deaf":false}}")
2021-03-30 10:05:02 | DEBUG | (PrivacyProtectionLogger.java:51) - Received all information required to connect to voice channel ServerVoiceChannel (id: [CHAN ID], name: [CHAN NAME])
2021-03-30 10:05:02 | DEBUG | (PrivacyProtectionLogger.java:51) - Trying to connect to websocket wss://eu-central4013.discord.media:443?v=4
2021-03-30 10:05:03 | DEBUG | (PrivacyProtectionLogger.java:51) - Received HELLO packet for AudioConnection (channel: ServerVoiceChannel (id: [CHAN ID], name: [CHAN NAME]), sessionId: [SESSION ID], endpoint: eu-central4013.discord.media:443)
2021-03-30 10:05:03 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending voice identify packet for AudioConnection (channel: ServerVoiceChannel (id: [CHAN ID], name: [CHAN NAME]), sessionId: [SESSION ID], endpoint: eu-central4013.discord.media:443)
2021-03-30 10:05:03 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1636756561})
2021-03-30 10:05:03 | DEBUG | (PrivacyProtectionLogger.java:51) - Received READY packet for AudioConnection (channel: ServerVoiceChannel (id: [CHAN ID], name: [CHAN NAME]), sessionId: [SESSION ID], endpoint: eu-central4013.discord.media:443)
2021-03-30 10:05:03 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1636756561}). Took 71 ms to receive ACK
2021-03-30 10:05:13 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued lifecycle frame for sending with priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:05:13 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending priority lifecycle frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:05:13 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: false, packet: {"op":1,"d":9})
2021-03-30 10:05:13 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: false, packet: {"t":null,"s":null,"op":11,"d":null}). Took 121 ms to receive ACK
2021-03-30 10:05:16 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1340128277})
2021-03-30 10:05:16 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1340128277}). Took 42 ms to receive ACK
2021-03-30 10:05:30 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1763156639})
2021-03-30 10:05:30 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1763156639}). Took 36 ms to receive ACK
2021-03-30 10:05:44 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":913943586})
2021-03-30 10:05:44 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":913943586}). Took 48 ms to receive ACK
2021-03-30 10:05:54 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued lifecycle frame for sending with priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:05:54 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending priority lifecycle frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:05:54 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: false, packet: {"op":1,"d":9})
2021-03-30 10:05:54 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: false, packet: {"t":null,"s":null,"op":11,"d":null}). Took 137 ms to receive ACK
2021-03-30 10:05:58 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1280403229})
2021-03-30 10:05:58 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1280403229}). Took 49 ms to receive ACK
2021-03-30 10:06:11 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1680218539})
2021-03-30 10:06:11 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1680218539}). Took 47 ms to receive ACK
2021-03-30 10:06:25 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":1171436739})
2021-03-30 10:06:25 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":1171436739}). Took 35 ms to receive ACK
2021-03-30 10:06:36 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued lifecycle frame for sending with priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:06:36 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: false, packet: {"op":1,"d":9})
2021-03-30 10:06:36 | DEBUG | (PrivacyProtectionLogger.java:51) - Sending priority lifecycle frame WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=TEXT,Length=14,Payload="{"op":1,"d":9}")
2021-03-30 10:06:36 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: false, packet: {"t":null,"s":null,"op":11,"d":null}). Took 121 ms to receive ACK
2021-03-30 10:06:39 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":514863837})
2021-03-30 10:06:39 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":514863837}). Took 39 ms to receive ACK
2021-03-30 10:06:53 | DEBUG | (PrivacyProtectionLogger.java:51) - Sent heartbeat (voice: true, packet: {"op":3,"d":402475903})
2021-03-30 10:06:53 | DEBUG | (PrivacyProtectionLogger.java:51) - Heartbeat ACK received (voice: true, packet: {"op":6,"d":402475903}). Took 43 ms to receive ACK
2021-03-30 10:07:00 | DEBUG | (PrivacyProtectionLogger.java:51) - Queued lifecycle frame for sending without priority: WebSocketFrame(FIN=1,RSV1=0,RSV2=0,RSV3=0,Opcode=CLOSE,Length=2,CloseCode=1000,Reason=null)
2021-03-30 11:42:09 | INFO | (Application.java:29) - Bot is online & ready
2021-03-30 11:42:15 | INFO | (MessageListener.java:60) - Pong!
调试下载: https ://drive.google.com/file/d/1t8xwQcUx5VDpH0OVWxZnJb38eu5vgBpI/view?usp=sharing
Javacord 维基: https ://javacord.org/wiki/advanced-topics/playing-audio.html
开发计算机: Windows 10 Home - 20H2 - java 版本“1.8.0_281” - Java(TM) SE 运行时环境(内部版本 1.8.0_281-b09)- Java HotSpot(TM) 64 位服务器 VM(内部版本 25.281-b09,混合模式)
Raspberry Pi 3 Model B: Raspbian GNU/Linux 9.13(拉伸)-openjdk 版本“1.8.0_275”-OpenJDK 运行时环境(内部版本 1.8.0_275-8u275-b01-1~deb9u1-b01)-OpenJDK 客户端 VM(内部版本 25.275- b01,混合模式)