Webrtc Rtp包解密

一、包发送优先级

Audio = 重传包 》视频包 = Fec包 》数据包二

int GetPriorityForType(RtpPacketMediaType type) {
  // 较低的数字优先于较高的数字
  switch (type) {
    case RtpPacketMediaType::kAudio:
      // 音频始终优先于其他数据包类型
      return kFirstPriority + 1;
    case RtpPacketMediaType::kRetransmission:
      // 在新媒体之前发送重传
      return kFirstPriority + 2;
    case RtpPacketMediaType::kVideo:
    case RtpPacketMediaType::kForwardErrorCorrection:
      // 视频具有“正常”优先级,用老话说。同时向视频发送冗余。 如果延迟,它可能有一个有用的机会较低
      return kFirstPriority + 3;
    case RtpPacketMediaType::kPadding:
      // 本身可能无用的数据包,仅发送以保持BWE高
      return kFirstPriority + 4;
  }
  RTC_CHECK_NOTREACHED();
}

二、rtp协议

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1      		32位  uint8_t* buffer  size_t size 
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
// |V=2|P|X|  CC   |M|     PT      |       sequence number         |            buffer[0]  buffer[1]  buffer[2]  buffer[3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                           timestamp                           |			buffer[4]  buffer[5]  buffer[6]  buffer[7]	
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |           synchronization source (SSRC) identifier            |			buffer[8]  buffer[9]  buffer[10] buffer[11]	
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// |            Contributing source (CSRC) identifiers             |			buffer[12] ~ buffer[11 + CC * 4]
// |                             ....                              |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// |  header eXtension profile id  |       length in 32bits        |			buffer[12 + CC * 4]~ buffer[12 + CC * 4 +3]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                          Extensions                           |			buffer[12 + CC * 4 + 4]
// |                             ....                              |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// |                           Payload                             |
// |             ....              :  padding...                   |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |               padding         | Padding size  |							buffer[size - 2]  buffer[size - 1]
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


/* RTP header extension, RFC 3550.
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1	 payload_offset = 12 + CC * 4;
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+	 id							| 			扩展容量
|      defined by profile       |           length              |    buffer[payload_offset + 4] | buffer[payload_offset + 4 +2] 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        header extension                       |
|                             ....                              |
*/

// 数据流
80 e0 00 1e 00 00 d2 f0 00 00 00 00 41 9b 6b 49 €?....??....A?kI      
e1 0f 26 53 02 1a ff06 59 97 1d d2 2e 8c 50 01 ?.&S....Y?.?.?P.
cc 13 ec 52 77 4e e50e 7b fd 16 11 66 27 7c b4 ?.?RwN?.{?..f'|?
f6 e1 29 d5 d6 a4 ef3e 12 d8 fd 6c 97 51 e7 e9 ??)????>.??l?Q??
cfc7 5e c8 a9 51 f6 82 65 d6 48 5a 86 b0 e0 8c ??^??Q??e?HZ????
    
其中,
80               是V_P_X_CC
e0               是M_PT
00 1e          	 是SequenceNum
00 00 d2 f0 	 是Timestamp
00 00 00 00		 是SSRC
    
换成二进制:
0X80 = 1000 0000 
     = 10|0|0|0000
        v|p|x|cc 
    
0Xe0 = 1110 0000  
     = |1|110000
       |m|pt

前 12 个字节出现在每个 RTP 包中,仅仅在被混合器插入时,才出现 CSRC 识别符列表。这些域有以下意义: 版本(V): 2位 RTP版本。此协议定义的版本是2 解析: buffer[0] >> 6 填充(P):1位 若填料比特被设置,则此包包含一到多个附加在末端的填充比特,填充比特不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充比特。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个 RTP 包。 解析: buffer[0] & 0x20

扩展(X):占1位 若设置扩展比特,固定头(仅)后面跟随一个头扩展。 解析: buffer[0] & 0x10

CSRC计数(CC): 占4位 CSRC计数器,

标志(M): 占1位 标志的解释由具体协议规定。它用来允许在比特流中标记重要的事件,如帧边界。

负载类型(PT):有效荷载类型,占7位, 此域定义了负载的格式,由具体应用决定其解释。

序列号(sequence number): 占16位, 每发送一个 RTP 数据包,序列号加 1,接收端可以据此检测丢包和重建包序列。序列号的初始值是随机的(不可预测),以使即便在源本身不加密时(有时包要通过翻译器,它会这样做),对加密算法泛知的普通文本攻击也会更加困难。

