剑痴乎

  • 首页
  • 文章分类
    • 音视频
    • WebRTC
    • 编程之美
    • Linux
    • Windows
    • 生活点滴
    • 校园生活
  • 参考
    • API参考
    • 实用工具
    • 测试音视频
    • 文档
  • 留言板
  • 关于
剑痴乎
代码为剑,如痴如醉
  1. 首页
  2. WebRTC
  3. 正文

WebRTC研究:RTP中的序列号以及时间戳比较

2019年7月6日 557点热度 1人点赞 1条评论

在使用RTP协议时,如果需要网络对抗,保障QoS(Quality of Service,服务质量),我们需要通过序列号以及时间戳的比较,进行丢包判断。但是有个问题,比如一个RTP包,序列号为number1:5000,另一个RTP包序列号为number2:60000,可以说60000一定比5000大,是个更新的RTP包吗?

当然不是了,首先我们先重温下RTP数据包的结构。

在RFC3550中RTP固定报头结构按如下定义:

1
2
3
4
5
6
7
8
9
10
11
12
    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

可以看到,RTP序列号sequence number用两字节表示,时间戳timestamp用四字节表示。所以序列号以及时间戳就存在一个取值范围。由于是无符号数,所以序列号范围为:[0,2^16-1],时间戳范围为:[0,2^32-1]。当达到最大值时,将发生所谓的回绕。例如,序列号到了2^16-1,下个包序列号就将是0。所以我们不能直接根据数学意义上的大小进行序列号以及时间戳的比较。

在WebRTC中定义了一个大小比较算法,包含数字回绕处理,判断是否是更新的数字。下面说下算法原理:
1)假设有两个U类型的无符号整数:value, prev_value;
2)定义一个常量kBreakpoint,为U类型取值范围的一半;
3)value > prev_value,满足value - prev_value = kBreakpoint时,value大于prev_value;
4)value与prev_value不相等,满足(U)(valude - prev_value) < kBreakpoint时,value大于prev_value。

总结起来就是value与prev_value距离小于取值范围的一半且不相等或者value与prev_value距离等于取值范围的一半,value大于prev_value,就可以说明value大于prev_value。
在modules\include\module_common_types_public.h,相应代码如下:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
template <typename U>
inline bool IsNewer(U value, U prev_value) {
  static_assert(!std::numeric_limits<U>::is_signed, "U must be unsigned");
  // kBreakpoint is the half-way mark for the type U. For instance, for a
  // uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
  constexpr U kBreakpoint = (std::numeric_limits<U>::max() >> 1) + 1;
  // Distinguish between elements that are exactly kBreakpoint apart.
  // If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
  // IsNewer(t2,t1)=false
  // rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
  if (value - prev_value == kBreakpoint) {
    return value > prev_value;
  }
  return value != prev_value &&
         static_cast<U>(value - prev_value) < kBreakpoint;
}
// NB: Doesn't fulfill strict weak ordering requirements.
//     Mustn't be used as std::map Compare function.
inline bool IsNewerSequenceNumber(uint16_t sequence_number,
                                  uint16_t prev_sequence_number) {
  return IsNewer(sequence_number, prev_sequence_number);
}
 
// NB: Doesn't fulfill strict weak ordering requirements.
//     Mustn't be used as std::map Compare function.
inline bool IsNewerTimestamp(uint32_t timestamp, uint32_t prev_timestamp) {
  return IsNewer(timestamp, prev_timestamp);
}

顺便也说下如上函数的一个应用。在WebRTC丢包重传判断中(jitter_buffer模块),需要保存上一次收到的最新RTP序列号latest_received_sequence_number_,以便用于丢包判断(请参考:WebRTC研究:丢包判断),这个RTP包必须是新的数据,不能是重传的旧数据。所以每来一个RTP包时,可以将该RTP包序列号传入如上函数,与之前收到的最新RTP序列号进行对比,从而判断当前RTP包是不是最新的。相应代码如下:

C++
1
2
3
4
5
6
7
8
9
inline uint16_t LatestSequenceNumber(uint16_t sequence_number1,
                                     uint16_t sequence_number2) {
  return IsNewerSequenceNumber(sequence_number1, sequence_number2)
             ? sequence_number1
             : sequence_number2;
}
 
latest_received_sequence_number_ =
          LatestSequenceNumber(latest_received_sequence_number_, packet.seq_num);

参考

[1].rfc1982.https://tools.ietf.org/html/rfc1982

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
标签: WebRTC 网络 音视频
最后更新:2021年3月4日

Jeff

管理员——代码为剑,如痴如醉

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

我的其它小窝

公众号:码上Play(基本不更新,回答问题用。如果没回复就多发几次,忙的时候可能会看不到。)

近期评论
  • 头像lingjzhang on WebRTC研究:Trendline滤波器-TrendlineEstimator我个人一直很好奇threshold_gain_参数…
  • 头像lingjzhang on WebRTC研究:Trendline滤波器-TrendlineEstimator你好,我这边看modified_trend的计算公…
  • 头像Jeff on 大话WebRTC是的
  • 头像tube on 大话WebRTC这个人抄袭你的吧:https://develope…
  • 头像vivi on WebRTC 安卓Native code编译问题sudo update-alternatives…
版权声明

为支持原创,创作更好的文章,未经许可,禁止任何形式的转载与抄袭,如需转载请邮件私信!本人保留所有法定权利。违者必究!

相关文章推荐
  • WebRTC研究:Transport-cc之RTP及RTCP
  • WebRTC音视频传输基础:NAT穿透
  • WebRTC研究:丢包判断
  • WebRTC研究:统计参数之往返时延
  • 音视频开发入门:视频基础

COPYRIGHT © 2021 剑痴乎. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS