Bandwidth Estimation in WebRTC (and the new Sender Side BWE)

本文探讨了WebRTC中带宽估算(BWE)模块的关键作用及其算法的发展历程。从早期依赖丢包反馈到现代通过分析数据包延迟变化预测网络拥塞的方法,文章详细介绍了Google拥塞控制算法等几种主流算法的工作原理。同时,文中还讨论了发送方带宽估算的最新进展,包括传输范围序列号和传输反馈机制,并分析了这些变化对服务器实施带宽估算的影响。

Bandwidth Estimation in WebRTC (and the new Sender Side BWE)

Bandwidth estimation is probably the most critical component in the video engine of WebRTC. The bandwidth estimation (BWE) module is responsible for deciding how much video* traffic you can send without congesting the network to prevent degradation of the video quality. 

In the past bandwidth estimation algorithms used to be very rudimentary and based mostly on packet loss. Basically we used to start increasing slowly the video bitrate until we detected packets being lost.  To detect the packet loss you use the standard RTCP feedback mechanisms where the receiver side reports packet loss periodically using RTCP Receiver Report (RR) messages.

Modern bandwidth estimation algorithms are more advanced and try to detect congestion before it is bad enough to make routers discard packets. These algorithms predicts congestion analyzing the delay between packets. The idea is that when you start having some congestion, the buffers in the routers will start filling and the delay will be more variable. Some popular examples of these algorithms are  Google Congestion Control (the one used in WebRTC),  SCReAMand  SPROUT.  If you want to read more about the history and status of congestion control standards you can read this very  interesting post from Randell Jesup.

From the very beginning of WebRTC, the media engine (that is built by Google but included in both Chrome and Firefox) was based on the concept of remote bandwidth estimation. As explained before the receiver of the traffic analyzes the inter-packet delay and generates an estimation of the available bandwidth that is reported back to the sender using RTCP messages with a new message type that was defined for this purpose:  REMB. Another detail of WebRTC implementation is that the sender will use not only this bandwidth estimation received in the REMB packet but also the packet loss feedback to decide the final value of the target video bitrate to be sent.

Sender pseudocode (send_side_bandwidth_estimation.cc):
  onFeedbackFromReceiver(lossRate):
     if (lossRate < 2%) video_bitrate *= 1.08
     if (lossRate > 10%) video_bitrate *= (1 - 0.5*lossRate)
    if (video_bitrate > bwe) video_bitrate = bwe;

The nice consequence of that implementation is that it reduces bitrate quickly when overuse is detected while slowly increasing bitrate when no congestion is detected.

But in recent versions of Chrome this has changed and now the whole bandwidth estimation logic happens in the sender side.   The basic detection of congestion is not very different from how it was before and the sender needs delay information from the receiver side in order to be able to estimate the available bandwidth.  This is accomplished with two new mechanisms/protocols:

1. Transport wide sequence numbers header extension:   All the video RTP packets carry an extra 4 bytes in the header to include a sequence number.    This is negotiated in the SDP with the following line:

a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

Note: the idea of this new sequence number is to be able to use a single counter for both audio and video but Chrome still doesn't use it for audio, so I think it is not very useful yet .


2. Transport Feedback: The receiver side sends periodic feedback to the media sender with information  about the packets received and the the delay between them.  To do this the receiver uses a new RTCP Packet (Transport Feedback).  This feature is negotiated in the SDP with this line including the new RTCP feedback message:

a=rtcp-fb:100 transport-cc 

When looking at how is this transport feedback packet looks like it is funny to realize that there is a  specification with Google's proposal and an  official standardization proposal but the only source of truth is the  real implementation in the source code.

This RTCP feedback is sent every 100 msecs by default but it is dynamically adapted to use 5% of the available bandwidth (min value is 50 msecs and max is 250 msecs).

The format of this new RTCP packet is very concise to minimize the size, including grouping packets in chunks, storing numbers as base + diff or reducing granularity to 0.25 msec intervals. I did a simple test and even with these improvements it was still using 16Kbps sending feedback packets every 50 msecs (Figure 2).
 
 
 
 

Figure 2: Bandwidth used in RTCP Transport Feedback Messages
You can take a look at the implementation in remote_estimator_proxy.h (generating the packets) and transport_feedback.cc(serialization). 

What is good about sender side bandwidth estimation? The theory  as explained by Google is that this way all the decision logic is in a single place (the sender) and that it makes it possible to test new algorithms easily because you don't depend on both endpoints. Honestly given that browsers auto update I don't see the big advantage of this point but it is certainly cleaner even if it is more expensive in bandwidth usage. The other advantage is that the sender knows the type of traffic he is sending and can use a different algorithm when sending normal video than when doing a screencast for example.

