From 09adb9854cd54cf02e4b3cfb33cfd465c7d7dc0e Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 28 Feb 2016 14:47:08 +0100 Subject: [PATCH] poopy buffer, the best ring buffer --- NadekoBot/Classes/Music/Song.cs | 90 ++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/NadekoBot/Classes/Music/Song.cs b/NadekoBot/Classes/Music/Song.cs index c71d0778..18448373 100644 --- a/NadekoBot/Classes/Music/Song.cs +++ b/NadekoBot/Classes/Music/Song.cs @@ -24,21 +24,62 @@ namespace NadekoBot.Classes.Music { private byte[] ringBuffer; public int WritePosition { get; private set; } = 0; + public int ReadPosition { get; private set; } = 0; + + public int ContentLength => (WritePosition >= ReadPosition ? + WritePosition - ReadPosition : + (BufferSize - ReadPosition) + WritePosition); + + public int BufferSize { get; } + + private readonly object readWriteLock = new object(); public PoopyBuffer(int size) { + if (size <= 0) + throw new ArgumentException(); + BufferSize = size; ringBuffer = new byte[size]; } public int Read(byte[] buffer, int count) { - lock (this) { - if (count > WritePosition) - count = WritePosition; - if (count == 0) + if (buffer.Length < count) + throw new ArgumentException(); + //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); + lock (readWriteLock) { + //read as much as you can if you're reading too much + if (count > ContentLength) + count = ContentLength; + //if nothing to read, return 0 + if (WritePosition == ReadPosition) return 0; + // if buffer is in the "normal" state, just read + if (WritePosition > ReadPosition) { + Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); + ReadPosition += count; + //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]"); + return count; + } + //else ReadPos buffer.Length) throw new ArgumentException(); - while (count + WritePosition > ringBuffer.Length) { + while (ContentLength + count > BufferSize) { await Task.Delay(20); if (cancelToken.IsCancellationRequested) return; } - lock (this) { - Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); - WritePosition += count; + //the while above assures that i cannot write past readposition with my write, so i don't have to check + // *unless its multithreaded or task is not awaited + lock (readWriteLock) { + // if i can just write without hitting buffer.length, do it + if (WritePosition + count < BufferSize) { + Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); + WritePosition += count; + //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]"); + return; + } + // otherwise, i have to write to the end, then write the rest from the start + + int wroteNormaly = BufferSize - WritePosition; + Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly); + + //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]"); + + int wroteFromStart = count - wroteNormaly; + Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart); + + //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}"); + + WritePosition = wroteFromStart; } } } @@ -62,8 +123,8 @@ namespace NadekoBot.Classes.Music { public string PrettyName => $"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}`"; public SongInfo SongInfo { get; } - - private PoopyBuffer songBuffer { get; } = new PoopyBuffer(10.MB()); + + private PoopyBuffer songBuffer { get; } = new PoopyBuffer(2.MB()); private bool prebufferingComplete { get; set; } = false; public MusicPlayer MusicPlayer { get; set; } @@ -81,7 +142,7 @@ namespace NadekoBot.Classes.Music { RedirectStandardOutput = true, }); - int blockSize = 512; + int blockSize = 3840; byte[] buffer = new byte[blockSize]; int attempt = 0; while (!cancelToken.IsCancellationRequested) { @@ -94,7 +155,7 @@ namespace NadekoBot.Classes.Music { else attempt = 0; await songBuffer.WriteAsync(buffer, read, cancelToken); - if (songBuffer.WritePosition > 5.MB()) + if (songBuffer.ContentLength > 1.MB()) prebufferingComplete = true; } Console.WriteLine("Buffering done."); @@ -112,6 +173,7 @@ namespace NadekoBot.Classes.Music { byte[] buffer = new byte[blockSize]; int attempt = 0; while (!cancelToken.IsCancellationRequested) { + //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); int read = songBuffer.Read(buffer, blockSize); if (read == 0) if (attempt++ == 10) {