diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs index c66b1b30..36ba4dec 100644 --- a/NadekoBot/Classes/Extensions.cs +++ b/NadekoBot/Classes/Extensions.cs @@ -303,6 +303,15 @@ namespace NadekoBot.Extensions public static int GiB(this int value) => value.MiB() * 1024; public static int GB(this int value) => value.MB() * 1000; + public static ulong KiB(this ulong value) => value * 1024; + public static ulong KB(this ulong value) => value * 1000; + + public static ulong MiB(this ulong value) => value.KiB() * 1024; + public static ulong MB(this ulong value) => value.KB() * 1000; + + public static ulong GiB(this ulong value) => value.MiB() * 1024; + public static ulong GB(this ulong value) => value.MB() * 1000; + public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null) { if (format == null) diff --git a/NadekoBot/Modules/Music/Classes/MusicControls.cs b/NadekoBot/Modules/Music/Classes/MusicControls.cs index b024ca47..847070eb 100644 --- a/NadekoBot/Modules/Music/Classes/MusicControls.cs +++ b/NadekoBot/Modules/Music/Classes/MusicControls.cs @@ -113,17 +113,10 @@ namespace NadekoBot.Modules.Music.Classes if (CurrentSong == null) continue; - try - { - OnStarted(this, CurrentSong); - await CurrentSong.Play(audioClient, cancelToken); - } - catch (OperationCanceledException) - { - Console.WriteLine("Song canceled"); - SongCancelSource = new CancellationTokenSource(); - cancelToken = SongCancelSource.Token; - } + + OnStarted(this, CurrentSong); + await CurrentSong.Play(audioClient, cancelToken); + OnCompleted(this, CurrentSong); if (RepeatPlaylist) @@ -135,6 +128,12 @@ namespace NadekoBot.Modules.Music.Classes } finally { + if (!cancelToken.IsCancellationRequested) + { + SongCancelSource.Cancel(); + } + SongCancelSource = new CancellationTokenSource(); + cancelToken = SongCancelSource.Token; CurrentSong = null; await Task.Delay(300).ConfigureAwait(false); } diff --git a/NadekoBot/Modules/Music/Classes/Song.cs b/NadekoBot/Modules/Music/Classes/Song.cs index fc831b52..08be13b8 100644 --- a/NadekoBot/Modules/Music/Classes/Song.cs +++ b/NadekoBot/Modules/Music/Classes/Song.cs @@ -32,9 +32,7 @@ namespace NadekoBot.Modules.Music.Classes public SongInfo SongInfo { get; } public string QueuerName { get; set; } - private PoopyBuffer songBuffer { get; set; } - - private bool prebufferingComplete { get; set; } = false; + private bool bufferingCompleted { get; set; } = false; public MusicPlayer MusicPlayer { get; set; } public string PrettyCurrentTime() @@ -90,9 +88,20 @@ namespace NadekoBot.Modules.Music.Classes RedirectStandardError = false, CreateNoWindow = true, }); + var prebufferSize = 100ul.MiB(); using (var outStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read)) - await p.StandardOutput.BaseStream.CopyToAsync(outStream, 81920, cancelToken); - prebufferingComplete = true; + { + byte[] buffer = new byte[81920]; + int bytesRead; + while ((bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false)) != 0) + { + await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false); + while ((ulong)outStream.Length - bytesSent > prebufferSize) + await Task.Delay(100, cancelToken); + } + } + + bufferingCompleted = true; } catch (System.ComponentModel.Win32Exception) { var oldclr = Console.ForegroundColor; @@ -106,11 +115,11 @@ Check the guides for your platform on how to setup ffmpeg correctly: } catch (Exception ex) { - Console.WriteLine($"Buffering errored: {ex.Message}"); + Console.WriteLine($"Buffering stopped: {ex.Message}"); } finally { - Console.WriteLine($"Buffering done." + $" [{songBuffer.ContentLength}]"); + Console.WriteLine($"Buffering done."); if (p != null) { try @@ -128,18 +137,36 @@ Check the guides for your platform on how to setup ffmpeg correctly: var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); var bufferTask = BufferSong(filename, cancelToken).ConfigureAwait(false); - + var inStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); + + bytesSent = 0; + try { - await Task.Delay(1000); + var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken); + var sw = new Stopwatch(); + sw.Start(); + var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken)); + if (t != prebufferingTask) + { + Console.WriteLine("Prebuffering timed out or canceled. Cannot get any data from the stream."); + return; + } + else if(prebufferingTask.IsCanceled) + { + Console.WriteLine("Prebuffering timed out. Cannot get any data from the stream."); + return; + } + sw.Stop(); + Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed); const int blockSize = 3840; var attempt = 0; + byte[] buffer = new byte[blockSize]; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); - byte[] buffer = new byte[blockSize]; var read = inStream.Read(buffer, 0, buffer.Length); //await inStream.CopyToAsync(voiceClient.OutputStream); unchecked @@ -149,9 +176,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: if (read == 0) if (attempt++ == 20) { - Console.WriteLine("blocking"); voiceClient.Wait(); - Console.WriteLine("unblocking"); break; } else @@ -161,19 +186,29 @@ Check the guides for your platform on how to setup ffmpeg correctly: while (this.MusicPlayer.Paused) await Task.Delay(200, cancelToken).ConfigureAwait(false); + buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } - await bufferTask; - voiceClient.Clear(); - cancelToken.ThrowIfCancellationRequested(); } - finally { + finally + { + await bufferTask; + await Task.Run(() => voiceClient.Clear()); inStream.Dispose(); try { File.Delete(filename); } catch { } } } + private async Task CheckPrebufferingAsync(Stream inStream, CancellationToken cancelToken) + { + while (!bufferingCompleted && inStream.Length < 2.MiB()) + { + await Task.Delay(100, cancelToken); + } + Console.WriteLine("Buffering successfull"); + } + /* //stackoverflow ftw private static byte[] AdjustVolume(byte[] audioSamples, float volume)