C# Discord.Net使用ffmpeg发送音频只工作一次(第一次) 背景:
所以我写了一个小机器人,它可以根据命令播放本地音频文件。我正在使用Discord.Net、ffmpeg、opus和LibNasdaq。 我有一个Speak()函数,理论上 打开ffmpeg->编码.mp3->创建PCM流->将编码的.mp3压缩到输出(PCM流) 看起来是这样的:C# Discord.Net使用ffmpeg发送音频只工作一次(第一次) 背景:,c#,audio,ffmpeg,audio-streaming,discord.net,C#,Audio,Ffmpeg,Audio Streaming,Discord.net,所以我写了一个小机器人,它可以根据命令播放本地音频文件。我正在使用Discord.Net、ffmpeg、opus和LibNasdaq。 我有一个Speak()函数,理论上 打开ffmpeg->编码.mp3->创建PCM流->将编码的.mp3压缩到输出(PCM流) 看起来是这样的: public async Task Speak(IGuild guild, Sound.SoundName soundName) { IAudioClient client; if (ConnectedChan
public async Task Speak(IGuild guild, Sound.SoundName soundName)
{
IAudioClient client;
if (ConnectedChannels.TryGetValue(guild.Id, out client))
{
using (var ffmpeg = CreateStream(sound.Filename))
using (var stream = client.CreatePCMStream(AudioApplication.Voice, 98304))
using (var output = ffmpeg.StandardOutput.BaseStream)
{
try
{
await output.CopyToAsync(stream);
}
catch (Exception ex) { Console.WriteLine("Error " + ex.Message); Console.WriteLine($"- {ex.StackTrace}"); }
finally { await stream.FlushAsync(); }
Console.WriteLine("Spoken!");
}
}
private Process CreateStream(string _path)
{
var process = Process.Start(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;
}
[Command("join", RunMode = RunMode.Async)]
[RequireUserPermission(GuildPermission.MentionEveryone)]
public async Task JoinChannel(IVoiceChannel channel = null)
{
// Get the Voice channel
channel = channel ?? (Context.User as IGuildUser)?.VoiceChannel;
if (channel == null) { await Context.Channel.SendMessageAsync("You are not in a VoiceChannel"); return; }
// Saving the AudioClient
var audioClient = await channel.ConnectAsync();
Console.WriteLine($"Connected to channel {channel.Name}");
ConnectedChannels.TryAdd(channel.Guild.Id, audioClient);
await Task.Delay(1000);
await Speak(Context.Guild, Sound.SoundName.hello);
}
[Command("speak")]
public async Task speakSingle()
{
await Speak(Context.Guild, Sound.SoundName.Random);
}
它做到了,但只有一次。更具体地说,当我的bot加入语音频道时,它会将语音频道ID和IAudioClient保存在私有静态只读ConcurrentDictionary ConnectedChannels=new ConcurrentDictionary()中代码>。之后,它会自动调用Speak()函数来播放hello.mp3音频。此过程如下所示:
public async Task Speak(IGuild guild, Sound.SoundName soundName)
{
IAudioClient client;
if (ConnectedChannels.TryGetValue(guild.Id, out client))
{
using (var ffmpeg = CreateStream(sound.Filename))
using (var stream = client.CreatePCMStream(AudioApplication.Voice, 98304))
using (var output = ffmpeg.StandardOutput.BaseStream)
{
try
{
await output.CopyToAsync(stream);
}
catch (Exception ex) { Console.WriteLine("Error " + ex.Message); Console.WriteLine($"- {ex.StackTrace}"); }
finally { await stream.FlushAsync(); }
Console.WriteLine("Spoken!");
}
}
private Process CreateStream(string _path)
{
var process = Process.Start(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;
}
[Command("join", RunMode = RunMode.Async)]
[RequireUserPermission(GuildPermission.MentionEveryone)]
public async Task JoinChannel(IVoiceChannel channel = null)
{
// Get the Voice channel
channel = channel ?? (Context.User as IGuildUser)?.VoiceChannel;
if (channel == null) { await Context.Channel.SendMessageAsync("You are not in a VoiceChannel"); return; }
// Saving the AudioClient
var audioClient = await channel.ConnectAsync();
Console.WriteLine($"Connected to channel {channel.Name}");
ConnectedChannels.TryAdd(channel.Guild.Id, audioClient);
await Task.Delay(1000);
await Speak(Context.Guild, Sound.SoundName.hello);
}
[Command("speak")]
public async Task speakSingle()
{
await Speak(Context.Guild, Sound.SoundName.Random);
}
这非常好,音频播放
现在,机器人已连接到语音频道,IAudioClient已保存到字典中。只要机器人在VoiceChannel中,我应该能够在任何时候、任何地点调用Speak()函数,对吗
不,不是这样。
这就把我带到了我的
问题:
机器人现在静坐在语音频道后,我调用一个“说话”命令,代码如下:
public async Task Speak(IGuild guild, Sound.SoundName soundName)
{
IAudioClient client;
if (ConnectedChannels.TryGetValue(guild.Id, out client))
{
using (var ffmpeg = CreateStream(sound.Filename))
using (var stream = client.CreatePCMStream(AudioApplication.Voice, 98304))
using (var output = ffmpeg.StandardOutput.BaseStream)
{
try
{
await output.CopyToAsync(stream);
}
catch (Exception ex) { Console.WriteLine("Error " + ex.Message); Console.WriteLine($"- {ex.StackTrace}"); }
finally { await stream.FlushAsync(); }
Console.WriteLine("Spoken!");
}
}
private Process CreateStream(string _path)
{
var process = Process.Start(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;
}
[Command("join", RunMode = RunMode.Async)]
[RequireUserPermission(GuildPermission.MentionEveryone)]
public async Task JoinChannel(IVoiceChannel channel = null)
{
// Get the Voice channel
channel = channel ?? (Context.User as IGuildUser)?.VoiceChannel;
if (channel == null) { await Context.Channel.SendMessageAsync("You are not in a VoiceChannel"); return; }
// Saving the AudioClient
var audioClient = await channel.ConnectAsync();
Console.WriteLine($"Connected to channel {channel.Name}");
ConnectedChannels.TryAdd(channel.Guild.Id, audioClient);
await Task.Delay(1000);
await Speak(Context.Guild, Sound.SoundName.hello);
}
[Command("speak")]
public async Task speakSingle()
{
await Speak(Context.Guild, Sound.SoundName.Random);
}
但是机器人保持沉默,即使Discord中的speak指示灯亮起!我错过了什么?我不明白。它发送的是空流吗?
即使我断开机器人与语音频道的连接并重新连接,它也不会发送音频。唯一有帮助的是从服务器重新连接Bot。
我对C#和Streams以及异步编程非常陌生。有人能帮我找出问题并解决吗
错误(CommandPromt输出):
1#
当我运行“speak”命令时,会发生这种情况,我在VisualStudio中收到“Discord.WebSocket.pdb not loaded”的NullReferenceException。虽然我找不到任何空的东西
17:34:17 Audio #1 System.Exception: WebSocket connection was closed
---> Discord.Net.WebSocketClosedException: The server sent close 4008: "Rate limited."
at Discord.Net.WebSockets.DefaultWebSocketClient.RunAsync(CancellationToken cancelToken)
--- End of inner exception stack trace ---
at Discord.ConnectionManager.<>c__DisplayClass29_0.<<StartAsync>b__0>d.MoveNext()
这是我关于StackOverflow的第一个问题,我希望提供足够的上下文,如果没有请告诉我。您考虑过使用Lavalink吗?运行lavalink服务器jar,可以使用.NET lavalink包装器(如Victoria.lavalink或Lavalink4NET)连接到它。Lavalink可以配置为从一系列来源获取音频,包括本地文件。我上面列出的库是为使用Discord.NET而构建的,Lavalink被最流行的音乐机器人(如Rythm)使用。@230Daniel我听说过Lavalink,但认为它只用于从youtube等web链接获取音乐。我再看看。谢谢你的回复@所以我让lavalink和victoria一起运行。lavalink但我无法播放本地文件。你知道如何加载本地文件吗?你考虑过使用Lavalink吗?运行lavalink服务器jar,可以使用.NET lavalink包装器(如Victoria.lavalink或Lavalink4NET)连接到它。Lavalink可以配置为从一系列来源获取音频,包括本地文件。我上面列出的库是为使用Discord.NET而构建的,Lavalink被最流行的音乐机器人(如Rythm)使用。@230Daniel我听说过Lavalink,但认为它只用于从youtube等web链接获取音乐。我再看看。谢谢你的回复@所以我让lavalink和victoria一起运行。lavalink但我无法播放本地文件。你知道如何加载本地文件吗?