webrtc弱网-ReceiveSideCongestionController类源码分析及算法原理

       ReceiveSideCongestionController是WebRTC接收端拥塞控制的核心枢纽,承担双模式带宽估计的关键职责。它通过智能算法切换机制,动态选择发送端BWE(基于TransportSequenceNumber的延迟反馈)或接收端BWE(基于AbsoluteSendTime/TOF的本地估计)模式。针对音频流强制使用发送端BWE确保低延迟,视频流则自适应选择最优路径。该组件集成RembThrottler进行码率限制,通过RemoteEstimatorProxy生成TransportFeedback,并采用精细的线程安全设计保护共享状态。最终通过REMB和TransportFeedback RTCP消息将网络状态反馈给发送端,实现端到端的拥塞控制闭环,确保实时通信的质量和稳定性。

一. 核心功能

接收端拥塞控制器是WebRTC中负责接收方带宽估计的关键组件,主要功能包括:

  • 双模式带宽估计:支持发送端BWE和接收端BWE两种模式

  • 反馈管理:通过TransportFeedback和REMB消息向发送端反馈网络状态

  • 动态算法选择:根据RTP扩展头自动选择最优的带宽估计算法

  • 码率控制:限制最大接收码率,避免网络拥塞

二. 核心算法原理

发送端BWE (Sender-side BWE)

详细见:https://blog.youkuaiyun.com/talkRTC/article/details/150635619?spm=1001.2014.3001.5501
// 基于TransportSequenceNumber的带宽估计
// 接收端记录包到达时间,通过TransportFeedback消息反馈给发送端
// 发送端基于这些信息进行带宽估计

接收端BWE (Receiver-side BWE)

// 两种估计算法:
// 1. AbsoluteSendTime算法:基于绝对发送时间扩展头
// 2. SingleStream算法:基于传输时间偏移
// 算法根据数据包中的扩展头动态切换

算法原理图

1. 两种估计算法对比

特性AbsoluteSendTime算法SingleStream(TOF)算法
时间基准绝对发送时间戳传输时间偏移
精度高(24位, 约15μs)中等
同步要求需要时钟同步相对时间,不要求严格同步
适用场景视频会议、实时通信传统RTP流

2. 包分组处理

// 包组划分原则:
// - 发送时间间隔 > 5ms 作为组边界
// - 每组包含多个连续包
// 计算组间延迟变化:
组间延迟梯度 = (到达时间差 - 发送时间差) / 发送时间差

3. 过载检测机制

基于Kalman滤波的延迟变化检测:
状态变量: [延迟梯度, 延迟变化率]
观测值: 实际测量的延迟梯度
检测逻辑:
  - 延迟梯度 > 阈值 + 方差: 过载
  - 延迟梯度 < -阈值: 欠载  
  - 其他: 正常

工作时序图

AST算法核心流程

// 1. 时间戳转换
absolute_send_time = 从RTP扩展头提取
send_time_24bits = (absolute_send_time * 1000) >> 18

// 2. 包组检测
if (current_send_time - prev_send_time > 5ms) {
    // 新包组开始
    form_new_packet_group();
}

// 3. 延迟计算
inter_arrival = current_arrival - prev_arrival
inter_send = current_send - prev_send  
delay_gradient = inter_arrival - inter_send

// 4. 状态判断
if (delay_gradient > threshold + noise_var) {
    state = OVERUSE;
} else if (delay_gradient < -threshold) {
    state = UNDERUSE;
} else {
    state = NORMAL;
}

三. 关键数据结构

class ReceiveSideCongestionController {
private:
    Clock& clock_;                          // 系统时钟
    RembThrottler remb_throttler_;          // REMB码率限制器
    RemoteEstimatorProxy remote_estimator_proxy_; // 远程估计代理
    
    mutable Mutex mutex_;                   // 线程安全锁
    std::unique_ptr<RemoteBitrateEstimator> rbe_; // 远程带宽估计器
    bool using_absolute_send_time_;         // 当前使用的算法标志
    uint32_t packets_since_absolute_send_time_; // AST算法包计数器
};

四. 核心方法详解

4.1 构造函数

