当每个复合 RTCP 报文被接收到时,平均 RTCP 报文大小(AVG_RTCP_Size)的状态就会更新,更新公式为:AVG_RTCP_Size = (1 / 16) * last_rtcp_package_size + (15 / 16) * previous_avg_rtcp_size。
接收 RTCP BYE 报文如果接收到了 RTCP BYE 报文,会在成员列表中确认一下,如果有对应的 SSRC 项,就会把它移除并更新成员总数(Members)。同时也会在发送者 SSRC 表中做类似的操作,如果找到了就删除它并更新发送者总数(Senders)。
此外,为了让 RTCP 的传输率跟随 Session 中人数的变化而动态变化,如下算法会在收到 BYE 报文时执行:
TN 按照如下公式更新:TN = TC + (Members / P-Members) * (TN - TC) 。
TP 按照如下公式更新:TP = TC - (Members / P-Members) * (TC - TP) 。
下一个 RTCP 报文按照新的 TN 指示发送(比原来发的更早了)。
将 P-Members 设置成 Members 的值。
这个算法没有考虑到一个意外情况,那就是当一大波人(并不是所有人)同时退出 Session 时,会导致 RTCP 的周期降到一个非常小的值,这样可能出现错误的 Timeout 判断,最终它会导致整个 Session 的总人数降到 0。但是,这种情况一般来说很少发生,所以大家都觉得问题不是很大。
SSRC 的超时我们需要偶尔确认一下是不是太久没收到某个与会者的报文了,一般来说每个 RTCP 周期内都必须确认。如果发现了超时,就需要将这个 SSRC 从成员列表(Members & Senders)中移除,并更新当前人数。
Member 表:一般超过 5 个发送周期(不考虑随机缩放因素)未收到某人的消息,会被确定为超时。
Sender 表:一般是 2 个发送周期。
如果某个成员被确定为超时,上一步介绍的算法就操作起来了。
发送倒计时我们已经知道,每个 RTCP 都是周期性的发送的,当发送完一个 RTCP 报文时,就会根据 TN 新建一个倒计时,每次当倒计时归零时就会重复如下操作:
计算传输周期 T,引入随机缩放因素。
如果 TP + T <= TC,立即发送一个 RTCP 报文,并将 TP 设定为 TC,TN 设定为 TC + T,下一个倒计时会在 TN 时刻归零。如果 TP + T> TC,就不发送了 RTCP 报文,计算 TN = TC + T 后,然后重设一个定时器在 TN 归零。
P-Members 设定为 Members。
如果发送了 RTCP 报文,initial 会被设定为 FALSE,AVG_RTCP_Size 会按如下方式更新:
AVG_RTCP_Size = (1 / 16) * last_rtcp_package_size + (15 / 16) * previous_avg_rtcp_size。
当某个人想要退出 Session 时,他就会发一个 BYE 报文给其他人。为了防止一大帮人同时退出 Session 时出现 BYE 报文井喷的情况,所以当 Session 人数超过 50 时,会按下述方式操作:
当一个参与者想要离开时,TP 会设置成 TC,Members 和 P-Members 会设置成 1,initial 设置成 1,we_send 设置成 false,senders 设置成 0,avg_rtcp_size 设置成复合 BYE 报文的大小。然后计算 RTCP 发送间隔 T,下个 BYE 报文会在 TN = TC + T 后发送。
每当这个要离开的人收到了别人的 BYE 报文时,Members 就会增加 1,无论这个人是否在成员列表中。Members 的数量只有收到 BYE 报文时才增加,其他报文都不管。同样,avg_rtcp_size 也只管收到的 BYE 报文的大小。Senders 数量也不变。
对了 BYE 报文来说,除了状态值的维护套路变了,发送逻辑和前面提到的都一样。通过上述方案,即可以让 BYE 报文正确地发送,还能控制整体带宽。最差的情况下,也只会导致 RTCP 报文传输占用 10% 的 Session 总带宽。
有些参与者可能不想按照上述的方式发送 BYE 报文,他们可能什么也不发就离开了。这类情况会被 Timeout 机制 hold 住。
如果一个参与者要离开时,Session 的总人数小于 50,他可能会直接发送一个 BYE 报文,也可能按照上述方案来进行。
此外还有一个无论如何都要遵循的规则,如果一个参与者一个 RTP 报文或者 RTCP 报文都没发送过的话,那他离开 Session 时绝对不能发送 BYE 报文。
更新 WE_Sent当某个参与者最近发送过一个 RTP 后,他就会将 WE_Sent 置为 true 并将自己加入到 Senders 表中,否则如果超过两个 RTCP 发送周期的时间内都没发送过 RTP 报文,那他就会将自己从 Sender 表中移除,并将 WE_Sent 置为 false。
SDES 类报文的带宽分配SDES 报文中除了必须要有的 CNAME 之外,还有一些别的信息,比如 NAME(个人名称),EMAIL(email 地址)等。上层应用也可以自定义的一些报文类型,但是要小心别付加了太多的自定义信息以至于拖慢了整个 RTCP 协议的运转。建议这些附加内容的带宽占用不要超过整个 RTCP 协议带宽的 20%。此外,也不要觉得每个上层应用都会包含所有的 SDES 内容。上层应用要根据实际使用的情况给这些内容分配一定的带宽,一般来说他们会通过控制发送间隔来控制这部分的带宽。