Are we affected? If you are building a media server that requires bandwidth estimation for anything (for example to decide the quality to forward when using simulcast) you will need to upgrade your implementation at some point. The good news is that Chrome will have to support the old mechanism (REMB) for a while, at least until Firefox includes support for it.   But REMB probably won't get more improvements and it is more likely to have bugs now so probably not a good idea to postpone the change much.

Is sender side bwe really better?
 I did a quick test ( this is the test page where you can try one or the other changing a boolean) with both algorithms in Chrome (old REMB vs new Transport Feedback) and the new one performed way better at least regarding ramp-up time at the beginning of the connection (see figures below).   I don't think there is a technical reason for that apart from the fact that Google is now focused on the new one and not the old one and all the new improvements are probably only in the new algorithm.   Apparently there is something in the new code to handle in a special way the bwe during the first 2 seconds but I didn't investigate it much.



Who is working on this and what is the status?
  Sender side bandwidth estimation is the default in Chrome 55 but this is still work in progress and we should expect many changes.   The official standardization is happening in IETF in the  RMCAT group but most of the implementation available in Chrome is Google's own version of the in-progress specifications for algorithms and feedback protocols. 

 
 
 
 
 
 
 
 * Chrome is planning to use bandwidth estimation also to decide the audio bitrate to send (Planned for version 58).

You can follow me in Twitter if you are interested in Real Time Communications.
### WebRTC中RtpSender的工作原理 在WebRTC中,`RtpSender` 是一个核心组件,用于将音视频数据通过 RTP(实时传输协议)发送到对端。以下是关于 `RtpSender` 工作原理的详细说明: #### 1. 数据封装与传输 `RtpSender` 的主要任务是将媒体流(音频或视频)的数据进行封装并发送到网络上。它会根据 RTP 协议的标准格式化数据包,确保每个数据包包含必要的头部信息和负载数据。这些头部信息包括时间戳、序列号以及同步源标识符(SSRC)等[^1]。 ```python # 示例代码:RTP 数据包的基本结构 class RtpPacket: def __init__(self, payload_type, sequence_number, timestamp, ssrc, payload): self.payload_type = payload_type self.sequence_number = sequence_number self.timestamp = timestamp self.ssrc = ssrc self.payload = payload def serialize(self): # 将 RTP 数据包序列化为字节流 header = bytearray(12) # 假设固定大小的 RTP 头部 # 设置版本、填充位、扩展位等字段 header[0] = (2 << 6) | (0 << 5) | (0 << 4) # 设置有效载荷类型 header[1] = self.payload_type # 设置序列号 header[2:4] = self.sequence_number.to_bytes(2, 'big') # 设置时间戳 header[4:8] = self.timestamp.to_bytes(4, 'big') # 设置 SSRC header[8:12] = self.ssrc.to_bytes(4, 'big') return header + self.payload ``` #### 2. 与RTP/RTCP模块的交互 `RtpSender` 与 RTP 和 RTCP 模块紧密协作。它不仅负责发送 RTP 数据包,还会生成相关的 RTCP 控制包,例如接收方报告(RR)和发送方报告(SR)。这些控制包用于监控传输质量,并提供反馈以调整发送速率或编码参数[^2]。 #### 3. 音视频流的处理 在实际应用中,`RtpSender` 可能需要同时处理多路音视频流。每一路流都会分配唯一的 SSRC 标识符,以便接收端能够区分不同的媒体流。此外,`RtpSender` 还支持扩展头字段(Extension Header),用于携带额外的元数据,例如空间方向信息或唇同步标记[^3]。 #### 4. 网络路径选择与优化 `RtpSender` 在发送数据时会利用 ICE(交互式连接建立)协商过程中确定的最佳网络路径。这意味着它会选择最合适的候选地址和端口组合来发送 RTP 数据包,从而降低延迟并提高传输可靠性[^1]。 #### 5. 动态适应网络条件 为了应对网络条件的变化,`RtpSender` 通常会结合拥塞控制算法(如 Google Congestion Control 或 GCC)动态调整发送速率。这有助于避免网络拥塞导致的丢包或延迟增加问题。 ```python # 示例代码:简单的拥塞控制逻辑 class CongestionController: def __init__(self, initial_bitrate): self.target_bitrate = initial_bitrate def update_bitrate(self, feedback): # 根据 RTCP 反馈更新目标比特率 if feedback['packet_loss_rate'] > 0.05: self.target_bitrate *= 0.9 elif feedback['available_bandwidth'] > self.target_bitrate: self.target_bitrate *= 1.1 return self.target_bitrate ``` #### 6. 安全性保障 在发送 RTP 数据之前,`RtpSender` 通常会对数据进行加密处理,以确保通信的安全性。这通常通过 SRTP(安全 RTP)协议实现,使用预共享密钥或 DTLS-SRTP 协商的密钥对数据进行加密和解密[^2]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值