ReceiveSideCongestionController::ReceiveSideCongestionController(
    Clock* clock,
    RemoteEstimatorProxy::TransportFeedbackSender feedback_sender,
    RembThrottler::RembSender remb_sender,
    NetworkStateEstimator* network_state_estimator)
    : clock_(*clock),
      remb_throttler_(std::move(remb_sender), clock),
      remote_estimator_proxy_(std::move(feedback_sender), network_state_estimator),
      rbe_(new RemoteBitrateEstimatorSingleStream(&remb_throttler_, clock)),
      using_absolute_send_time_(false),
      packets_since_absolute_send_time_(0) {}

功能:初始化所有组件,默认使用SingleStream算法

4.2 包处理入口

void ReceiveSideCongestionController::OnReceivedPacket(
    const RtpPacketReceived& packet, MediaType media_type) {
    bool has_transport_sequence_number = 
        packet.HasExtension<TransportSequenceNumber>() ||
        packet.HasExtension<TransportSequenceNumberV2>();
        
    if (media_type == MediaType::AUDIO && !has_transport_sequence_number) {
        // 音频流且无传输序列号,不支持接收端BWE
        return;
    }

    if (has_transport_sequence_number) {
        // 发送端BWE模式:转发包信息给远程估计代理
        remote_estimator_proxy_.IncomingPacket(packet);
    } else {
        // 接收端BWE模式:本地进行带宽估计
        MutexLock lock(&mutex_);
        PickEstimator(packet.HasExtension<AbsoluteSendTime>());
        rbe_->IncomingPacket(packet);
    }
}

4.3 算法选择器

void ReceiveSideCongestionController::PickEstimator(bool has_absolute_send_time) {
    if (has_absolute_send_time) {
        // 发现AST扩展头,立即切换到AST算法
        if (!using_absolute_send_time_) {
            RTC_LOG(LS_INFO) << "切换到绝对发送时间RBE算法";
            using_absolute_send_time_ = true;
            rbe_ = std::make_unique<RemoteBitrateEstimatorAbsSendTime>(
                &remb_throttler_, &clock_);
        }
        packets_since_absolute_send_time_ = 0;
    } else {
        // 没有AST扩展头,等待一定包数后切回TOF算法
        if (using_absolute_send_time_) {
            ++packets_since_absolute_send_time_;
            if (packets_since_absolute_send_time_ >= kTimeOffsetSwitchThreshold) {
                RTC_LOG(LS_INFO) << "切换到传输时间偏移RBE算法";
                using_absolute_send_time_ = false;
                rbe_ = std::make_unique<RemoteBitrateEstimatorSingleStream>(
                    &remb_throttler_, &clock_);
            }
        }
    }
}

4.4 周期处理

TimeDelta ReceiveSideCongestionController::MaybeProcess() {
    Timestamp now = clock_.CurrentTime();
    mutex_.Lock();
    TimeDelta time_until_rbe = rbe_->Process();           // 处理接收端BWE
    mutex_.Unlock();
    TimeDelta time_until_rep = remote_estimator_proxy_.Process(now); // 处理发送端BWE反馈
    TimeDelta time_until = std::min(time_until_rbe, time_until_rep);
    return std::max(time_until, TimeDelta::Zero());       // 返回下次处理时间
}

五. 设计亮点

5.1 智能算法切换

// 基于数据包特征自动选择最优算法
// AST算法优先,在没有AST时回退到TOF算法
// 切换阈值kTimeOffsetSwitchThreshold=30包,避免频繁切换

算法原理图:

5.2 双模式支持

// 统一处理发送端BWE和接收端BWE
// 根据TransportSequenceNumber存在性自动路由
// 音频流特殊处理:仅支持发送端BWE

算法原理图

5.3 线程安全设计

// 使用Mutex保护共享状态
// RTC_GUARDED_BY(mutex_)注解明确线程约束
// 细粒度锁:仅保护接收端BWE相关状态

六. 典型工作流程

6.1 视频流处理(接收端BWE)

1. 收到视频RTP包 → 检查扩展头
2. 有AbsoluteSendTime → 选择AST算法
3. 调用rbe_->IncomingPacket()进行本地估计
4. 定期MaybeProcess()生成REMB反馈
5. 通过remb_throttler_发送码率限制

6.2 音频流处理

1. 收到音频RTP包
2. 必须有TransportSequenceNumber,否则跳过
3. 仅支持发送端BWE模式

这个设计体现了WebRTC拥塞控制的核心理念:灵活性自适应性,能够根据网络条件和流类型自动选择最优的带宽估计策略。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值