我正在使用Discord.Net包装器在VS2017中编写Discord Bot。除了主要目标:在语音通道中使用TTS音频输出流之外,我已经完成了所有工作(解析/发送文本命令,加入语音通道)。

基本上,我正在使用SpeechSynthesizer创建MemoryStream并将其写入Discord机器人。问题是,没有音频。完全没有我一直在关注其他几个答案以及Discord.Net网站上的文档,但似乎找不到找到使之起作用的方法。通过url / file进行音频流传输的文档非常丰富,但事实并非如此。

var ffmpeg = CreateProcess("");
            var output = ffmpeg.StandardOutput.BaseStream;
            IAudioClient client;
            ConnectedChannels.TryGetValue(guild.Id, out client);
            var discord = client.CreatePCMStream(AudioApplication.Mixed);


            await output.CopyToAsync(discord);
            await discord.FlushAsync();

上面是我一直在使用的示例,它是通过ffmpeg从文件中获取的。我看到它只是在流上复制,因此我尝试了各种方法进行以下操作:
IAudioClient client;
            ConnectedChannels.TryGetValue(guild.Id, out client);
            var discord = client.CreatePCMStream(AudioApplication.Mixed);

            var synth = new SpeechSynthesizer();
            var stream = new MemoryStream();
            var synthFormat = new SpeechAudioFormatInfo(
                EncodingFormat.Pcm,
                8000,
                16,
                1,
                16000,
                2,
                null);

            synth.SetOutputToAudioStream(stream, synthFormat);
            synth.Speak("this is a test");

            await stream.CopyToAsync(discord);
            await discord.FlushAsync();

我尝试过更改SpeechAudioFormatInfo属性,更改了SpeechSynthesizer的输出,完全删除了异步调用,几乎所有我能想到的事情都没有结果。

我意识到我可以将声音输出到虚拟音频设备,并让另一个帐户/机器人来接听,但这不是本练习的目的。
我也意识到我可以将输出写入文件并进行流传输,但这会增加处理时间。这些TTS指令很小,永远不会超过5个单词,并且由于它们应该是“标注”,因此需要在某种程度上快速点。

最后,我也无法完全找到使用ffmpeg进行这项工作的方法。我阅读的所有内容似乎都表明需要物理源,而不仅仅是内存流。

所以,我机智了。任何援助将不胜感激。

最佳答案

Discord.NET对于AudioStreams有点挑剔。每个音频连接只需要一个PCMStream,否则它会做一些奇怪的事情。语音连接时可以创建PCMStream,然后调用多个SendAsync发送音频。

如果我没记错的话,您应该可以将TTS流作为媒体(mp3或AAC媒体文件)输出
然后像这样播放TTS音频文件

public async Task SendAsync(float volume, string path, AudioOutStream stream)
{
    _currentProcess = CreateStream(path);
    while (true)
    {
        if (_currentProcess.HasExited)
        { break; }
        int blockSize = 2880;
        byte[] buffer = new byte[blockSize];
        int byteCount;
        byteCount = await _currentProcess.StandardOutput.BaseStream.ReadAsync(buffer, 0, blockSize);
        if (byteCount == 0)
        { break; }
        await stream.WriteAsync(buffer, 0, byteCount);
     }
    await stream.FlushAsync();
}

然后像这样调用ffmpeg:
private static Process CreateStream(string path)
{
    var ffmpeg = new ProcessStartInfo
    {
        FileName = "ffmpeg",
        Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1",
        UseShellExecute = false,
        RedirectStandardOutput = true
    };
    return Process.Start(ffmpeg);
}

关于c# - 使用TTS从MemoryStream到Discord Bot的音频输出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53917665/

10-12 00:13
查看更多