Browse Source

Voice performance update, and reenabled pings

tags/docs-0.9
RogueException 9 years ago
parent
commit
04a15100ff
2 changed files with 66 additions and 51 deletions
  1. +9
    -7
      src/Discord.Net/Audio/VoiceBuffer.cs
  2. +57
    -44
      src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs

+ 9
- 7
src/Discord.Net/Audio/VoiceBuffer.cs View File

@@ -9,7 +9,7 @@ namespace Discord.Audio
private readonly byte[] _buffer;
private readonly byte[] _blankFrame;
private ushort _readCursor, _writeCursor;
private ManualResetEventSlim _underflowEvent, _notOverflowEvent;
private ManualResetEventSlim _notOverflowEvent;
private bool _isClearing;

public int FrameSize => _frameSize;
@@ -26,7 +26,6 @@ namespace Discord.Audio
_writeCursor = 0;
_buffer = new byte[_bufferSize];
_blankFrame = new byte[_frameSize];
_underflowEvent = new ManualResetEventSlim(); //Notifies when an underflow has occurred
_notOverflowEvent = new ManualResetEventSlim(); //Notifies when an overflow is solved
}

@@ -79,7 +78,6 @@ namespace Discord.Audio

//Advance the write cursor to the next position
AdvanceCursorPos(ref _writeCursor);
_underflowEvent.Set();
}
}
}
@@ -88,7 +86,6 @@ namespace Discord.Audio
{
if (_writeCursor == _readCursor)
{
_underflowEvent.Set();
_notOverflowEvent.Set();
return false;
}
@@ -112,8 +109,8 @@ namespace Discord.Audio
Buffer.BlockCopy(_blankFrame, 0, _buffer, i * _frameCount, i++);
try
{
_underflowEvent.Wait(cancelToken);
}
Wait(cancelToken);
}
catch (OperationCanceledException) { }
_writeCursor = 0;
_readCursor = 0;
@@ -123,7 +120,12 @@ namespace Discord.Audio

public void Wait(CancellationToken cancelToken)
{
_underflowEvent.Wait(cancelToken);
while (true)
{
_notOverflowEvent.Wait(cancelToken);
if (_writeCursor == _readCursor)
break;
}
}

private void AdvanceCursorPos(ref ushort pos)


+ 57
- 44
src/Discord.Net/Net/WebSockets/VoiceWebSocket.cs View File

@@ -21,7 +21,7 @@ namespace Discord.Net.WebSockets
private const string EncryptedMode = "xsalsa20_poly1305";
private const string UnencryptedMode = "plain";

