Discord.net 无法使用 NAudio 流式传输音频 [英] Discord.net can't stream audio with NAudio

查看:98
本文介绍了Discord.net 无法使用 NAudio 流式传输音频的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在语音频道中播放 mp3 文件.BOT成功可以连接,但是什么也不玩,抛出异常.

I want to play an mp3 file in a voice channel. The BOT successfully can connect, but doesn't play anything, and throws an exception.

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 

这个版本的异常,用谷歌翻译从匈牙利语翻译过来..

我做了更多研究,发现了这个例子,因为它已经过时了,所以我重写了一下,现在看起来像这样:

I did more research and found this example, because it's outdated I rewrote a bit and now looks like this:

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);
    }
}

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

Now it doesn't do anything and doesn't throw any exception.

推荐答案

我想出了这个代码,它对我有用.由于这被认为是一个测试程序,我并不真正关心同步/异步编程.应该很容易适应这一点.我希望这会有所帮助.

I have come up with this Code, which does work for me. As this is considered to be a test program I did not really care about synchronous/asynchrounos programming. It should be easy to adapt this. I hope this helps.

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);

It also worked, when instead of using a byte[] to buffer the audio, I just called naudio.CopyToAsync(dstream);

这篇关于Discord.net 无法使用 NAudio 流式传输音频的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