时间戳(timestamp): 占32位,时间戳反映了RTP数据包中第一个字节的采样时间。时钟频率依赖于负载数据格式,并在描述文件(profile)中进行描述。也可以通过 RTP 方法对负载格式动态描述。 SSRC: 占32位 用以识别同步源。标识符被随机生成,以使在同一个 RTP 会话期中没有任何两个同步源有相同的 SSRC 识别符。 CSRC列表:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

// uint8_t 0~255  0000 0000
bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
  if (size < kFixedHeaderSize) {
    return false;
  }
  // 前两位为版本号
  const uint8_t version = buffer[0] >> 6;
  if (version != kRtpVersion) {
    return false;
  }
  // 0x20 = 0010 0000
  const bool has_padding = (buffer[0] & 0x20) != 0;
  // 0x10 = 0001 0000
  const bool has_extension = (buffer[0] & 0x10) != 0;
  // 0x0f = 0000 1111
  const uint8_t number_of_crcs = buffer[0] & 0x0f;
  // 0x80 = 1000 0000
  marker_ = (buffer[1] & 0x80) != 0;
  // 0x7f = 0111 1111
  payload_type_ = buffer[1] & 0x7f;
  // 读16位 4字节
  sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
  // 读32位 8字节
  timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
  // 读32位 8字节
  ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
  // 数据足够,没有丢失
  if (size < kFixedHeaderSize + number_of_crcs * 4) {
    return false;
  }
  // payload 偏移
  payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;

  if (has_padding) {
    padding_size_ = buffer[size - 1];
    if (padding_size_ == 0) {
      RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
      return false;
    }
  } else {
    padding_size_ = 0;
  }
  // 初始化extension
  extensions_size_ = 0;
  extension_entries_.clear();
  if (has_extension) {
    /* RTP header extension, RFC 3550.
     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |      defined by profile       |           length              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                        header extension                       |
    |                             ....                              |
    */
    // 扩展偏移
    size_t extension_offset = payload_offset_ + 4;
    if (extension_offset > size) {
      return false;
    }
    // ID
    uint16_t profile =
        ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
    // 扩展容量
    size_t extensions_capacity =
        ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
    extensions_capacity *= 4;
    // 判断扩展合法
    if (extension_offset + extensions_capacity > size) {
      return false;
    }
    // 判断是否支持rtp扩展
    if (profile != kOneByteExtensionProfileId &&
        profile != kTwoByteExtensionProfileId) {
      RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
    } else {
      // 扩展头长度
      size_t extension_header_length = profile == kOneByteExtensionProfileId
                                           ? kOneByteExtensionHeaderLength
                                           : kTwoByteExtensionHeaderLength;
      // 填充字节
      constexpr uint8_t kPaddingByte = 0;
      // 填充Id
      constexpr uint8_t kPaddingId = 0;
      // 一字节报头扩展保留ID
      constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
      // 读取extensions
      while (extensions_size_ + extension_header_length < extensions_capacity) {
        // 填充字节为0
        if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
          extensions_size_++;
          continue;
        }
        int id;
        uint8_t length;
        // 例如: 0100 1000
        // 单字节扩展
        if (profile == kOneByteExtensionProfileId) {
          // id 0100
          id = buffer[extension_offset + extensions_size_] >> 4;
          // 1 + 1000
          length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
          // id = 15 或者 id = 0 且 长度 != 1
          if (id == kOneByteHeaderExtensionReservedId ||
              (id == kPaddingId && length != 1)) {
            break;
          }
        } else {
          // id 0100 1000
          id = buffer[extension_offset + extensions_size_];
          length = buffer[extension_offset + extensions_size_ + 1];
        }

        // 超大的rtp标头扩展
        if (extensions_size_ + extension_header_length + length >
            extensions_capacity) {
          RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
          break;
        }
        // 查找或创建扩展信息
        ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
        if (extension_info.length != 0) {
          RTC_LOG(LS_VERBOSE)
              << "Duplicate rtp header extension id " << id << ". Overwriting.";
        }
        // 偏移
        size_t offset =
            extension_offset + extensions_size_ + extension_header_length;
        if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
          RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
          break;
        }
        extension_info.offset = static_cast<uint16_t>(offset);
        extension_info.length = length;
        extensions_size_ += extension_header_length + length;
      }
    }
    // 更新paload偏移
    payload_offset_ = extension_offset + extensions_capacity;
  }
  // 判断越界错误
  if (payload_offset_ + padding_size_ > size) {
    return false;
  }
  // payload 大小
  payload_size_ = size - payload_offset_ - padding_size_;
  return true;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值