Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Discord.Net使用ffmpeg发送音频只工作一次(第一次) 背景:_C#_Audio_Ffmpeg_Audio Streaming_Discord.net - Fatal编程技术网

C# Discord.Net使用ffmpeg发送音频只工作一次(第一次) 背景:

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

所以我写了一个小机器人,它可以根据命令播放本地音频文件。我正在使用Discord.Net、ffmpeg、opus和LibNasdaq。 我有一个Speak()函数,理论上

打开ffmpeg->编码.mp3->创建PCM流->将编码的.mp3压缩到输出(PCM流)

看起来是这样的:

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但我无法播放本地文件。你知道如何加载本地文件吗?