140 lines
4.8 KiB
C#
Executable File
140 lines
4.8 KiB
C#
Executable File
using System;
|
|
using System.Linq;
|
|
|
|
namespace Luski.net.Sound
|
|
{
|
|
internal class RTPPacket
|
|
{
|
|
internal RTPPacket()
|
|
{
|
|
|
|
}
|
|
|
|
internal RTPPacket(byte[] data)
|
|
{
|
|
Parse(data);
|
|
}
|
|
|
|
internal static int MinHeaderLength = 12;
|
|
internal int HeaderLength = MinHeaderLength;
|
|
internal int Version = 0;
|
|
internal bool Padding = false;
|
|
internal bool Extension = false;
|
|
internal int CSRCCount = 0;
|
|
internal bool Marker = false;
|
|
internal int PayloadType = 0;
|
|
internal ushort SequenceNumber = 0;
|
|
internal uint Timestamp = 0;
|
|
internal uint SourceId = 0;
|
|
internal byte[]? Data;
|
|
internal ushort ExtensionHeaderId = 0;
|
|
internal ushort ExtensionLengthAsCount = 0;
|
|
internal int ExtensionLengthInBytes = 0;
|
|
|
|
private void Parse(byte[] data)
|
|
{
|
|
if (data.Length >= MinHeaderLength)
|
|
{
|
|
Version = ValueFromByte(data[0], 6, 2);
|
|
Padding = Convert.ToBoolean(ValueFromByte(data[0], 5, 1));
|
|
Extension = Convert.ToBoolean(ValueFromByte(data[0], 4, 1));
|
|
CSRCCount = ValueFromByte(data[0], 0, 4);
|
|
Marker = Convert.ToBoolean(ValueFromByte(data[1], 7, 1));
|
|
PayloadType = ValueFromByte(data[1], 0, 7);
|
|
HeaderLength = MinHeaderLength + (CSRCCount * 4);
|
|
|
|
//Sequence Nummer
|
|
byte[] seqNum = new byte[2];
|
|
seqNum[0] = data[3];
|
|
seqNum[1] = data[2];
|
|
SequenceNumber = BitConverter.ToUInt16(seqNum, 0);
|
|
|
|
//TimeStamp
|
|
byte[] timeStmp = new byte[4];
|
|
timeStmp[0] = data[7];
|
|
timeStmp[1] = data[6];
|
|
timeStmp[2] = data[5];
|
|
timeStmp[3] = data[4];
|
|
Timestamp = BitConverter.ToUInt32(timeStmp, 0);
|
|
|
|
//SourceId
|
|
byte[] srcId = new byte[4];
|
|
srcId[0] = data[8];
|
|
srcId[1] = data[9];
|
|
srcId[2] = data[10];
|
|
srcId[3] = data[11];
|
|
SourceId = BitConverter.ToUInt32(srcId, 0);
|
|
|
|
if (Extension)
|
|
{
|
|
byte[] extHeaderId = new byte[2];
|
|
extHeaderId[1] = data[HeaderLength + 0];
|
|
extHeaderId[0] = data[HeaderLength + 1];
|
|
ExtensionHeaderId = BitConverter.ToUInt16(extHeaderId, 0);
|
|
|
|
byte[] extHeaderLength16 = new byte[2];
|
|
extHeaderLength16[1] = data[HeaderLength + 2];
|
|
extHeaderLength16[0] = data[HeaderLength + 3];
|
|
ExtensionLengthAsCount = BitConverter.ToUInt16(extHeaderLength16.ToArray(), 0);
|
|
|
|
ExtensionLengthInBytes = ExtensionLengthAsCount * 4;
|
|
HeaderLength += ExtensionLengthInBytes + 4;
|
|
}
|
|
|
|
Data = new byte[data.Length - HeaderLength];
|
|
Array.Copy(data, HeaderLength, Data, 0, data.Length - HeaderLength);
|
|
}
|
|
}
|
|
|
|
private static int ValueFromByte(byte value, int startPos, int length)
|
|
{
|
|
byte mask = 0;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
mask = (byte)(mask | 0x1 << startPos + i);
|
|
}
|
|
|
|
byte result = (byte)((value & mask) >> startPos);
|
|
return Convert.ToInt32(result);
|
|
}
|
|
|
|
internal byte[] ToBytes()
|
|
{
|
|
byte[] bytes = new byte[HeaderLength + Data.Length];
|
|
|
|
//Byte 0
|
|
bytes[0] = (byte)(Version << 6);
|
|
bytes[0] |= (byte)(Convert.ToInt32(Padding) << 5);
|
|
bytes[0] |= (byte)(Convert.ToInt32(Extension) << 4);
|
|
bytes[0] |= (byte)(Convert.ToInt32(CSRCCount));
|
|
|
|
//Byte 1
|
|
bytes[1] = (byte)(Convert.ToInt32(Marker) << 7);
|
|
bytes[1] |= (byte)(Convert.ToInt32(PayloadType));
|
|
|
|
//Byte 2 + 3
|
|
byte[] bytesSequenceNumber = BitConverter.GetBytes(SequenceNumber);
|
|
bytes[2] = bytesSequenceNumber[1];
|
|
bytes[3] = bytesSequenceNumber[0];
|
|
|
|
//Byte 4 bis 7
|
|
byte[] bytesTimeStamp = BitConverter.GetBytes(Timestamp);
|
|
bytes[4] = bytesTimeStamp[3];
|
|
bytes[5] = bytesTimeStamp[2];
|
|
bytes[6] = bytesTimeStamp[1];
|
|
bytes[7] = bytesTimeStamp[0];
|
|
|
|
//Byte 8 bis 11
|
|
byte[] bytesSourceId = BitConverter.GetBytes(SourceId);
|
|
bytes[8] = bytesSourceId[3];
|
|
bytes[9] = bytesSourceId[2];
|
|
bytes[10] = bytesSourceId[1];
|
|
bytes[11] = bytesSourceId[0];
|
|
|
|
Array.Copy(Data, 0, bytes, HeaderLength, Data.Length);
|
|
|
|
return bytes;
|
|
}
|
|
}
|
|
}
|