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

Discord.Net机器人语音频道发送MP3音频失败:FlushAsync调用异常问题求助

问题排查与修复方案

从你的代码和FFmpeg日志来看,FFmpeg的转码流程是完全正常的(日志显示已完整处理音频文件并输出符合Discord要求的PCM格式),问题大概率出在音频流的生命周期管理上,尤其是FlushAsync后的流关闭逻辑,以及文件生成的同步问题。下面是具体的排查点和修复步骤:

1. 核心问题:未正确管理音频流与FFmpeg进程

你的SendAsync方法中,完成CopyToAsync后只调用了FlushAsync,但没有正确关闭Discord的PCM流,也没有等待FFmpeg进程完全退出。Discord的音频客户端需要明确的结束信号,否则可能会丢弃未完成的缓冲数据,导致FlushAsync看似失效。

修复后的SendAsync方法

public async Task SendAsync(IAudioClient client, string path)
{
    // 使用using语句自动释放资源,避免内存泄漏
    using var ffmpegProcess = CreateStream(path);
    using var ffmpegOutput = ffmpegProcess.StandardOutput.BaseStream;
    using var discordStream = client.CreatePCMStream(AudioApplication.Mixed);

    // 复制音频数据到Discord流
    await ffmpegOutput.CopyToAsync(discordStream);
    
    // 发送空字节数组作为音频结束标记(Discord需要这个来确认流结束)
    await discordStream.WriteAsync(Array.Empty<byte>());
    await discordStream.FlushAsync();
    
    // 等待FFmpeg进程完全退出,确保所有数据都已输出完毕
    await ffmpegProcess.WaitForExitAsync();
}

2. 潜在问题:TTS文件生成的同步问题

你的Say方法中直接调用MakeTTS(text)后就立即读取文件,如果MakeTTS是异步生成音频文件的(比如调用远程TTS API或异步写入磁盘),会导致FFmpeg读取到不完整的文件,进而引发音频播放异常。

修复方案

如果MakeTTS是异步方法,一定要加上await等待文件生成完成:

[Command("tts", RunMode = RunMode.Async)]
public async Task Say()
{
    IAudioClient audioClient = TTSBot.AudioClient;
    // 优化命令内容截取:避免手动截取出错,建议用后续的参数绑定方式
    string text = Context.Message.Content.Substring(Context.Message.Content.IndexOf(' ') + 1);
    
    // 如果MakeTTS是异步方法,必须await确保文件写入完成
    await MakeTTS(text);
    
    string path = Path.GetFullPath("tts.mp3");
    await SendAsync(audioClient, path);
    // 无需额外Task.Delay,SendAsync已处理完所有流程
}

更优雅的方式是使用Discord.Net的参数绑定,彻底避免手动截取字符串的问题:

[Command("tts", RunMode = RunMode.Async)]
public async Task Say([Remainder] string text)
{
    IAudioClient audioClient = TTSBot.AudioClient;
    await MakeTTS(text);
    string path = Path.GetFullPath("tts.mp3");
    await SendAsync(audioClient, path);
}

3. 额外优化:FFmpeg参数调整

虽然当前FFmpeg参数能正常工作,但可以做一些优化提升稳定性:

private Process CreateStream(string path)
{
    ProcessStartInfo ffmpeg = new ProcessStartInfo
    {
        FileName = "ffmpeg",
        // 添加-y参数自动覆盖已存在的tts.mp3文件,避免文件占用冲突
        // 替换loglevel为error减少冗余日志输出
        Arguments = $@"-y -hide_banner -loglevel error -i ""{path}"" -ac 2 -f s16le -ar 48000 pipe:1 ",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true // 设为true避免弹出FFmpeg控制台窗口
    };
    return Process.Start(ffmpeg);
}

验证步骤

  1. 确保机器人已正确连接到目标语音频道(TTSBot.AudioClient不为null且处于活跃连接状态)
  2. 运行!tts命令,检查FFmpeg是否正常完成转码(日志无错误提示)
  3. 观察语音频道是否能完整播放生成的TTS音频

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:47:28