private const byte PAYLOAD_TYPE_MASK = 0x7F; // 01111111b /// <summary> /// Буфер для полезной нагрузки RTP пакетов /// </summary> //private byte[] buffer = new byte[ushort.MaxValue]; /// <summary> /// Формирует структуру RtpPacket и вызывает событие CreatedRtpPacket /// </summary> /// <param name="data">Указатель на область памяти /// в неуправляемой куче, где содержится RTP пакет</param> /// <param name="count">Размер области памяти в байтах</param> unsafe public void HandleRtpPacket(IPEndPoint remoteEndPoint, IntPtr data, int count) //IntPtr data, int count)// { RtpPacket packet = new RtpPacket(); int offset = 0; byte firstByte = *(byte *)(data + offset); offset++; byte secondByte = *(byte *)(data + offset); packet.Version = (byte)(firstByte >> 6); packet.Padding = (firstByte & PADDING_MASK) == PADDING_MASK; packet.HasExtension = (firstByte & EXTENSION_MASK) == EXTENSION_MASK; packet.CSRCCount = (byte)(firstByte & CSRCCOUNT_MASK); packet.IsMarker = (secondByte & IS_MARKER_MASK) == IS_MARKER_MASK; packet.PayloadType = (byte)(secondByte & PAYLOAD_TYPE_MASK); offset++; packet.SequenceNumber = BigEndian.ReadUInt16((void *)(data + offset)); offset += 2; packet.Timestamp = BigEndian.ReadUInt32((void *)(data + offset)); offset += 4; packet.SSRC = BigEndian.ReadUInt32((void *)(data + offset)); if (packet.SSRC != SSRC) { return; // пакеты другой сессии } if (packet.HasExtension) { offset = 12 + packet.CSRCCount * 4 + 0; packet.HeaderExtensionProfile = BigEndian.ReadUInt16((void *)(data + offset)); offset += 2; packet.HeaderExtensionLength = BigEndian.ReadUInt16((void *)(data + offset)); offset += 2; packet.HeaderExtension = data + offset; offset += packet.HeaderExtensionLength; packet.PayloadLength = count - offset; packet.Payload = data + offset; } else { offset = 12 + packet.CSRCCount * 4 + 0; packet.HeaderExtensionProfile = 0; packet.HeaderExtensionLength = 0; packet.HeaderExtension = IntPtr.Zero; packet.PayloadLength = count - offset; packet.Payload = data + offset; } RtpPacketRecieved(packet); }
/// <summary> /// Обрабатывает пришедшие данные и вызывает всякие события /// </summary> /// <param name="data">Указатель область памяти, /// где располагаются данные RTCP пакета</param> /// <param name="count">Размер области памяти в байтах</param> public void CreateRtcpPacket(IntPtr data, int count) { Marshal.Copy(data, buffer, 0, count); // сейчас в массиве buffer содержится один или более RTCP пакетов // их нужно обработать в цикле // сначала обрабатывается первый пакет, который находится в начале // буфера, потом данные в буфере сдвигаются к началу, и т. д., // пока не будут обработаны все пакеты while (count > 0) { int version = buffer[0] >> 6; if (version != 2) { return; } bool padding = (buffer[0] & _00100000) == _00100000; RtcpPacketType packetType = (RtcpPacketType)buffer[1]; int length = (BigEndian.ReadUInt16(buffer, 2) + 1) * 4; switch (packetType) { case RtcpPacketType.SenderReport: RtcpSenderReportPacket packet = new RtcpSenderReportPacket(); packet.Version = (byte)(buffer[0] >> 6); packet.Padding = ((buffer[0] & _00100000) == _00100000); packet.ReceptionReportCount = (byte)(buffer[0] & _00011111); packet.PayloadType = RtcpPacketType.SenderReport; packet.SenderSSRC = BigEndian.ReadUInt32(buffer, 4); packet.TimestampMSW = BigEndian.ReadUInt32(buffer, 8); packet.TimestampLSW = BigEndian.ReadUInt32(buffer, 12); packet.RTPTimestamp = BigEndian.ReadUInt32(buffer, 16); packet.SenderPacketCount = BigEndian.ReadUInt32(buffer, 20); packet.SenderOctetCount = BigEndian.ReadUInt32(buffer, 24); CreatedRtcpSenderReport(packet); break; case RtcpPacketType.ReceiverReport: // ничего не делать, т. к. нам не будут приходить пакеты такого типа break; case RtcpPacketType.SourceDescription: // прочитать количество источников int sourceCount = buffer[0] & _00011111; int pos = 4; RtcpSourceDescription[] result = new RtcpSourceDescription[sourceCount]; for (int i = 0; i < sourceCount; i++) { result[i] = new RtcpSourceDescription(); result[i].SSRC = BigEndian.ReadUInt32(buffer, pos); pos += 4; List <RtcpSourceDescriptionItem> items = new List <RtcpSourceDescriptionItem>(); while (buffer[pos] != 0) { RtcpSourceDescriptionType type = (RtcpSourceDescriptionType)buffer[pos]; pos += 1; int itemLength = buffer[pos]; pos += 1; string itemText = Encoding.UTF8.GetString(buffer, pos, itemLength); pos += itemLength; items.Add(new RtcpSourceDescriptionItem() { Type = type, Text = itemText }); } result[i].Items = items.ToArray(); // выравниваем по 4 байтам while (pos % 4 != 0) { pos++; } } CreatedRtcpSourceDescription(result); break; case RtcpPacketType.Goodbye: // ничего не делать break; case RtcpPacketType.ApplicationDefined: // ничего не делать break; } // смещаем оставшиеся данные в буфере к началу for (int i = length; i < count; i++) { buffer[i - length] = buffer[i]; buffer[i] = 0; } count -= length; } }