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;
|
private byte[] ringBuffer;
|
||||||
|
|
||||||
public int WritePosition { get; private set; } = 0;
|
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) {
|
public PoopyBuffer(int size) {
|
||||||
|
if (size <= 0)
|
||||||
|
throw new ArgumentException();
|
||||||
|
BufferSize = size;
|
||||||
ringBuffer = new byte[size];
|
ringBuffer = new byte[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Read(byte[] buffer, int count) {
|
public int Read(byte[] buffer, int count) {
|
||||||
lock (this) {
|
if (buffer.Length < count)
|
||||||
if (count > WritePosition)
|
throw new ArgumentException();
|
||||||
count = WritePosition;
|
//Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
|
||||||
if (count == 0)
|
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;
|
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);
|
if (count + ReadPosition <= BufferSize) {
|
||||||
Buffer.BlockCopy(ringBuffer, count, ringBuffer, 0, WritePosition -= count);
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,14 +87,34 @@ namespace NadekoBot.Classes.Music {
|
|||||||
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken) {
|
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken) {
|
||||||
if (count > buffer.Length)
|
if (count > buffer.Length)
|
||||||
throw new ArgumentException();
|
throw new ArgumentException();
|
||||||
while (count + WritePosition > ringBuffer.Length) {
|
while (ContentLength + count > BufferSize) {
|
||||||
await Task.Delay(20);
|
await Task.Delay(20);
|
||||||
if (cancelToken.IsCancellationRequested)
|
if (cancelToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lock (this) {
|
//the while above assures that i cannot write past readposition with my write, so i don't have to check
|
||||||
Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count);
|
// *unless its multithreaded or task is not awaited
|
||||||
WritePosition += count;
|
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 ?? "-")}`";
|
$"**【 {SongInfo.Title.TrimTo(55)} 】**`{(SongInfo.Provider ?? "-")}`";
|
||||||
public SongInfo SongInfo { get; }
|
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;
|
private bool prebufferingComplete { get; set; } = false;
|
||||||
public MusicPlayer MusicPlayer { get; set; }
|
public MusicPlayer MusicPlayer { get; set; }
|
||||||
@ -81,7 +142,7 @@ namespace NadekoBot.Classes.Music {
|
|||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
int blockSize = 512;
|
int blockSize = 3840;
|
||||||
byte[] buffer = new byte[blockSize];
|
byte[] buffer = new byte[blockSize];
|
||||||
int attempt = 0;
|
int attempt = 0;
|
||||||
while (!cancelToken.IsCancellationRequested) {
|
while (!cancelToken.IsCancellationRequested) {
|
||||||
@ -94,7 +155,7 @@ namespace NadekoBot.Classes.Music {
|
|||||||
else
|
else
|
||||||
attempt = 0;
|
attempt = 0;
|
||||||
await songBuffer.WriteAsync(buffer, read, cancelToken);
|
await songBuffer.WriteAsync(buffer, read, cancelToken);
|
||||||
if (songBuffer.WritePosition > 5.MB())
|
if (songBuffer.ContentLength > 1.MB())
|
||||||
prebufferingComplete = true;
|
prebufferingComplete = true;
|
||||||
}
|
}
|
||||||
Console.WriteLine("Buffering done.");
|
Console.WriteLine("Buffering done.");
|
||||||
@ -112,6 +173,7 @@ namespace NadekoBot.Classes.Music {
|
|||||||
byte[] buffer = new byte[blockSize];
|
byte[] buffer = new byte[blockSize];
|
||||||
int attempt = 0;
|
int attempt = 0;
|
||||||
while (!cancelToken.IsCancellationRequested) {
|
while (!cancelToken.IsCancellationRequested) {
|
||||||
|
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
|
||||||
int read = songBuffer.Read(buffer, blockSize);
|
int read = songBuffer.Read(buffer, blockSize);
|
||||||
if (read == 0)
|
if (read == 0)
|
||||||
if (attempt++ == 10) {
|
if (attempt++ == 10) {
|
||||||
|
Loading…
Reference in New Issue
Block a user