|
|
@@ -6,47 +6,48 @@ namespace Discord.Audio |
|
|
|
public class RTPWriteStream : Stream |
|
|
|
{ |
|
|
|
private readonly AudioClient _audioClient; |
|
|
|
private readonly byte[] _buffer, _nonce, _secretKey; |
|
|
|
private readonly byte[] _nonce, _secretKey; |
|
|
|
private int _samplesPerFrame; |
|
|
|
private uint _ssrc, _timestamp = 0; |
|
|
|
|
|
|
|
protected readonly byte[] _buffer; |
|
|
|
|
|
|
|
public override bool CanRead => false; |
|
|
|
public override bool CanSeek => false; |
|
|
|
public override bool CanWrite => true; |
|
|
|
|
|
|
|
|
|
|
|
internal RTPWriteStream(AudioClient audioClient, byte[] secretKey, int samplesPerFrame, uint ssrc, int bufferSize = 4000) |
|
|
|
{ |
|
|
|
_audioClient = audioClient; |
|
|
|
_secretKey = secretKey; |
|
|
|
_samplesPerFrame = samplesPerFrame; |
|
|
|
_ssrc = ssrc; |
|
|
|
_nonce = new byte[24]; |
|
|
|
_buffer = new byte[bufferSize]; |
|
|
|
_buffer[0] = 0x80; |
|
|
|
_buffer[1] = 0x78; |
|
|
|
_buffer[8] = (byte)(_ssrc >> 24); |
|
|
|
_buffer[9] = (byte)(_ssrc >> 16); |
|
|
|
_buffer[10] = (byte)(_ssrc >> 8); |
|
|
|
_buffer[11] = (byte)(_ssrc >> 0); |
|
|
|
_nonce = new byte[24]; |
|
|
|
_nonce[0] = 0x80; |
|
|
|
_nonce[1] = 0x78; |
|
|
|
_nonce[8] = (byte)(_ssrc >> 24); |
|
|
|
_nonce[9] = (byte)(_ssrc >> 16); |
|
|
|
_nonce[10] = (byte)(_ssrc >> 8); |
|
|
|
_nonce[11] = (byte)(_ssrc >> 0); |
|
|
|
} |
|
|
|
|
|
|
|
public override void Write(byte[] buffer, int offset, int count) |
|
|
|
{ |
|
|
|
unchecked |
|
|
|
{ |
|
|
|
if (_buffer[3]++ == byte.MaxValue) |
|
|
|
_buffer[2]++; |
|
|
|
if (_nonce[3]++ == byte.MaxValue) |
|
|
|
_nonce[2]++; |
|
|
|
|
|
|
|
_timestamp += (uint)_samplesPerFrame; |
|
|
|
_buffer[4] = (byte)(_timestamp >> 24); |
|
|
|
_buffer[5] = (byte)(_timestamp >> 16); |
|
|
|
_buffer[6] = (byte)(_timestamp >> 8); |
|
|
|
_buffer[7] = (byte)(_timestamp >> 0); |
|
|
|
_nonce[4] = (byte)(_timestamp >> 24); |
|
|
|
_nonce[5] = (byte)(_timestamp >> 16); |
|
|
|
_nonce[6] = (byte)(_timestamp >> 8); |
|
|
|
_nonce[7] = (byte)(_timestamp >> 0); |
|
|
|
} |
|
|
|
|
|
|
|
Buffer.BlockCopy(_buffer, 0, _nonce, 0, 12); //Copy the 12-byte header to be used for nonce |
|
|
|
count = SecretBox.Encrypt(buffer, offset, count, _buffer, 12, _nonce, _secretKey); |
|
|
|
Buffer.BlockCopy(_nonce, 0, _buffer, 0, 12); //Copy the RTP header from nonce to buffer |
|
|
|
_audioClient.Send(_buffer, count + 12); |
|
|
|
} |
|
|
|
|
|
|
|