webrtc通过函数AheadOf( )进行rtp序列号的新旧的比较,rtp序列号的比较不能单纯的比较大小,因为会涉及到回环:
template <typename T, T M = 0>
inline bool AheadOf(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
return a != b && AheadOrAt<T, M>(a, b);
}
template <typename T, T M>
inline typename std::enable_if<(M == 0), bool>::type AheadOrAt(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
const T maxDist = std::numeric_limits<T>::max() / 2 + T(1);
if (a - b == maxDist)
return b < a;
return ForwardDiff(b, a) < maxDist;
}
template <typename T, T M>
inline typename std::enable_if<(M == 0), T>::type ForwardDiff(T a, T b) {
static_assert(std::is_unsigned<T>::value,
"Type must be an unsigned integer.");
return b - a;
}
这里一共涉及到了三个函数AheadOf()、AheadOrAt()、ForwardDiff()
AheadOf(a,b)
的语义就是序列号a是否比序列号新,return中看到比较是否相等,然后就是执行AheadOrAt( )
AheadOrAt(a, b)
是判断a是否比b新的核心,其原理是这样的:rfc1982规定了序列号递增间隔不能超过取值范围的1/2(这是自己理解的),那么要判断a是否比b新,只要判断b到a的递增是否在1/2即可,递增超过1/2,则一定是因为a比b老而导致了回环, b到a的递增就是b到a的前向间距,前向间距怎么求呢,我们知道在向量的世界里,表示b到a的前向间距的话,我们会用 a - b(也就是终点减去起点得到一个向量增量),增量是正数时,就是前向增量,而增量是一个负数的时候,代表这是一个后向增量(b要后退这么才能到a),因无符号系统中因为没有负数,运算出来的负数都被无符号运算系统转变成了正数,相当于被加了一圈成了正数,向后倒变成了向前跑多大半圈,刚好是我们想要的前向间距的值
所以ForwardDiff(b, a) < maxDist;
这句话的意思就是说b到a的前向间距小于maxDist,此时符合协议要求的递增大小,所以a更新;
(注意: ForwardDiff(a, b)
中的内部实现虽然是 b - a
而不是a - b
,这是因为a和b在上一个函数是被反转传过来的。)
最后总结: 如果上一个包到当前包的前向间距在最大取值范围1/2内,那么说明当前包在递增间隔内做了递增,所以它是一个更新的包,当当前包是一个更旧的包的时候,上一个包到当前包的前向间距要绕过超过一个大半圈的间距增量才能到当前包,和序列号的递增间隔所设定的范围矛盾了,所以肯定是一个旧包。