Discord.net无法使用NAudio

时间:2018-07-31 11:05:35

标签: c# naudio discord.net

我想在语音通道中播放mp3文件。 BOT成功可以连接,但不播放任何内容,并引发异常。

代码

public async Task SendAudioAsync(IGuild guild, IMessageChannel channel, string path)
{
    try
    {
        if (!File.Exists(path))
        {
            await channel.SendMessageAsync("File does not exist.");
            return;
        }
        IAudioClient client;
        if (ConnectedChannels.TryGetValue(guild.Id, out client))
        {
            await Log.d($"Starting playback of {path} in {guild.Name}", src);
            using (var reader = new Mp3FileReader(path))
            using (var output = client.CreateOpusStream())
            {
                try
                {
                    reader.CopyTo(output);//<- AudioService.cs, line: 70
                }
                catch(Exception e)
                {
                    await Log.e(e.ToString(), src);
                }
                finally { await output.FlushAsync(); }
            }
        }
    }
    catch (Exception e)
    {
        await Log.e(e.ToString(), src);
    }
}

异常

System.ArgumentException: Shift and length outside the array boundaries or the number of elements is greater than the number of items in the source collection from the index to the end of the collection. 
System.Buffer.BlockCopy(Array src, Int32 srcOffset , Array dst, Int32 dstOffset, Int32 count)
at Discord.Audio.Streams.BufferedWriteStream.<WriteAsync>d__21.MoveNext() 
--- Trigger end tracking from the previous occurrence of the exception --- 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Discord.Audio.AudioStream.Write(Byte [] buffer, Int32 offset, Int32 count)
at System.IO.Stream.InternalCopyTo(Stream destination, Int32 <SendAudioAsync> d__4.MoveNext() location: C:\Users\noel\source\repos\DiscordBot\Bot\Core\Voice\AudioService.cs, line: 70 

此版本的例外情况,是使用Google翻译从匈牙利语翻译过来的。

更新

我做了更多的研究,发现this example,因为它已经过时了,我重写了一下,现在看起来像这样:

public async Task SendAudioAsync(IGuild guild, IMessageChannel channel, string path)
{
    try
    {
        if (!File.Exists(path))
        {
            await channel.SendMessageAsync("File does not exist.");
            return;
        }
        IAudioClient client;
        if (ConnectedChannels.TryGetValue(guild.Id, out client))
        {
            await Log.d($"Starting playback of \"{path}\" in \"{guild.Name}\"", src);
            var OutFormat = new WaveFormat(48000, 16, 2);

            using (var MP3Reader = new Mp3FileReader(path)) // Create a new Disposable MP3FileReader, to read audio from the filePath parameter
            using (var resampler = new MediaFoundationResampler(MP3Reader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format
            {
                resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality
                int blockSize = OutFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer
                byte[] buffer = new byte[blockSize];
                int byteCount;
                while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present
                {
                    if (byteCount < blockSize)
                    {
                        // Incomplete Frame
                        for (int i = byteCount; i < blockSize; i++)
                            buffer[i] = 0;
                    }
                    using(var output = client.CreatePCMStream(AudioApplication.Mixed))
                    await output.WriteAsync(buffer, 0, blockSize); // Send the buffer to Discord
                }
            }
        }
    }
    catch (Exception e)
    {
        await Log.e(e.ToString(), src);
    }
}

现在它什么也不做,也不会抛出任何异常。

1 个答案:

答案 0 :(得分:2)

我想出了本守则,对我有用。因为这被认为是测试程序,所以我实际上并不关心同步/异步编程。适应这一点应该很容易。我希望这会有所帮助。

class Program
{
    private static string mytoken = "";
    private static CancellationTokenSource cancellationToken = new CancellationTokenSource();
    private static bool playing = false;
    private static AudioOutStream dstream = null;
    private static IAudioClient client = null;

    static void Main(string[] args)
    {
        var Client = new DiscordSocketClient();
        Client.LoginAsync(TokenType.Bot, mytoken).Wait();
        Client.StartAsync().Wait();

        var path = "path\\testfile.mp3";

        Client.Ready += async () =>
        {
            var guild = Client.Guilds.First();
            var channel = guild.Channels.Where(x => x is SocketVoiceChannel).Select(x => x as SocketVoiceChannel).First();

            try
            {
                client = await channel.ConnectAsync();

                var reader = new Mp3FileReader(path);
                var naudio = WaveFormatConversionStream.CreatePcmStream(reader);

                dstream = client.CreatePCMStream(AudioApplication.Music);
                byte[] buffer = new byte[naudio.Length];

                int rest = (int)(naudio.Length - naudio.Position);
                await naudio.ReadAsync(buffer, 0, rest);
                playing = true;
                await dstream.WriteAsync(buffer, 0, rest, cancellationToken.Token);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.Message);
                if(e.InnerException != null)
                    Debug.WriteLine(e.InnerException.Message);
            }

        };

        while (!playing) ;
        Console.ReadLine();
        cancellationToken.Cancel();
        Debug.WriteLine("Pre-Flush");
        dstream.Flush();
        Debug.WriteLine("POST-FLUSH");
        client.StopAsync().Wait();

        Client.StopAsync().Wait();
        Client.LogoutAsync().Wait();
    }
}

它也起作用,当我不使用byte[]来缓冲音频时,我只是叫naudio.CopyToAsync(dstream);