Voice performance update, and reenabled pings

This commit is contained in:
RogueException
2015-11-22 01:33:24 -04:00
parent 3fa6ba8d50
commit 04a15100ff
2 changed files with 66 additions and 51 deletions

View File

@@ -9,7 +9,7 @@ namespace Discord.Audio
private readonly byte[] _buffer; private readonly byte[] _buffer;
private readonly byte[] _blankFrame; private readonly byte[] _blankFrame;
private ushort _readCursor, _writeCursor; private ushort _readCursor, _writeCursor;
private ManualResetEventSlim _underflowEvent, _notOverflowEvent; private ManualResetEventSlim _notOverflowEvent;
private bool _isClearing; private bool _isClearing;
public int FrameSize => _frameSize; public int FrameSize => _frameSize;
@@ -26,7 +26,6 @@ namespace Discord.Audio
_writeCursor = 0; _writeCursor = 0;
_buffer = new byte[_bufferSize]; _buffer = new byte[_bufferSize];
_blankFrame = new byte[_frameSize]; _blankFrame = new byte[_frameSize];
_underflowEvent = new ManualResetEventSlim(); //Notifies when an underflow has occurred
_notOverflowEvent = new ManualResetEventSlim(); //Notifies when an overflow is solved _notOverflowEvent = new ManualResetEventSlim(); //Notifies when an overflow is solved
} }
@@ -79,7 +78,6 @@ namespace Discord.Audio
//Advance the write cursor to the next position //Advance the write cursor to the next position
AdvanceCursorPos(ref _writeCursor); AdvanceCursorPos(ref _writeCursor);
_underflowEvent.Set();
} }
} }
} }
@@ -88,7 +86,6 @@ namespace Discord.Audio
{ {
if (_writeCursor == _readCursor) if (_writeCursor == _readCursor)
{ {
_underflowEvent.Set();
_notOverflowEvent.Set(); _notOverflowEvent.Set();
return false; return false;
} }
@@ -112,8 +109,8 @@ namespace Discord.Audio
Buffer.BlockCopy(_blankFrame, 0, _buffer, i * _frameCount, i++); Buffer.BlockCopy(_blankFrame, 0, _buffer, i * _frameCount, i++);
try try
{ {
_underflowEvent.Wait(cancelToken); Wait(cancelToken);
} }
catch (OperationCanceledException) { } catch (OperationCanceledException) { }
_writeCursor = 0; _writeCursor = 0;
_readCursor = 0; _readCursor = 0;
@@ -123,7 +120,12 @@ namespace Discord.Audio
public void Wait(CancellationToken cancelToken) public void Wait(CancellationToken cancelToken)
{ {
_underflowEvent.Wait(cancelToken); while (true)
{
_notOverflowEvent.Wait(cancelToken);
if (_writeCursor == _readCursor)
break;
}
} }
private void AdvanceCursorPos(ref ushort pos) private void AdvanceCursorPos(ref ushort pos)

View File

@@ -21,7 +21,7 @@ namespace Discord.Net.WebSockets
private const string EncryptedMode = "xsalsa20_poly1305"; private const string EncryptedMode = "xsalsa20_poly1305";
private const string UnencryptedMode = "plain"; private const string UnencryptedMode = "plain";
private readonly Random _rand; //private readonly Random _rand;
private readonly int _targetAudioBufferLength; private readonly int _targetAudioBufferLength;
private OpusEncoder _encoder; private OpusEncoder _encoder;
private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders; private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders;
@@ -48,7 +48,7 @@ namespace Discord.Net.WebSockets
public VoiceWebSocket(DiscordWSClient client) public VoiceWebSocket(DiscordWSClient client)
: base(client) : base(client)
{ {
_rand = new Random(); //_rand = new Random();
_decoders = new ConcurrentDictionary<uint, OpusDecoder>(); _decoders = new ConcurrentDictionary<uint, OpusDecoder>();
_targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames _targetAudioBufferLength = client.Config.VoiceBufferLength / 20; //20 ms frames
_encodingBuffer = new byte[MaxOpusSize]; _encodingBuffer = new byte[MaxOpusSize];
@@ -301,7 +301,8 @@ namespace Discord.Net.WebSockets
byte[] voicePacket, pingPacket, nonce = null; byte[] voicePacket, pingPacket, nonce = null;
uint timestamp = 0; uint timestamp = 0;
double nextTicks = 0.0, nextPingTicks = 0.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 ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength;
double spinLockThreshold = 3 * ticksPerMillisecond; double spinLockThreshold = 3 * ticksPerMillisecond;
uint samplesPerFrame = (uint)_encoder.SamplesPerFrame; uint samplesPerFrame = (uint)_encoder.SamplesPerFrame;
@@ -346,57 +347,69 @@ namespace Discord.Net.WebSockets
if (_isEncrypted) if (_isEncrypted)
Buffer.BlockCopy(voicePacket, 0, nonce, 0, 12); Buffer.BlockCopy(voicePacket, 0, nonce, 0, 12);
bool hasFrame = false;
while (!cancelToken.IsCancellationRequested) 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) if (ticksToNextFrame <= 0.0)
{ {
long currentTicks = sw.ElapsedTicks; if (hasFrame)
while (currentTicks > nextTicks)
{ {
if (_sendBuffer.Pop(frame)) _udp.Send(voicePacket, rtpPacketLength);
{ hasFrame = false;
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;
} }
nextTicks += ticksPerFrame;
//Is it time to send out another ping?
if (currentTicks > nextPingTicks) if (currentTicks > nextPingTicks)
{ {
//_udp.Send(pingPacket, pingPacket.Length); _udp.Send(pingPacket, pingPacket.Length);
nextPingTicks = currentTicks + 5 * Stopwatch.Frequency; nextPingTicks = currentTicks + 5 * ticksPerSeconds;
} }
} }
//Dont sleep if we need to output audio in the next spinLockThreshold else
else if (ticksToNextFrame > spinLockThreshold)
{ {
int time = (int)Math.Ceiling((ticksToNextFrame - spinLockThreshold) / ticksPerMillisecond); if (hasFrame)
Thread.Sleep(1); {
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); _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 //No thread issue here because SendAsync doesn't start until _isReady is true
byte[] packet = new byte[70]; byte[] packet = new byte[70];
packet[0] = (byte)((_ssrc >> 24) & 0xFF); packet[0] = (byte)((_ssrc >> 24) & 0xFF);