You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JDA v5 Discord机器人中启用语音模式并推送音频流

问题解决思路

你的核心问题是startStream方法里的死循环while(true)阻塞了JDA的事件线程。SlashCommandEvent的处理逻辑运行在JDA的事件分发线程中,这个线程被死循环占住后,JDA无法执行后续的音频调度逻辑,自然不会调用AudioSendHandler的canProvide()方法。

具体修复步骤

1. 移除阻塞事件线程的死循环

直接删掉while(true),JDA的音频连接会由内部线程自动维护,不需要手动用死循环保持。修改后的startStream方法:

public void startStream(SlashCommandEvent event) {
    AudioManager manager = Objects.requireNonNull(event.getGuild()).getAudioManager();
    AudioFormatter stream = new AudioFormatter();
    manager.setSendingHandler(stream);
    manager.setSpeakingMode(SpeakingMode.VOICE);
    if (event.getMember().getVoiceState().inAudioChannel()) {
        manager.openAudioConnection(event.getMember().getVoiceState().getChannel());
    }
    // 移除死循环,不要阻塞事件线程
}

2. 修正音频格式匹配Discord要求

Discord的语音服务要求音频为48kHz、16位、立体声、小端(little-endian)的PCM格式,你的当前格式设置了大端(最后一个参数true),需要改为false:

this.format = new AudioFormat((float)48000, 16, 2, true, false); // 最后一个参数改为false

3. 优化AudioFormatter的实现

  • 避免每次canProvide()都新建buffer,减少内存分配开销
  • 读取音频数据时检查实际读取字节数,确保传递有效数据
  • 确保TargetDataLine正确打开并启动采集

修改后的AudioFormatter:

public class AudioFormatter implements AudioSendHandler {
    private final AudioFormat format;
    private final TargetDataLine targetDataLine;
    private final byte[] buffer;
    private ByteBuffer returnedAudio;

    public AudioFormatter() {
        this.format = new AudioFormat(48000.0f, 16, 2, true, false); // 修正小端格式
        this.targetDataLine = AudioDevice.getAudioDevice();
        // 计算20ms音频所需字节数:48000采样率 * 2声道 * 2字节/采样 / 50(1秒含50个20ms片段)
        this.buffer = new byte[48000 * 2 * 2 / 50];
        try {
            targetDataLine.open(format);
            targetDataLine.start(); // 启动音频采集
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean canProvide() {
        int bytesRead = targetDataLine.read(buffer, 0, buffer.length);
        if (bytesRead <= 0) {
            return false; // 无有效数据时返回false
        }
        returnedAudio = ByteBuffer.wrap(buffer, 0, bytesRead); // 仅传递实际读取的有效字节
        return true;
    }

    @Nullable
    @Override
    public ByteBuffer provide20MsAudio() {
        return returnedAudio;
    }

    @Override
    public boolean isOpus() {
        return false;
    }
}

4. 验证音频设备获取逻辑

检查AudioDevice.getAudioDevice()的实现,确保它正确获取了系统的音频输入设备,没有抛出未捕获的异常。如果需要指定特定输入设备,可以通过AudioSystem.getMixerInfo()遍历设备后选择合适的目标线路。

内容的提问来源于stack exchange,提问作者kabaniery

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:07:34