poopy buffer, the best ring buffer
This commit is contained in:
parent
ad44e4937c
commit
09adb9854c
@ -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 <Writepos
|
||||
// buffer is in its inverted state
|
||||
// A: if i can read as much as possible without hitting the buffer.length, read that
|
||||
|
||||
Buffer.BlockCopy(ringBuffer, 0, buffer, 0, count);
|
||||
Buffer.BlockCopy(ringBuffer, count, ringBuffer, 0, WritePosition -= count);
|
||||
if (count + ReadPosition <= BufferSize) {
|
||||
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count);
|
||||
ReadPosition += count;
|
||||
//Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]");
|
||||
return count;
|
||||
}
|
||||
// B: if i can't read as much, read to the end,
|
||||
int readNormaly = BufferSize - ReadPosition;
|
||||
Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly);
|
||||
|
||||
//Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]");
|
||||
//then read the remaining amount from the start
|
||||
|
||||
int readFromStart = count - readNormaly;
|
||||
Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart);
|
||||
//Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]");
|
||||
ReadPosition = readFromStart;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@ -46,14 +87,34 @@ namespace NadekoBot.Classes.Music {
|
||||
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken) {
|
||||
if (count > 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,7 +124,7 @@ namespace NadekoBot.Classes.Music {
|
||||
$"**【 {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) {
|
||||
|
Loading…
Reference in New Issue
Block a user