|
@@ -18,8 +18,9 @@ namespace Discord.WebSockets.Voice |
|
|
{ |
|
|
{ |
|
|
internal partial class VoiceWebSocket : WebSocket |
|
|
internal partial class VoiceWebSocket : WebSocket |
|
|
{ |
|
|
{ |
|
|
private const int MaxOpusSize = 4000; |
|
|
|
|
|
private const string EncryptedMode = "xsalsa20_poly1305"; |
|
|
|
|
|
|
|
|
private const int MaxOpusSize = 4000; //Max size of a single 20ms Opus frame |
|
|
|
|
|
private const double SpinLockMilliseconds = 3.0; //If we're going to send audio in the next X milliseconds, dont use Task.Delay or Thread.Sleep |
|
|
|
|
|
private const string EncryptedMode = "xsalsa20_poly1305"; |
|
|
private const string UnencryptedMode = "plain"; |
|
|
private const string UnencryptedMode = "plain"; |
|
|
|
|
|
|
|
|
private readonly Random _rand; |
|
|
private readonly Random _rand; |
|
@@ -350,8 +351,8 @@ namespace Discord.WebSockets.Voice |
|
|
uint timestamp = 0; |
|
|
uint timestamp = 0; |
|
|
double nextTicks = 0.0; |
|
|
double nextTicks = 0.0; |
|
|
double ticksPerMillisecond = Stopwatch.Frequency / 1000.0; |
|
|
double ticksPerMillisecond = Stopwatch.Frequency / 1000.0; |
|
|
|
|
|
double spinLockThreshold = SpinLockMilliseconds * ticksPerMillisecond; |
|
|
double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength; |
|
|
double ticksPerFrame = ticksPerMillisecond * _encoder.FrameLength; |
|
|
double spinLockThreshold = 3 * ticksPerMillisecond; |
|
|
|
|
|
uint samplesPerFrame = (uint)_encoder.SamplesPerFrame; |
|
|
uint samplesPerFrame = (uint)_encoder.SamplesPerFrame; |
|
|
Stopwatch sw = Stopwatch.StartNew(); |
|
|
Stopwatch sw = Stopwatch.StartNew(); |
|
|
|
|
|
|
|
@@ -371,7 +372,7 @@ namespace Discord.WebSockets.Voice |
|
|
result[10] = (byte)((_ssrc >> 8) & 0xFF); |
|
|
result[10] = (byte)((_ssrc >> 8) & 0xFF); |
|
|
result[11] = (byte)((_ssrc >> 0) & 0xFF); |
|
|
result[11] = (byte)((_ssrc >> 0) & 0xFF); |
|
|
|
|
|
|
|
|
if (_isEncrypted) |
|
|
|
|
|
|
|
|
if (_isEncrypted) |
|
|
Buffer.BlockCopy(result, 0, nonce, 0, 12); |
|
|
Buffer.BlockCopy(result, 0, nonce, 0, 12); |
|
|
|
|
|
|
|
|
while (!cancelToken.IsCancellationRequested) |
|
|
while (!cancelToken.IsCancellationRequested) |
|
@@ -427,13 +428,26 @@ namespace Discord.WebSockets.Voice |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
//Dont sleep for 1 millisecond if we need to output audio in the next 1.5 |
|
|
|
|
|
else if (_sendQueue.Count == 0 || ticksToNextFrame >= spinLockThreshold) |
|
|
|
|
|
|
|
|
//Dont sleep if we need to output audio in the next spinLockThreshold |
|
|
|
|
|
else if (ticksToNextFrame > spinLockThreshold) |
|
|
|
|
|
{ |
|
|
|
|
|
int time = (int)Math.Ceiling((ticksToNextFrame - spinLockThreshold) / ticksPerMillisecond); |
|
|
|
|
|
#if USE_THREAD |
|
|
|
|
|
Thread.Sleep(time); |
|
|
|
|
|
#else |
|
|
|
|
|
await Task.Delay(time).ConfigureAwait(false); |
|
|
|
|
|
#endif |
|
|
|
|
|
} |
|
|
|
|
|
//Don't spinlock if we're not actually sending audio (or buffer underrunning) |
|
|
|
|
|
else if (_sendQueue.Count == 0) |
|
|
|
|
|
{ |
|
|
|
|
|
int time = (int)Math.Ceiling(ticksToNextFrame / ticksPerMillisecond); |
|
|
#if USE_THREAD |
|
|
#if USE_THREAD |
|
|
Thread.Sleep(1); |
|
|
|
|
|
|
|
|
Thread.Sleep(time); |
|
|
#else |
|
|
#else |
|
|
await Task.Delay(1).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
await Task.Delay(time).ConfigureAwait(false); |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
catch (OperationCanceledException) { } |
|
|
catch (OperationCanceledException) { } |
|
|