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); }
验证步骤
- 确保机器人已正确连接到目标语音频道(
TTSBot.AudioClient不为null且处于活跃连接状态) - 运行
!tts命令,检查FFmpeg是否正常完成转码(日志无错误提示) - 观察语音频道是否能完整播放生成的TTS音频
内容的提问来源于stack exchange,提问作者Mingle
相关产品推荐
相关产品推荐

