You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.9 KiB
81 lines
2.9 KiB
4 years ago
|
using System;
|
||
|
using System.Threading;
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
namespace Discord.Audio.Streams
|
||
|
{
|
||
|
///<summary> Reads the payload from an RTP frame </summary>
|
||
|
public class RTPReadStream : AudioOutStream
|
||
|
{
|
||
|
private readonly AudioStream _next;
|
||
|
private readonly byte[] _buffer, _nonce;
|
||
|
|
||
|
public override bool CanRead => true;
|
||
|
public override bool CanSeek => false;
|
||
|
public override bool CanWrite => true;
|
||
|
|
||
|
public RTPReadStream(AudioStream next, int bufferSize = 4000)
|
||
|
{
|
||
|
_next = next;
|
||
|
_buffer = new byte[bufferSize];
|
||
|
_nonce = new byte[24];
|
||
|
}
|
||
|
|
||
|
/// <exception cref="OperationCanceledException">The token has had cancellation requested.</exception>
|
||
|
/// <exception cref="ObjectDisposedException">The associated <see cref="T:System.Threading.CancellationTokenSource" /> has been disposed.</exception>
|
||
|
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancelToken)
|
||
|
{
|
||
|
cancelToken.ThrowIfCancellationRequested();
|
||
|
|
||
|
int headerSize = GetHeaderSize(buffer, offset);
|
||
|
|
||
|
ushort seq = (ushort)((buffer[offset + 2] << 8) |
|
||
|
(buffer[offset + 3] << 0));
|
||
|
|
||
|
uint timestamp = (uint)((buffer[offset + 4] << 24) |
|
||
|
(buffer[offset + 5] << 16) |
|
||
|
(buffer[offset + 6] << 8) |
|
||
|
(buffer[offset + 7] << 0));
|
||
|
|
||
|
_next.WriteHeader(seq, timestamp, false);
|
||
|
await _next.WriteAsync(buffer, offset + headerSize, count - headerSize, cancelToken).ConfigureAwait(false);
|
||
|
}
|
||
|
|
||
|
public static bool TryReadSsrc(byte[] buffer, int offset, out uint ssrc)
|
||
|
{
|
||
|
ssrc = 0;
|
||
|
if (buffer.Length - offset < 12)
|
||
|
return false;
|
||
|
|
||
|
int version = (buffer[offset + 0] & 0b1100_0000) >> 6;
|
||
|
if (version != 2)
|
||
|
return false;
|
||
|
int type = (buffer[offset + 1] & 0b01111_1111);
|
||
|
if (type != 120) //Dynamic Discord type
|
||
|
return false;
|
||
|
|
||
|
ssrc = (uint)((buffer[offset + 8] << 24) |
|
||
|
(buffer[offset + 9] << 16) |
|
||
|
(buffer[offset + 10] << 8) |
|
||
|
(buffer[offset + 11] << 0));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public static int GetHeaderSize(byte[] buffer, int offset)
|
||
|
{
|
||
|
byte headerByte = buffer[offset];
|
||
|
bool extension = (headerByte & 0b0001_0000) != 0;
|
||
|
int csics = (headerByte & 0b0000_1111) >> 4;
|
||
|
|
||
|
if (!extension)
|
||
|
return 12 + csics * 4;
|
||
|
|
||
|
int extensionOffset = offset + 12 + (csics * 4);
|
||
|
int extensionLength =
|
||
|
(buffer[extensionOffset + 2] << 8) |
|
||
|
(buffer[extensionOffset + 3]);
|
||
|
return extensionOffset + 4 + (extensionLength * 4);
|
||
|
}
|
||
|
}
|
||
|
}
|