private readonly Random _rand;
//private readonly Random _rand;
private readonly int _targetAudioBufferLength;
private OpusEncoder _encoder;
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
@@ -48,7 +48,7 @@ namespace Discord.Net.WebSockets
public VoiceWebSocket(DiscordWSClient client)
: base(client)
{
_rand = new Random();
//_rand = new Random();
_decoders = new ConcurrentDictionary<uint, OpusDecoder>();
_targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames
_encodingBuffer = new byte[MaxOpusSize];
@@ -301,7 +301,8 @@ namespace Discord.Net.WebSockets
byte[] voicePacket, pingPacket, nonce = null;
uint timestamp = 0;
double nextTicks = 0.0, nextPingTicks = 0.0;
double ticksPerMillisecond = Stopwatch.Frequency / 1000.0;
long ticksPerSeconds = Stopwatch.Frequency;
double ticksPerMillisecond = Stopwatch.Frequency / 1000.0;
double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength;
double spinLockThreshold = 3 * ticksPerMillisecond;
uint samplesPerFrame = (uint)_encoder.SamplesPerFrame;
@@ -346,57 +347,69 @@ namespace Discord.Net.WebSockets
if (_isEncrypted)
Buffer.BlockCopy(voicePacket, 0, nonce, 0, 12);

bool hasFrame = false;
while (!cancelToken.IsCancellationRequested)
{
double ticksToNextFrame = nextTicks - sw.ElapsedTicks;
if (!hasFrame && _sendBuffer.Pop(frame))
{
ushort sequence = unchecked(_sequence++);
voicePacket[2] = (byte)((sequence >> 8) & 0xFF);
voicePacket[3] = (byte)((sequence >> 0) & 0xFF);
voicePacket[4] = (byte)((timestamp >> 24) & 0xFF);
voicePacket[5] = (byte)((timestamp >> 16) & 0xFF);
voicePacket[6] = (byte)((timestamp >> 8) & 0xFF);
voicePacket[7] = (byte)((timestamp >> 0) & 0xFF);

//Encode
int encodedLength = _encoder.EncodeFrame(frame, 0, encodedFrame);

//Encrypt
if (_isEncrypted)
{
Buffer.BlockCopy(voicePacket, 2, nonce, 2, 6); //Update nonce
int ret = Sodium.Encrypt(encodedFrame, encodedLength, voicePacket, 12, nonce, _secretKey);
if (ret != 0)
continue;
rtpPacketLength = encodedLength + 12 + 16;
}
else
{
Buffer.BlockCopy(encodedFrame, 0, voicePacket, 12, encodedLength);
rtpPacketLength = encodedLength + 12;
}

timestamp = unchecked(timestamp + samplesPerFrame);
hasFrame = true;
}

long currentTicks = sw.ElapsedTicks;
double ticksToNextFrame = nextTicks - currentTicks;
if (ticksToNextFrame <= 0.0)
{
long currentTicks = sw.ElapsedTicks;
while (currentTicks > nextTicks)
if (hasFrame)
{
if (_sendBuffer.Pop(frame))
{
ushort sequence = unchecked(_sequence++);
voicePacket[2] = (byte)((sequence >> 8) & 0xFF);
voicePacket[3] = (byte)((sequence >> 0) & 0xFF);
voicePacket[4] = (byte)((timestamp >> 24) & 0xFF);
voicePacket[5] = (byte)((timestamp >> 16) & 0xFF);
voicePacket[6] = (byte)((timestamp >> 8) & 0xFF);
voicePacket[7] = (byte)((timestamp >> 0) & 0xFF);

//Encode
int encodedLength = _encoder.EncodeFrame(frame, 0, encodedFrame);

//Encrypt
if (_isEncrypted)
{
Buffer.BlockCopy(voicePacket, 2, nonce, 2, 6); //Update nonce
int ret = Sodium.Encrypt(encodedFrame, encodedLength, voicePacket, 12, nonce, _secretKey);
if (ret != 0)
continue;
rtpPacketLength = encodedLength + 12 + 16;
}
else
{
Buffer.BlockCopy(encodedFrame, 0, voicePacket, 12, encodedLength);
rtpPacketLength = encodedLength + 12;
}
_udp.Send(voicePacket, rtpPacketLength);
}
timestamp = unchecked(timestamp + samplesPerFrame);
nextTicks += ticksPerFrame;
_udp.Send(voicePacket, rtpPacketLength);
hasFrame = false;
}
nextTicks += ticksPerFrame;

//Is it time to send out another ping?
if (currentTicks > nextPingTicks)
{
//_udp.Send(pingPacket, pingPacket.Length);
nextPingTicks = currentTicks + 5 * Stopwatch.Frequency;
_udp.Send(pingPacket, pingPacket.Length);
nextPingTicks = currentTicks + 5 * ticksPerSeconds;
}
}
//Dont sleep if we need to output audio in the next spinLockThreshold
else if (ticksToNextFrame > spinLockThreshold)
else
{
int time = (int)Math.Ceiling((ticksToNextFrame - spinLockThreshold) / ticksPerMillisecond);
Thread.Sleep(1);
if (hasFrame)
{
int time = (int)Math.Floor(ticksToNextFrame / ticksPerMillisecond);
if (time > 0)
Thread.Sleep(time);
}
else
Thread.Sleep(1); //Give as much time to the encrypter as possible
}
}
}
@@ -445,7 +458,7 @@ namespace Discord.Net.WebSockets
}
_udp.Connect(_endpoint);

_sequence = (ushort)_rand.Next(0, ushort.MaxValue);
_sequence = 0;// (ushort)_rand.Next(0, ushort.MaxValue);
//No thread issue here because SendAsync doesn't start until _isReady is true
byte[] packet = new byte[70];
packet[0] = (byte)((_ssrc >> 24) & 0xFF);


Loading…
Cancel
Save