Fix voice receiving (#3190)

* Update voice API to version 8

* Fix voice receiving

* Reuse RTP Header array during decryption
This commit is contained in:
José Santos Garrido
2025-09-21 19:20:03 +02:00
committed by GitHub
parent 8883596c31
commit a468e182eb
3 changed files with 26 additions and 18 deletions

View File

@@ -31,7 +31,7 @@ namespace Discord.Audio
}
}
public static int Decrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, byte[] header, byte[] nonce, byte[] key)
public static int Decrypt(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, byte[] header, int headerSize, byte[] nonce, byte[] key)
{
fixed (byte* inPtr = input)
fixed (byte* outPtr = output)
@@ -41,7 +41,7 @@ namespace Discord.Audio
outPtr + outputOffset, out ulong plainLen,
null,
inPtr + inputOffset, (ulong)inputLength,
adPtr, (ulong)header.Length,
adPtr, (ulong)headerSize,
nonce, key
);

View File

@@ -10,11 +10,13 @@ namespace Discord.Audio.Streams
public class SodiumDecryptStream : AudioOutStream
{
private const int RtpHeaderSize = 12;
private const int ExtendedRtpHeaderSize = RtpHeaderSize + 4;
private const int NonceSize = 24;
private const int NonceCounterSize = 4;
private readonly AudioClient _client;
private readonly AudioStream _next;
private readonly byte[] _rtpHeader;
private readonly byte[] _nonce;
public override bool CanRead => true;
@@ -25,6 +27,7 @@ namespace Discord.Audio.Streams
{
_next = next;
_client = (AudioClient)client;
_rtpHeader = new byte[ExtendedRtpHeaderSize];
_nonce = new byte[NonceSize];
}
@@ -35,26 +38,30 @@ namespace Discord.Audio.Streams
if (_client.SecretKey == null)
return Task.CompletedTask;
// Extract nonce from the payload.
// Extract nonce counter from the end of the payload.
for (int i = 0; i < NonceCounterSize; i++)
_nonce[i] = buffer[offset + count + NonceCounterSize - i - 1]; // Big-endian to little-endian
_nonce[i] = buffer[offset + count - NonceCounterSize + i];
// Extract RTP header
bool hasExtendedHeader = (buffer[0] & 0x10) != 0;
int rtpHeaderSize = hasExtendedHeader ? ExtendedRtpHeaderSize : RtpHeaderSize;
Buffer.BlockCopy(buffer, offset, _rtpHeader, 0, rtpHeaderSize);
// Decrypt payload
byte[] rtpHeader = new byte[RtpHeaderSize];
Buffer.BlockCopy(buffer, offset, rtpHeader, 0, rtpHeader.Length);
int payloadOffset = offset + rtpHeader.Length;
int payloadLength = count - rtpHeader.Length - NonceCounterSize;
int payloadOffset = offset + rtpHeaderSize;
int payloadLength = count - offset - rtpHeaderSize - NonceCounterSize;
int decryptedLength = SecretBox.Decrypt(
buffer,
payloadOffset,
payloadLength,
buffer,
payloadOffset,
rtpHeader,
_rtpHeader,
rtpHeaderSize,
_nonce,
_client.SecretKey);
int packageLength = rtpHeader.Length + decryptedLength;
int packageLength = rtpHeaderSize + decryptedLength;
return _next.WriteAsync(buffer, offset, packageLength, cancelToken);
}

View File

@@ -14,6 +14,7 @@ namespace Discord.Audio.Streams
private readonly AudioClient _client;
private readonly AudioStream _next;
private readonly byte[] _rtpHeader;
private readonly byte[] _nonce;
private bool _hasHeader;
private ushort _nextSeq;
@@ -24,6 +25,7 @@ namespace Discord.Audio.Streams
{
_next = next;
_client = (AudioClient)client;
_rtpHeader = new byte[RtpHeaderSize];
_nonce = new byte[NonceSize];
_nonceCounter = 0;
}
@@ -60,23 +62,22 @@ namespace Discord.Audio.Streams
_nonceCounter = 0;
// Encrypt payload
byte[] rtpHeader = new byte[RtpHeaderSize];
Buffer.BlockCopy(buffer, offset, rtpHeader, 0, rtpHeader.Length);
int payloadOffset = offset + rtpHeader.Length;
int payloadLength = count - rtpHeader.Length;
Buffer.BlockCopy(buffer, offset, _rtpHeader, 0, _rtpHeader.Length);
int payloadOffset = offset + _rtpHeader.Length;
int payloadLength = count - offset - _rtpHeader.Length;
int encryptedLength = SecretBox.Encrypt(
buffer,
payloadOffset,
payloadLength,
buffer,
payloadOffset,
rtpHeader,
_rtpHeader,
_nonce,
_client.SecretKey);
// Append nonce to encripted payload
Buffer.BlockCopy(counterBytes, 0, buffer, payloadOffset + encryptedLength, counterBytes.Length);
int packageLength = rtpHeader.Length + encryptedLength + counterBytes.Length;
int packageLength = _rtpHeader.Length + encryptedLength + counterBytes.Length;
_next.WriteHeader(_nextSeq, _nextTimestamp, false);
await _next.WriteAsync(buffer, offset, packageLength, cancelToken).ConfigureAwait(false);