WebRTC PCC (Performance-oriented Congestion Control) 算法精解

一、架构总览

PccNetworkControllerFactory (工厂,创建控制器实例)

└── PccNetworkController (主控制器,驱动状态机)

├── PccMonitorInterval (监测区间,采集丢包/时延/吞吐量)

├── RttTracker (RTT 跟踪器,EWMA 平滑)

└── PccBitrateController (码率控制器,梯度上升更新速率)

└── ModifiedVivaceUtilityFunction (效用函数,将性能指标映射为数值)


二、算法原理概述

PCC Vivace 是基于在线凸优化(机器学习)的拥塞控制算法:

  1. 将时间分割为连续的 Monitor Interval (MI)
  2. 在每个 MI 中分别以速率 r(1+ε)r(1-ε) 探测发送
  3. MI 结束后,用丢包率、时延梯度、吞吐量计算效用函数 U
  4. 通过梯度上升法调整发送速率以最大化 U

状态转移图:

kStartup ──(500ms到期)──> kSlowStart ──(utility下降)──> kOnlineLearning

│ │

└───(超时)───> kOnlineLearning │

kDoubleCheck <─┘─(低速率高丢包异常)

└──(验证完毕)──> kOnlineLearning

三、RttTracker --- RTT 跟踪器

rtt_tracker.h

cpp 复制代码
namespace webrtc {

namespace pcc {

class RttTracker {

public:
// initial_rtt: 初始RTT估计值, alpha: EWMA中新样本权重(越大越信任新值)
RttTracker(TimeDelta initial_rtt, double alpha);
// 收到包反馈时更新RTT估计
void OnPacketsFeedback(const std::vector<PacketResult>& packet_feedbacks,
Timestamp feedback_received_time);
// 返回当前平滑后的RTT估计
TimeDelta GetRtt() const;

private:
TimeDelta rtt_estimate_; // 当前EWMA平滑后的RTT估计值
double alpha_; // EWMA权重: 新样本占比(默认0.9, 高度信任最新测量)
};

} // namespace pcc
} // namespace webrtc

rtt_tracker.cc

cpp 复制代码
namespace webrtc {

namespace pcc {
// 构造函数: 用初始RTT和alpha初始化
RttTracker::RttTracker(TimeDelta initial_rtt, double alpha)
: rtt_estimate_(initial_rtt), // 初始RTT估计, 默认200ms
alpha_(alpha) {} // EWMA权重, 默认0.9

void RttTracker::OnPacketsFeedback(
const std::vector<PacketResult>& packet_feedbacks,
Timestamp feedback_received_time) { // feedback_received_time: 反馈到达本端的时间戳
TimeDelta packet_rtt = TimeDelta::MinusInfinity(); // 初始化为负无穷, 用于取最大值

for (const PacketResult& packet_result : packet_feedbacks) { // 遍历本批反馈中的所有包
if (!packet_result.IsReceived()) // 跳过未收到(丢失)的包
continue;
packet_rtt = std::max<TimeDelta>( // 取本批所有包中的最大RTT
packet_rtt,
feedback_received_time - // RTT = 反馈到达时间 - 包发送时间
packet_result.sent_packet.send_time); // (从发送端视角的端到端往返时延)
}

if (packet_rtt.IsFinite()) // 有有效RTT样本时才更新
// EWMA平滑: rtt = (1-0.9)*旧rtt + 0.9*新rtt
// alpha=0.9 意味着高度信任最新测量, 快速跟踪RTT变化
rtt_estimate_ = (1 - alpha_) * rtt_estimate_ + alpha_ * packet_rtt;
}

TimeDelta RttTracker::GetRtt() const {
return rtt_estimate_; // 返回当前平滑后的RTT
}

} // namespace pcc
} // namespace webrtc

四、PccMonitorInterval --- 监测区间

monitor_interval.h

cpp 复制代码
namespace webrtc {
namespace pcc {
// PCC将时间分割为连续的监测区间, 用来测试以某个速率发送的后果
class PccMonitorInterval {

public:
// target_sending_rate: 本区间的目标发送速率
// start_time: 区间开始时间(不包含在区间内)
// duration: 区间持续时长
PccMonitorInterval(DataRate target_sending_rate,
Timestamp start_time,
TimeDelta duration);
~PccMonitorInterval();
PccMonitorInterval(const PccMonitorInterval& other); 
// 接收包反馈, 分类为已收到/丢失, 并判断区间反馈是否收集完毕
void OnPacketsFeedback(const std::vector<PacketResult>& packets_results);
// 返回true表示已收集到区间内所有包的反馈
// 判断标准: 收到了第一个发送时间超出区间结束时间的包的反馈
bool IsFeedbackCollectionDone() const;
// 返回区间结束时间 = start_time + duration
Timestamp GetEndTime() const;
// 计算本区间丢包率 = 丢失包数 / (丢失+收到)
double GetLossRate() const;
// 用线性回归估算时延梯度(时延随发送时间的变化斜率)
double ComputeDelayGradient(double delay_gradient_threshold) const;
// 返回本区间的目标发送速率
DataRate GetTargetSendingRate() const;
// 计算接收端的实际吞吐量
DataRate GetTransmittedPacketsRate() const;

private:

struct ReceivedPacket {
TimeDelta delay; // 单向时延 = receive_time - send_time
Timestamp sent_time; // 包的发送时间
};

DataRate target_sending_rate_; // 本区间的目标发送速率
Timestamp start_time_; // 区间开始时间(该时刻的包不算在内)
TimeDelta interval_duration_; // 区间持续时长
std::vector<ReceivedPacket> received_packets_; // 已收到的包列表
std::vector<Timestamp> lost_packets_sent_time_; // 丢失包的发送时间列表
DataSize received_packets_size_; // 已收到包的总字节数
bool feedback_collection_done_; // 反馈收集是否完成的标志

};
} // namespace pcc
} // namespace webrtc

monitor_interval.cc

cpp 复制代码
namespace webrtc {

namespace pcc {

// 构造函数: 初始化区间参数
PccMonitorInterval::PccMonitorInterval(DataRate target_sending_rate,
                                       Timestamp start_time,
                                       TimeDelta duration)
    : target_sending_rate_(target_sending_rate),  // 本区间的目标发送速率
      start_time_(start_time),                    // 区间起始时间
      interval_duration_(duration),               // 区间持续时长
      received_packets_size_(DataSize::Zero()),  // 已接收字节数归零
      feedback_collection_done_(false) {}        // 反馈收集尚未完成
PccMonitorInterval::~PccMonitorInterval() = default;
PccMonitorInterval::PccMonitorInterval(const PccMonitorInterval& other) =
    default;

// 核心: 处理包反馈, 将包归类到本区间
void PccMonitorInterval::OnPacketsFeedback(
    const std::vector<PacketResult>& packets_results) {
  for (const PacketResult& packet_result : packets_results) {  // 遍历所有反馈包
    if (packet_result.sent_packet.send_time <= start_time_) {
      continue;  // 包在本区间开始之前发送, 不属于本区间, 跳过
    }

    // 如果包的发送时间超过区间结束时间(start + duration)
    // 说明区间内所有包都已收到反馈, 标记完成
    if (packet_result.sent_packet.send_time >
        start_time_ + interval_duration_) {
      feedback_collection_done_ = true;  // 区间反馈收集完毕
      return;  // 后续包不属于本区间, 直接返回
    }

    // 包属于本区间, 根据是否收到分类处理
    if (!packet_result.IsReceived()) {
      // 未收到 = 丢失, 记录其发送时间
      lost_packets_sent_time_.push_back(packet_result.sent_packet.send_time);
    } else {
      // 已收到, 记录{单向时延, 发送时间}, 累加字节数
      received_packets_.push_back(
          {packet_result.receive_time - packet_result.sent_packet.send_time,
           // 单向时延 = 接收时间 - 发送时间
           packet_result.sent_packet.send_time});
      // 记录发送时间(用于后续线性回归)
      received_packets_size_ += packet_result.sent_packet.size;
      // 累加接收字节数(用于计算吞吐量)
    }
  }
}

// ═══════════════════════════════════════════════════
// 时延梯度计算 --- 最小二乘法线性回归
//
// 数学原理: 给定 (t_i, d_i), t_i=发送时间, d_i=单向时延
// 斜率 = Σ(t̄_i · d_i) / Σ(t̄_i²)
// 其中 t̄_i = t_i - mean(t) (中心化)
//
// 参考:
// https://www.johndcook.com/blog/2008/10/20/comparing-two-ways-to-fit-a-line-to-data/
// ═══════════════════════════════════════════════════
double PccMonitorInterval::ComputeDelayGradient(
    double delay_gradient_threshold) const {
  // 边界条件: 无包 或 所有包同时发送 → 梯度为0
  if (received_packets_.empty() || received_packets_.front().sent_time ==
                                       received_packets_.back().sent_time) {
    return 0;
  }

  // ---- 第一遍遍历: 计算发送时间之和, 用于求均值 ----
  double sum_times = 0;
  for (const ReceivedPacket& packet : received_packets_) {
    double time_delta_us =
        (packet.sent_time - received_packets_[0].sent_time).us();
    // 相对于首包的发送时间偏移(微秒)
    sum_times += time_delta_us;  // 累加所有偏移量
  }

  // ---- 第二遍遍历: 计算回归分子和分母 ----
  double sum_squared_scaled_time_deltas = 0;   // 分母: Σ(t̄²)
  double sum_scaled_time_delta_dot_delay = 0;  // 分子: Σ(t̄ · d)

  for (const ReceivedPacket& packet : received_packets_) {
    double time_delta_us =
        (packet.sent_time - received_packets_[0].sent_time).us();
    // 相对于首包的发送时间偏移
    double delay = packet.delay.us();
    // 该包的单向时延(微秒)
    double scaled_time_delta_us =
        time_delta_us - sum_times / received_packets_.size();
    // 中心化: t̄ = t - mean(t), 消除偏移使回归更稳定
    sum_squared_scaled_time_deltas +=
        scaled_time_delta_us * scaled_time_delta_us;
    // 累加 t̄² (分母)
    sum_scaled_time_delta_dot_delay += scaled_time_delta_us * delay;
    // 累加 t̄ × d (分子)
  }

  // 斜率 = Σ(t̄·d) / Σ(t̄²) --- 线性回归的标准公式
  double rtt_gradient =
      sum_scaled_time_delta_dot_delay / sum_squared_scaled_time_deltas;
  // 噪声过滤: |gradient| < 阈值(默认0.01)时视为0, 避免噪声干扰决策
  if (std::abs(rtt_gradient) < delay_gradient_threshold)
    rtt_gradient = 0;
  // gradient > 0: 时延在增长(队列积累, 拥塞加重)
  // gradient < 0: 时延在减少(队列排空, 拥塞缓解)
  // gradient = 0: 时延稳定
  return rtt_gradient;
}

// 区间反馈是否收集完毕
bool PccMonitorInterval::IsFeedbackCollectionDone() const {
  return feedback_collection_done_;
}

// 区间结束时间 = 开始时间 + 持续时长
Timestamp PccMonitorInterval::GetEndTime() const {
  return start_time_ + interval_duration_;
}

// 丢包率 = 丢失包数 / 总包数(丢失+收到)
double PccMonitorInterval::GetLossRate() const {
  size_t packets_lost = lost_packets_sent_time_.size();  // 丢失包数量
  size_t packets_received = received_packets_.size();    // 收到包数量

  if (packets_lost == 0)
    return 0;  // 无丢包, 直接返回0
  return static_cast<double>(packets_lost) / (packets_lost + packets_received);
}
// 返回本区间的目标发送速率
DataRate PccMonitorInterval::GetTargetSendingRate() const {
  return target_sending_rate_;
}

// 计算接收端的实际吞吐量(接收侧视角)
DataRate PccMonitorInterval::GetTransmittedPacketsRate() const {
  if (received_packets_.empty()) {
    return target_sending_rate_;  // 无收到包时, 回退到目标速率
  }

  // 重建接收端时间戳: receive_time = send_time + one_way_delay
  Timestamp receive_time_of_first_packet =
      received_packets_.front().sent_time + received_packets_.front().delay;
  Timestamp receive_time_of_last_packet =
      received_packets_.back().sent_time + received_packets_.back().delay;

  if (receive_time_of_first_packet == receive_time_of_last_packet) {
    RTC_LOG(LS_WARNING) << "区间内所有包在同一时刻接收";  // 无法计算吞吐量
    return target_sending_rate_;
  }

  // 吞吐量 = 总接收字节数 / (末包接收时刻 - 首包接收时刻)
  return received_packets_size_ /
         (receive_time_of_last_packet - receive_time_of_first_packet);
}
}  // namespace pcc
}  // namespace webrtc

五、Utility Function --- 效用函数

utility_function.h

cpp 复制代码
namespace webrtc {

namespace pcc {

// 效用函数接口: 将一个监测区间的性能统计(速率/丢包/时延)映射为数值
// 论文: https://www.usenix.org/conference/nsdi18/presentation/dong
class PccUtilityFunctionInterface {
 public:
  virtual double Compute(const PccMonitorInterval& monitor_interval) const = 0;
  virtual ~PccUtilityFunctionInterface() = default;
};

// 原始Vivace效用函数
// 论文: "PCC Vivace: Online-Learning Congestion Control", Mo Dong et al.
class VivaceUtilityFunction : public PccUtilityFunctionInterface {
 public:
  // delay_gradient_coefficient: 时延梯度惩罚系数 δ
  // loss_coefficient: 丢包惩罚系数 λ
  // throughput_coefficient: 吞吐量奖励系数 σ
  // throughput_power: 吞吐量指数 t (<1 保证凹性)
  // delay_gradient_threshold: 梯度噪声过滤阈值
  // delay_gradient_negative_bound: 负梯度截断值(防止过度奖励时延下降)
  VivaceUtilityFunction(double delay_gradient_coefficient,

                        double loss_coefficient,

                        double throughput_coefficient,

                        double throughput_power,

                        double delay_gradient_threshold,

                        double delay_gradient_negative_bound);

  double Compute(const PccMonitorInterval& monitor_interval) const override;
  ~VivaceUtilityFunction() override;

 private:
  const double delay_gradient_coefficient_;  // δ = 0.005
  const double loss_coefficient_;  // λ = 10
  const double throughput_power_;  // t = 0.9
  const double throughput_coefficient_;  // σ = 0.001
  const double delay_gradient_threshold_;  // 噪声阈值 = 0.01
  const double delay_gradient_negative_bound_;  // 负截断 = 0.1
};

// Modified Vivace效用函数(WebRTC默认使用)
// 与原始版本的核心区别: 每一项都额外乘以发送速率r
// 效果: 梯度(dU/dr)与r成正比, 高速率时步长自然更大, 收敛更快
class ModifiedVivaceUtilityFunction : public PccUtilityFunctionInterface {
 public:
  ModifiedVivaceUtilityFunction(double delay_gradient_coefficient,
                                double loss_coefficient,
                                double throughput_coefficient,
                                double throughput_power
                                double delay_gradient_threshold,
                                double delay_gradient_negative_bound);

  double Compute(const PccMonitorInterval& monitor_interval) const override;
  ~ModifiedVivaceUtilityFunction() override;

 private:
  const double delay_gradient_coefficient_;  // δ = 0.005
  const double loss_coefficient_;  // λ = 10
  const double throughput_power_;  // t = 0.9
  const double throughput_coefficient_;  // σ = 0.001
  const double delay_gradient_threshold_;  // 噪声阈值 = 0.01
  const double delay_gradient_negative_bound_;  // 负截断 = 0.1
};

}  // namespace pcc

}  // namespace webrtc

utility_function.cc

cpp 复制代码
namespace webrtc {
namespace pcc {
// ═══════════════════════════════════════════════════
// 原始 Vivace 效用函数
//
// 公式: U = σ·r^t - δ·r·g - λ·r·L
//
// σ·r^t = 吞吐量奖励 (t<1 保证凹性, 防止速率无限增长)
// δ·r·g = 时延梯度惩罚 (g>0 = 队列增长 → 扣分)
// λ·r·L = 丢包率惩罚 (L越大扣分越多)
// ═══════════════════════════════════════════════════
VivaceUtilityFunction::VivaceUtilityFunction(
    double delay_gradient_coefficient,  // δ
    double loss_coefficient,  // λ
    double throughput_coefficient,  // σ
    double throughput_power,  // t
    double delay_gradient_threshold,  // 噪声过滤阈值
    double delay_gradient_negative_bound)  // 负梯度截断值
    : delay_gradient_coefficient_(delay_gradient_coefficient),
      loss_coefficient_(loss_coefficient),
      throughput_power_(throughput_power),
      throughput_coefficient_(throughput_coefficient),
      delay_gradient_threshold_(delay_gradient_threshold),
      delay_gradient_negative_bound_(delay_gradient_negative_bound) {
  RTC_DCHECK_GE(delay_gradient_negative_bound_, 0);
  // 负截断值必须 >= 0
}

double VivaceUtilityFunction::Compute(

    const PccMonitorInterval& monitor_interval) const {
  RTC_DCHECK(monitor_interval.IsFeedbackCollectionDone());

  // 断言: 只有在反馈收集完毕后才能计算效用
  double bitrate = monitor_interval.GetTargetSendingRate().bps();
  //本区间的目标发送速率 r (bps)
  double loss_rate = monitor_interval.GetLossRate();
  //本区间丢包率 L
  double rtt_gradient =
      monitor_interval.ComputeDelayGradient(delay_gradient_threshold_);
  //用线性回归计算时延梯度 g (|g|<0.01时视为0)
  rtt_gradient = std::max(rtt_gradient, -delay_gradient_negative_bound_);
  // 截断负梯度: g = max(g, -0.1)
  // 防止时延下降时给予过多奖励(最多奖励到 -0.1 为止)
  // U = σ·r^t - δ·r·g - λ·r·L
  return (throughput_coefficient_ * std::pow(bitrate, throughput_power_)) -
         //第一项: σ·r^t = 0.001 × r^0.9 (吞吐量奖励)
         (delay_gradient_coefficient_ * bitrate * rtt_gradient) -
         //第二项: δ·r·g = 0.005 × r × g (时延梯度惩罚)
         (loss_coefficient_ * bitrate * loss_rate);
  //第三项: λ·r·L = 10 × r × L (丢包惩罚)
}

VivaceUtilityFunction::~VivaceUtilityFunction() = default;
// ═══════════════════════════════════════════════════
// Modified Vivace 效用函数 (WebRTC 默认使用)
//
// 公式: U = σ·r^t·r - δ·r²·g - λ·r²·L
// = σ·r^(t+1) - δ·r²·g - λ·r²·L
//
// 与原始版本区别: 每项额外乘以 r
// 效果: dU/dr 与 r 成正比 → 高速率自然用大步长, 低速率用小步长
// ═══════════════════════════════════════════════════

ModifiedVivaceUtilityFunction::ModifiedVivaceUtilityFunction(

    double delay_gradient_coefficient,

    double loss_coefficient,

    double throughput_coefficient,

    double throughput_power,

    double delay_gradient_threshold,

    double delay_gradient_negative_bound)

    : delay_gradient_coefficient_(delay_gradient_coefficient),

      loss_coefficient_(loss_coefficient),

      throughput_power_(throughput_power),

      throughput_coefficient_(throughput_coefficient),

      delay_gradient_threshold_(delay_gradient_threshold),

      delay_gradient_negative_bound_(delay_gradient_negative_bound) {
  RTC_DCHECK_GE(delay_gradient_negative_bound_, 0);
}

double ModifiedVivaceUtilityFunction::Compute(

    const PccMonitorInterval& monitor_interval) const {
  RTC_DCHECK(monitor_interval.IsFeedbackCollectionDone());
  double bitrate = monitor_interval.GetTargetSendingRate().bps();
  //目标发送速率 r (bps)
  double loss_rate = monitor_interval.GetLossRate();
  //丢包率 L
  double rtt_gradient =
      monitor_interval.ComputeDelayGradient(delay_gradient_threshold_);
  //时延梯度 g
  rtt_gradient = std::max(rtt_gradient, -delay_gradient_negative_bound_);

  //截断负梯度: g = max(g, -0.1)
  //U = σ·r^t·r - δ·r²·g - λ·r²·L
  //带入默认参数: U = 0.001·r^1.9 - 0.005·r²·g - 10·r²·L

  return (throughput_coefficient_ * std::pow(bitrate, throughput_power_) *
          bitrate) -
         //第一项: σ·r^t·r = 0.001 × r^0.9 × r = 0.001 × r^1.9
         (delay_gradient_coefficient_ * bitrate * bitrate * rtt_gradient) -
         //第二项: δ·r²·g = 0.005 × r² × g
         (loss_coefficient_ * bitrate * bitrate * loss_rate);
  //第三项: λ·r²·L = 10 × r² × L
}

ModifiedVivaceUtilityFunction::~ModifiedVivaceUtilityFunction() = default;

}  // namespace pcc

}  // namespace webrtc

六、PccBitrateController --- 码率控制器

bitrate_controller.h

cpp 复制代码
namespace webrtc {

namespace pcc {

class PccBitrateController {
 public:
  // 构造函数1: 传入效用函数参数, 内部创建 ModifiedVivaceUtilityFunction
  PccBitrateController(
      double initial_conversion_factor,  // 步长转换因子(默认5)
      double initial_dynamic_boundary,  // 动态边界初始值(默认0.1=10%)
      double dynamic_boundary_increment,  // 边界每次增量(默认0.1=10%)
      double rtt_gradient_coefficient,  // δ
      double loss_coefficient,  // λ
      double throughput_coefficient,  // σ
      double throughput_power,  // t
      double rtt_gradient_threshold,  // 梯度噪声阈值
      double delay_gradient_negative_bound);  // 负梯度截断
  // 构造函数2: 直接传入自定义效用函数

  PccBitrateController(
      double initial_conversion_factor,
      double initial_dynamic_boundary,
      double dynamic_boundary_increment,
      std::unique_ptr<PccUtilityFunctionInterface> utility_function);
  // 慢启动模式: 比较前后两轮效用, 效用增长则采纳新速率, 否则返回nullopt
  absl::optional<DataRate> ComputeRateUpdateForSlowStartMode(
      const PccMonitorInterval& monitor_interval);
  // 在线学习模式: 两点梯度计算 + 步长 + 动态边界 → 输出新速率
  DataRate ComputeRateUpdateForOnlineLearningMode(
      const std::vector<PccMonitorInterval>& block,
      DataRate bandwidth_estimate);
  ~PccBitrateController();

 private:
  // 将速率变化量限制在动态边界范围内
  double ApplyDynamicBoundary(double rate_change, double bitrate);
  // 根据梯度方向的连续性计算自适应步长
  double ComputeStepSize(double utility_gradient);
  int64_t consecutive_boundary_adjustments_number_;  // 连续同向边界调整次数
  const double initial_dynamic_boundary_;  // 边界初始值 0.1
  const double dynamic_boundary_increment_;  // 边界增量 0.1
  const std::unique_ptr<PccUtilityFunctionInterface> utility_function_;
  int64_t step_size_adjustments_number_;  // 连续同向步长调整计数(正=增, 负=减)
  const double initial_conversion_factor_;  // 步长基础转换因子 = 5
  absl::optional<double> previous_utility_;  // 上一轮效用值(慢启动用)
};
}  // namespace pcc
}  // namespace webrtc

bitrate_controller.cc

cpp 复制代码
namespace webrtc {

namespace pcc {
// 构造函数1: 内部创建 ModifiedVivace 效用函数, 委托给构造函数2

PccBitrateController::PccBitrateController(double initial_conversion_factor,
                                           double initial_dynamic_boundary,
                                           double dynamic_boundary_increment,
                                           double rtt_gradient_coefficient,
                                           double loss_coefficient,
                                           double throughput_coefficient,
                                           double throughput_power,
                                           double rtt_gradient_threshold,
                                           double delay_gradient_negative_bound)
    : PccBitrateController(initial_conversion_factor,
                           initial_dynamic_boundary,
                           dynamic_boundary_increment,
                           std::make_unique<ModifiedVivaceUtilityFunction>(
                               //默认使用Modified Vivace(非原始Vivace)
                               rtt_gradient_coefficient,
                               loss_coefficient,
                               throughput_coefficient,
                               throughput_power,
                               rtt_gradient_threshold,
                               delay_gradient_negative_bound)) {}

// 构造函数2: 直接接受效用函数对象

PccBitrateController::PccBitrateController(
    double initial_conversion_factor,
    double initial_dynamic_boundary,
    double dynamic_boundary_increment,
    std::unique_ptr<PccUtilityFunctionInterface> utility_function)
    : consecutive_boundary_adjustments_number_(0),  // 边界调整计数归零
      initial_dynamic_boundary_(initial_dynamic_boundary),  // 0.1
      dynamic_boundary_increment_(dynamic_boundary_increment),  // 0.1
      utility_function_(std::move(utility_function)),
      step_size_adjustments_number_(0),  // 步长调整计数归零
      initial_conversion_factor_(initial_conversion_factor) {}  // 5

PccBitrateController::~PccBitrateController() = default;

// ═══════════════════════════════════════════════════
// 自适应步长计算
//
// 原理: 连续多次梯度同向 → 远离最优点 → 逐步加大步长
// 方向切换时 → 步长回归最小
//
// 步长放大器规则:
// |n|=1: amp=1, |n|=2: amp=2, |n|=3: amp=3
// |n|>3: amp=2|n|-3 (加速增长)
//
// 最终步长 = amp × initial_conversion_factor(5)
// ═══════════════════════════════════════════════════

double PccBitrateController::ComputeStepSize(double utility_gradient) {
  // --- 更新连续同向计数 ---
  if (utility_gradient > 0) {
    step_size_adjustments_number_ =
        std::max<int64_t>(step_size_adjustments_number_ + 1, 1);
    // 梯度为正: 计数+1, 若之前为负则重置为+1(至少为1)
  } else if (utility_gradient < 0) {
    step_size_adjustments_number_ =
        std::min<int64_t>(step_size_adjustments_number_ - 1, -1);
    //梯度为负: 计数-1, 若之前为正则重置为-1(最大为-1)
  } else {
    step_size_adjustments_number_ = 0;
    //梯度为0: 计数清零
  }

  // --- 计算步长放大器 ---
  int64_t step_size_amplifier = 1;  // 默认放大器=1
  if (std::abs(step_size_adjustments_number_) <= 3) {
    // 连续 ≤3 次: 放大器 = |count| (线性增长: 1,2,3)
    step_size_amplifier =
        std::max<int64_t>(std::abs(step_size_adjustments_number_), 1);
  } else {
    // 连续 >3 次: 放大器 = 2|count|-3 (加速增长: 5,7,9,...)
    step_size_amplifier = 2 * std::abs(step_size_adjustments_number_) - 3;
  }
  // 最终步长 = 放大器 × 基础因子(5)
  return step_size_amplifier * initial_conversion_factor_;
}

// ═══════════════════════════════════════════════════
// 动态边界 --- 防止速率震荡的安全阀
//
// 初始边界 = 10% × bitrate
// 每次被截断: 边界扩大10% (允许更大的调整)
// 方向切换时: 重置为最小边界
// ═══════════════════════════════════════════════════

double PccBitrateController::ApplyDynamicBoundary(double rate_change,
                                                  double bitrate) {
  double rate_change_abs = std::abs(rate_change);
  //变化量的绝对值
  int64_t rate_change_sign = (rate_change > 0) ? 1 : -1;

  //变化方向: +1=升速, -1=降速
  if (consecutive_boundary_adjustments_number_ * rate_change_sign < 0) {
    consecutive_boundary_adjustments_number_ = 0;
    //方向切换(上次升速这次降速, 或反之): 重置边界计数
  }

  // 当前动态边界 = (0.1 + |count|×0.1) × bitrate
  // count=0: 边界 = 10% × bitrate
  // count=1: 边界 = 20% × bitrate
  // count=n: 边界 = (n+1)×10% × bitrate
  double dynamic_change_boundary =
      initial_dynamic_boundary_ +
      std::abs(consecutive_boundary_adjustments_number_) *
          dynamic_boundary_increment_;
  double boundary = bitrate * dynamic_change_boundary;

  //绝对值边界 (bps)
  if (rate_change_abs > boundary) {
    // 变化量超出边界 → 截断为边界值
    consecutive_boundary_adjustments_number_ += rate_change_sign;
    //计数+1, 下次允许更大的变化
    return boundary * rate_change_sign;
    //返回截断后的值(保持方向)
  }
  // 变化量未超出边界 → 收缩边界到刚好能容纳此变化量的最小值
  while (rate_change_abs <= boundary &&
         consecutive_boundary_adjustments_number_ * rate_change_sign > 0) {
    //只要变化量仍小于边界 且 还能收缩, 就继续收缩
    consecutive_boundary_adjustments_number_ -= rate_change_sign;
    // 边界计数-1, 缩小边界
    dynamic_change_boundary =
        initial_dynamic_boundary_ +
        std::abs(consecutive_boundary_adjustments_number_) *
            dynamic_boundary_increment_;
    boundary = bitrate * dynamic_change_boundary;
    //重新计算缩小后的边界
  }
  consecutive_boundary_adjustments_number_ += rate_change_sign;
  //最后+1确保当前变化量刚好在边界内
  return rate_change;
  //返回原始变化量(未截断)
}

// ═══════════════════════════════════════════════════
// 慢启动模式更新
//
// 每轮以 1.5x 速率发送, 计算效用:
// 效用增长 → 采纳新速率, 继续慢启动
// 效用不增长 → 返回nullopt, 触发退出慢启动
// ═══════════════════════════════════════════════════

absl::optional<DataRate>

PccBitrateController::ComputeRateUpdateForSlowStartMode(
    const PccMonitorInterval& monitor_interval) {
  double utility_value = utility_function_->Compute(monitor_interval);
  //计算本区间的效用值 U
  if (previous_utility_.has_value() && utility_value <= previous_utility_) {
    return absl::nullopt;
    //有前值 且 效用没增长 → 返回空(触发调用方退出慢启动)
  }
  previous_utility_ = utility_value;
  // 记录当前效用作为下一轮的参考
  return monitor_interval.GetTargetSendingRate();
  //效用在增长, 返回本区间速率作为新的带宽估计
}

// ═══════════════════════════════════════════════════
// 在线学习模式更新 --- 梯度上升法
//
// 输入: intervals[0]的速率为 r(1+ε) 或 r(1-ε)
// intervals[1]的速率为 r(1-ε) 或 r(1+ε)
// 计算: 梯度 = (U₁ - U₂) / (r₁ - r₂)
// Δr = 梯度 × 步长
// Δr = ApplyDynamicBoundary(Δr)
// new_r = max(0, old_r + Δr)
// ═══════════════════════════════════════════════════

DataRate PccBitrateController::ComputeRateUpdateForOnlineLearningMode(
    const std::vector<PccMonitorInterval>& intervals,
    DataRate bandwith_estimate) {
  double first_utility = utility_function_->Compute(intervals[0]);
  //计算第一个MI的效用值 U(r₁)
  double second_utility = utility_function_->Compute(intervals[1]);
  //计算第二个MI的效用值 U(r₂)
  double first_bitrate_bps = intervals[0].GetTargetSendingRate().bps();
  //第一个MI的目标速率 r₁
  double second_bitrate_bps = intervals[1].GetTargetSendingRate().bps();
  // 第二个MI的目标速率 r₂
  double gradient = (first_utility - second_utility) /
                    (first_bitrate_bps - second_bitrate_bps);
  //核心数值梯度: ∇U = [U(r₁)-U(r₂)] / [r₁-r₂]
  // 这就是两点法估算dU/dr的核心公式
  double rate_change_bps = gradient * ComputeStepSize(gradient);
  // 速率变化量 Δr = 梯度 × 自适应步长
  rate_change_bps =
      ApplyDynamicBoundary(rate_change_bps, bandwith_estimate.bps());
  //应用动态边界约束, 防止变化过大
  return DataRate::BitsPerSec(
      std::max(0.0, bandwith_estimate.bps() + rate_change_bps));
  //新速率 = max(0, 当前估计 + Δr), 保证不为负
}
}  // namespace pcc
}  // namespace webrtc

七、PccNetworkController --- 主控制器

pcc_network_controller.h

cpp 复制代码
namespace webrtc {

namespace pcc {

// PCC Vivace: 基于在线凸优化的拥塞控制算法
// 将时间分割为连续MI, 以 r(1+ε) 和 r(1-ε) 测试当前速率r
// 每个MI结束后计算效用函数, 再用梯度上升法更新速率以最大化效用
class PccNetworkController : public NetworkControllerInterface {
 public:
  enum class Mode {
    kStartup,  // 启动阶段: 前500ms, 用初始速率探测
    kSlowStart,  // 慢启动: 每轮速率×1.5, 直到效用不再增长
    kOnlineLearning,  // 在线学习: 两点梯度探测 + 梯度上升
    kDoubleCheck  // 双重验证: 低速率高丢包时重新测量
  };

  enum class MonitorIntervalLengthStrategy {
    kAdaptive,  // 自适应: MI时长 = max(RTT × 比率, 发包间隔 × 包数)
    kFixed  // 固定(默认): MI时长 = 发包间隔 × 最小包数(20)
  };

  explicit PccNetworkController(NetworkControllerConfig config);

  ~PccNetworkController() override;
  // ---- NetworkControllerInterface 回调 ----
  NetworkControlUpdate OnNetworkAvailability(NetworkAvailability msg) override;
  NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange msg) override;
  NetworkControlUpdate OnProcessInterval(ProcessInterval msg) override;
  NetworkControlUpdate OnSentPacket(SentPacket msg) override;  // 发包回调(核心)
  NetworkControlUpdate OnTargetRateConstraints(
      TargetRateConstraints msg) override;
  NetworkControlUpdate OnTransportPacketsFeedback(
      TransportPacketsFeedback msg) override;  // 反馈回调(核心)

  // 以下接口PCC不使用, 返回空更新
  NetworkControlUpdate OnStreamsConfig(StreamsConfig msg) override;
  NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport msg) override;
  NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) override;
  NetworkControlUpdate OnTransportLossReport(TransportLossReport msg) override;
  NetworkControlUpdate OnReceivedPacket(ReceivedPacket msg) override;
  NetworkControlUpdate OnNetworkStateEstimate(
      NetworkStateEstimate msg) override;

 private:
  void UpdateSendingRateAndMode();  // 根据MI结果更新速率和模式
  NetworkControlUpdate CreateRateUpdate(
      Timestamp at_time) const;  // 生成速率更新消息
  TimeDelta ComputeMonitorIntervalsDuration() const;  // 计算MI持续时长
  bool NeedDoubleCheckMeasurments() const;  // 是否需要双重验证
  bool IsTimeoutExpired(Timestamp current_time) const;  // MI是否超时
  bool IsFeedbackCollectionDone() const;  // 所有MI反馈是否收集完毕
  Timestamp start_time_;  // 算法启动时间
  Timestamp last_sent_packet_time_;  // 上一个包的发送时间
  TimeDelta smoothed_packets_sending_interval_;  // EWMA平滑的发包间隔
  Mode mode_;  // 当前状态机模式
  DataRate default_bandwidth_;  // 默认带宽(用于初始化)
  DataRate bandwidth_estimate_;  // 当前带宽估计 r
  RttTracker rtt_tracker_;  // RTT跟踪器
  TimeDelta monitor_interval_timeout_;  // MI超时阈值 = RTT × 2
  const MonitorIntervalLengthStrategy
      monitor_interval_length_strategy_;  // MI长度策略(默认Fixed)
  const double monitor_interval_duration_ratio_;  // 自适应模式下 MI/RTT 比率
  const double sampling_step_;  // 采样步长 ε = 0.05
  const double monitor_interval_timeout_ratio_;  // 超时比率 = 2.0
  const int64_t min_packets_number_per_interval_;  // MI最少包数 = 20
  PccBitrateController bitrate_controller_;  // 码率控制器(梯度上升)
  std::vector<PccMonitorInterval> monitor_intervals_;  // 当前轮的MI列表
  std::vector<DataRate> monitor_intervals_bitrates_;  // 当前轮各MI的目标速率
  TimeDelta monitor_intervals_duration_;  // 当前MI持续时长
  size_t complete_feedback_monitor_interval_number_;  // 已完成反馈的MI数量
  webrtc::Random random_generator_;  // 随机数生成器(决定探测方向)
  std::deque<PacketResult>
      last_received_packets_;  // 最近收到的20个包(用于超时时估算接收速率)
};
}  // namespace pcc
}  // namespace webrtc

pcc_network_controller.cc

cpp 复制代码
namespace webrtc {

namespace pcc {

namespace {
// ═══════════════════════════════════════════════════
// 常量定义
// ═══════════════════════════════════════════════════
constexpr int64_t kInitialRttMs = 200;
// 初始RTT估计 = 200ms
constexpr int64_t kInitialBandwidthKbps = 300;
//初始带宽估计 = 300kbps
constexpr double kMonitorIntervalDurationRatio = 1;
//自适应MI策略下, MI时长 = RTT × 1.0
constexpr double kDefaultSamplingStep = 0.05;
//采样步长 ε = 5%, 探测速率 r(1±0.05)
constexpr double kTimeoutRatio = 2;
//超时阈值 = RTT × 2
constexpr double kAlphaForRtt = 0.9;
//RTT EWMA权重: 新样本占90%, 快速跟踪变化
constexpr double kSlowStartModeIncrease = 1.5;
//慢启动每轮速率翻1.5倍
constexpr double kAlphaForPacketInterval = 0.9;
//包发送间隔EWMA的新样本权重
constexpr int64_t kMinPacketsNumberPerInterval = 20;
//固定MI策略下, 每MI至少包含20个包
const TimeDelta kMinDurationOfMonitorInterval = TimeDelta::Millis(50);
// MI最小持续时间 = 50ms
const TimeDelta kStartupDuration = TimeDelta::Millis(500);
//Startup阶段持续时间 = 500ms
constexpr double kMinRateChangeBps = 4000;
//低速率时最小速率变化量 = 4kbps (加法探测)
constexpr DataRate kMinRateHaveMultiplicativeRateChange = DataRate::BitsPerSec(
    static_cast<int64_t>(kMinRateChangeBps / kDefaultSamplingStep));
// = 4000 / 0.05 = 80000 bps = 80kbps
// 超过80kbps使用乘法探测 r(1±ε), 否则用加法探测 r±4kbps
// ---- 码率控制器参数 ----
constexpr double kInitialConversionFactor = 5;
//步长基础转换因子
constexpr double kInitialDynamicBoundary = 0.1;
//动态边界初始值 = 当前速率的10%
constexpr double kDynamicBoundaryIncrement = 0.1;
//每次连续同向截断, 边界扩大10%
// ---- 效用函数参数 ----
constexpr double kRttGradientCoefficientBps = 0.005;
//δ: 时延梯度惩罚系数
constexpr double kLossCoefficientBps = 10;
//λ: 丢包惩罚系数
constexpr double kThroughputCoefficient = 0.001;
//σ: 吞吐量奖励系数
constexpr double kThroughputPower = 0.9;
// t: 吞吐量指数 (<1 保证凹性)
constexpr double kRttGradientThreshold = 0.01;
// 时延梯度噪声过滤阈值, |g|<0.01 视为0
constexpr double kDelayGradientNegativeBound = 0.1;
// 负梯度截断值, g = max(g, -0.1)
constexpr int64_t kNumberOfPacketsToKeep = 20;
// 保留最近20个收到的包(用于超时时估算接收速率)
const uint64_t kRandomSeed = 100;
// 随机数种子(决定探测方向正负)
}  // namespace

// ═══════════════════════════════════════════════════
// 构造函数: 初始化所有成员
// ═══════════════════════════════════════════════════
PccNetworkController::PccNetworkController(NetworkControllerConfig config)
    : start_time_(Timestamp::PlusInfinity()),
      //  正无穷表示尚未启动, 首次发包时会被设为实际时间
      last_sent_packet_time_(Timestamp::PlusInfinity()),
      //  正无穷表示尚无发包记录
      smoothed_packets_sending_interval_(TimeDelta::Zero()),
      //  发包间隔EWMA初始为0
      mode_(Mode::kStartup),
      //  初始模式: Startup
      default_bandwidth_(DataRate::KilobitsPerSec(kInitialBandwidthKbps)),
      // 默认带宽 = 300kbps
      bandwidth_estimate_(default_bandwidth_),
      // 当前带宽估计 = 300kbps
      rtt_tracker_(TimeDelta::Millis(kInitialRttMs), kAlphaForRtt),
      // RTT跟踪器: 初始RTT=200ms, alpha=0.9
      monitor_interval_timeout_(TimeDelta::Millis(kInitialRttMs) *
                                kTimeoutRatio),
      // 初始超时 = 200ms × 2 = 400ms
      monitor_interval_length_strategy_(MonitorIntervalLengthStrategy::kFixed),
      // MI长度策略: 固定(基于包数)
      monitor_interval_duration_ratio_(kMonitorIntervalDurationRatio),
      // 自适应模式下MI/RTT比率 = 1.0
      sampling_step_(kDefaultSamplingStep),
      // ε = 0.05
      monitor_interval_timeout_ratio_(kTimeoutRatio),
      // 超时比率 = 2.0
      min_packets_number_per_interval_(kMinPacketsNumberPerInterval),
      // MI最少包数 = 20
      bitrate_controller_(kInitialConversionFactor,
                          kInitialDynamicBoundary,
                          kDynamicBoundaryIncrement,
                          kRttGradientCoefficientBps,
                          kLossCoefficientBps,
                          kThroughputCoefficient,
                          kThroughputPower,
                          kRttGradientThreshold,
                          kDelayGradientNegativeBound),
      // 初始化码率控制器(内部创建 ModifiedVivace 效用函数)
      monitor_intervals_duration_(TimeDelta::Zero()),
      // MI持续时间初始为0
      complete_feedback_monitor_interval_number_(0),
      // 已完成反馈的MI数量 = 0
      random_generator_(kRandomSeed) {
  // 随机数生成器, 种子=100
  if (config.constraints.starting_rate) {
    default_bandwidth_ = *config.constraints.starting_rate;
    bandwidth_estimate_ = default_bandwidth_;
    // 如果配置中指定了初始速率, 覆盖默认300kbps
  }
}

PccNetworkController::~PccNetworkController() {}
// ═══════════════════════════════════════════════════
// 生成速率更新消息 --- 返回给编码器和Pacer
// ═══════════════════════════════════════════════════
NetworkControlUpdate PccNetworkController::CreateRateUpdate(
    Timestamp at_time) const {
  DataRate sending_rate = DataRate::Zero();
  if (monitor_intervals_.empty() ||
      (monitor_intervals_.size() >= monitor_intervals_bitrates_.size() &&
       at_time >= monitor_intervals_.back().GetEndTime())) {
    sending_rate = bandwidth_estimate_;
    // 无活跃MI 或 所有MI已结束: 使用当前带宽估计
  } else {
    sending_rate = monitor_intervals_.back().GetTargetSendingRate();

    // 有活跃MI: 使用最新MI的目标发送速率(可能是探测速率 r±ε)
  }

  NetworkControlUpdate update;
  // ---- 设置目标码率(给编码器) ----
  TargetTransferRate target_rate_msg;
  target_rate_msg.at_time = at_time;  // 时间戳
  target_rate_msg.network_estimate.at_time = at_time;
  target_rate_msg.network_estimate.round_trip_time = rtt_tracker_.GetRtt();
  // 附带当前RTT估计
  target_rate_msg.network_estimate.loss_rate_ratio = 0;
  // TODO: 暂未实现丢包率估计

  target_rate_msg.network_estimate.bwe_period =
      monitor_interval_duration_ratio_ * rtt_tracker_.GetRtt();
  // 带宽估计周期 = 1.0 × RTT
  target_rate_msg.target_rate = sending_rate;
  // 目标发送速率
  update.target_rate = target_rate_msg;
  // ---- 设置Pacing配置(给发包器) ----
  PacerConfig pacer_config;
  pacer_config.at_time = at_time;
  pacer_config.time_window = TimeDelta::Millis(1);
  // 1ms时间窗口
  pacer_config.data_window = sending_rate * pacer_config.time_window;
  // 1ms内允许发送的数据量 = rate × 1ms
  pacer_config.pad_window = sending_rate * pacer_config.time_window;
  // padding也使用相同速率
  update.pacer_config = pacer_config;
  return update;
}

// ═══════════════════════════════════════════════════

//OnSentPacket --- 发包回调(算法主驱动)
//
//
// 1. 首包初始化
// 2. 更新发包间隔EWMA
// 3. 启动新MI
// 4. 超时检测与处理
// 5. Startup→SlowStart 转换
// 6. 反馈收集完毕后创建下一轮MI
// ═══════════════════════════════════════════════════
NetworkControlUpdate PccNetworkController::OnSentPacket(SentPacket msg) {
  // ---- 1. 首包初始化 ----
  if (start_time_.IsInfinite()) {
    // 正无穷 = 尚未启动, 这是第一个包
    start_time_ = msg.send_time;
    // 记录算法启动时间
    monitor_intervals_duration_ = kStartupDuration;
    // Startup阶段MI时长 = 500ms
    monitor_intervals_bitrates_ = {bandwidth_estimate_};
    // Startup只有1个MI, 速率 = 初始带宽估计(300kbps)
    monitor_intervals_.emplace_back(bandwidth_estimate_, msg.send_time,
                                    monitor_intervals_duration_);
    // 创建第一个MI: 速率=300kbps, 开始=现在, 时长=500ms
    complete_feedback_monitor_interval_number_ = 0;
    // 已完成MI数量归零
  }
  // ---- 2. 更新发包间隔EWMA ----
  if (last_sent_packet_time_.IsFinite()) {
    //不是第一个包时才能计算间隔
    smoothed_packets_sending_interval_ =
        (msg.send_time - last_sent_packet_time_) * kAlphaForPacketInterval +
        (1 - kAlphaForPacketInterval) * smoothed_packets_sending_interval_;
    // EWMA: interval = 0.9×新间隔 + 0.1×旧平滑值
    // 用于计算MI时长(固定策略: interval × 20)
  }

  last_sent_packet_time_ = msg.send_time;
  //记录本包发送时间
  // ---- 3. 如果当前MI已结束且还有待启动的MI, 启动下一个 ----
  if (!monitor_intervals_.empty() &&
      msg.send_time >= monitor_intervals_.back().GetEndTime() &&
      //当前时间已过最后一个MI的结束时间
      monitor_intervals_bitrates_.size() > monitor_intervals_.size()) {
    // 还有预定的MI未启动(在线学习模式下有2个MI)
    monitor_intervals_.emplace_back(
        monitor_intervals_bitrates_[monitor_intervals_.size()],
        //使用下一个预定速率
        msg.send_time,
        // 从当前时间开始
        monitor_intervals_duration_);
    //使用相同的MI时长
  }
  // ---- 4. 超时检测与处理 ----
  if (IsTimeoutExpired(msg.send_time)) {
    //当前时间 - 未完成MI的结束时间 >= RTT×2 → 超时
    // 说明长时间没收到反馈, 网络可能严重拥塞
    // 用最近收到的20个包估算接收速率
    DataSize received_size = DataSize::Zero();
    for (size_t i = 1; i < last_received_packets_.size(); ++i) {
      received_size += last_received_packets_[i].sent_packet.size;
      // 从第2个包开始累加(第1个作为时间基准)
    }
    TimeDelta sending_time = TimeDelta::Zero();
    if (last_received_packets_.size() > 0)
      sending_time = last_received_packets_.back().receive_time -
                     last_received_packets_.front().receive_time;
    // 时间跨度 = 最后包接收时间 - 第一包接收时间
    DataRate receiving_rate = bandwidth_estimate_;
    if (sending_time > TimeDelta::Zero())
      receiving_rate = received_size / sending_time;
    // 接收速率 = 总字节 / 时间跨度
    bandwidth_estimate_ =
        std::min<DataRate>(bandwidth_estimate_ * 0.5, receiving_rate);
    //超时保守策略: 带宽 = min(当前×0.5, 接收速率)
    // 即: 至少减半, 且不超过实际接收速率
    if (mode_ == Mode::kSlowStart)
      mode_ = Mode::kOnlineLearning;
    //慢启动中超时: 直接跳到在线学习(跳过剩余慢启动)
  }

  // ---- 5. Startup结束 → 转入SlowStart ----
  if (mode_ == Mode::kStartup &&
      msg.send_time - start_time_ >= kStartupDuration) {
    //已过500ms, Startup阶段结束
    //用最近20个包估算接收速率(与超时处理逻辑相同)
    DataSize received_size = DataSize::Zero();
    for (size_t i = 1; i < last_received_packets_.size(); ++i) {
      received_size += last_received_packets_[i].sent_packet.size;
    }
    TimeDelta sending_time = TimeDelta::Zero();
    if (last_received_packets_.size() > 0)
      sending_time = last_received_packets_.back().receive_time -
                     last_received_packets_.front().receive_time;
    DataRate receiving_rate = bandwidth_estimate_;
    if (sending_time > TimeDelta::Zero())
      receiving_rate = received_size / sending_time;
    bandwidth_estimate_ = receiving_rate;
    //用实测接收速率作为初始带宽估计
    monitor_intervals_.clear();
    //清除Startup的MI
    mode_ = Mode::kSlowStart;
    //进入慢启动模式
    monitor_intervals_duration_ = ComputeMonitorIntervalsDuration();
    //重新计算MI时长(基于当前发包间隔)

    monitor_intervals_bitrates_ = {bandwidth_estimate_};
    //慢启动第一轮: 1个MI, 速率=接收速率
    monitor_intervals_.emplace_back(bandwidth_estimate_, msg.send_time,
                                    monitor_intervals_duration_);
    //创建MI
    bandwidth_estimate_ = bandwidth_estimate_ * (1 / kSlowStartModeIncrease);
    //关键将估计回退到 1/1.5 = 0.667倍
    // 因为下一轮慢启动会乘以1.5x,
    // 0.667 × 1.5 = 1.0 → 第一个慢启动MI实际速率 = 接收速率
    // 之后每轮: bw×1.5 → 真正的翻倍增长
    complete_feedback_monitor_interval_number_ = 0;
    return CreateRateUpdate(msg.send_time);
  }

  // ---- 6. 反馈收集完毕 或 超时 → 创建下一轮MI ----
  if (IsFeedbackCollectionDone() || IsTimeoutExpired(msg.send_time)) {
    //所有MI反馈都收到 或 超时
    monitor_intervals_.clear();
    //清除旧MI
    monitor_interval_timeout_ =
        rtt_tracker_.GetRtt() * monitor_interval_timeout_ratio_;
    // 更新超时阈值 = 当前RTT × 2
    monitor_intervals_duration_ = ComputeMonitorIntervalsDuration();
    //重新计算MI时长
    complete_feedback_monitor_interval_number_ = 0;
    //已完成MI计数归零
    // ---- 根据模式创建MI ----
    if (mode_ == Mode::kSlowStart) {
      // 慢启动: 创建1个MI, 速率 = 1.5 × bandwidth_estimate_
      monitor_intervals_bitrates_ = {kSlowStartModeIncrease *
                                     bandwidth_estimate_};
      monitor_intervals_.emplace_back(
          kSlowStartModeIncrease * bandwidth_estimate_,
          msg.send_time,
          monitor_intervals_duration_);
    } else {
      // 在线学习 或 DoubleCheck: 创建2个MI
      RTC_DCHECK(mode_ == Mode::kOnlineLearning || mode_ == Mode::kDoubleCheck);
      monitor_intervals_.clear();
      int64_t sign = 2 * (random_generator_.Rand(0, 1) % 2) - 1;
      //随机产生 +1 或 -1, 决定哪个MI先用高速率
      // Rand(0,1) → 0或1 → ×2-1 → -1或+1
      RTC_DCHECK_GE(sign, -1);
      RTC_DCHECK_LE(sign, 1);
      if (bandwidth_estimate_ >= kMinRateHaveMultiplicativeRateChange) {
        //乘法探测: 速率 >= 80kbps 时使用
        monitor_intervals_bitrates_ = {
            bandwidth_estimate_ * (1 + sign * sampling_step_),
            //MI[0]: r × (1 + sign×0.05)
            bandwidth_estimate_ * (1 - sign * sampling_step_)};
        // MI[1]: r × (1 - sign×0.05)
        //
        //例: r=1Mbps, sign=+1
        // MI[0] = 1.05Mbps, MI[1] = 0.95Mbps
        // 例: r=1Mbps, sign=-1
        // MI[0] = 0.95Mbps, MI[1] = 1.05Mbps
      } else {
        //加法探测: 速率 < 80kbps 时使用
        monitor_intervals_bitrates_ = {
            DataRate::BitsPerSec(std::max<double>(
                bandwidth_estimate_.bps() + sign * kMinRateChangeBps, 0)),
            //MI[0]: r + sign×4kbps (不低于0)
            DataRate::BitsPerSec(std::max<double>(
                bandwidth_estimate_.bps() - sign * kMinRateChangeBps, 0))};
        //MI[1]: r - sign×4kbps (不低于0)
      }
      // 立即启动第一个MI
      monitor_intervals_.emplace_back(monitor_intervals_bitrates_[0],
                                      msg.send_time,
                                      monitor_intervals_duration_);
      //第二个MI在第一个MI结束后自动启动(见前面第3步)
    }
  }

  return CreateRateUpdate(msg.send_time);
  //返回速率更新给编码器和Pacer
}
// ═══════════════════════════════════════════════════
// MI持续时间计算
// ═══════════════════════════════════════════════════
TimeDelta PccNetworkController::ComputeMonitorIntervalsDuration() const {
  TimeDelta monitor_intervals_duration = TimeDelta::Zero();
  if (monitor_interval_length_strategy_ ==
      MonitorIntervalLengthStrategy::kAdaptive) {
    // 自适应: max(RTT × 1.0, 平均发包间隔 × 20)
    monitor_intervals_duration = std::max(
        rtt_tracker_.GetRtt() * monitor_interval_duration_ratio_,
        smoothed_packets_sending_interval_ * min_packets_number_per_interval_);
  } else {
    RTC_DCHECK(monitor_interval_length_strategy_ ==
               MonitorIntervalLengthStrategy::kFixed);
    // 固定(默认): 平均发包间隔 × 20
    monitor_intervals_duration =
        smoothed_packets_sending_interval_ * min_packets_number_per_interval_;
    //保证每个MI至少包含20个包的测量量
  }
  monitor_intervals_duration =
      std::max(kMinDurationOfMonitorInterval, monitor_intervals_duration);
  //下限50ms: 防止MI太短导致统计不可靠
  return monitor_intervals_duration;
}
// MI是否超时: 当前时间 - 未完成MI结束时间 >= RTT×2
bool PccNetworkController::IsTimeoutExpired(Timestamp current_time) const {
  if (complete_feedback_monitor_interval_number_ >= monitor_intervals_.size()) {
    return false;
    //所有MI都已完成, 不存在超时
  }
  return current_time -
             monitor_intervals_[complete_feedback_monitor_interval_number_]
                 .GetEndTime() >=
         monitor_interval_timeout_;
  //(当前时间 - 第一个未完成MI的结束时间) >= 超时阈值
}

// 所有预定MI的反馈是否全部收集完毕
bool PccNetworkController::IsFeedbackCollectionDone() const {
  return complete_feedback_monitor_interval_number_ >=
         monitor_intervals_bitrates_.size();
  //已完成数量 >= 预定MI数量(慢启动=1, 在线学习=2)
}

// ═══════════════════════════════════════════════════
// OnTransportPacketsFeedback --- 反馈回调
//
// 
// 1. 保存最近20包(用于超时估速)
// 2. 更新RTT
// 3. 将反馈路由到对应MI
// 4. 所有MI完成后触发速率更新
// ═══════════════════════════════════════════════════

NetworkControlUpdate PccNetworkController::OnTransportPacketsFeedback(

    TransportPacketsFeedback msg) {
  if (msg.packet_feedbacks.empty())
    return NetworkControlUpdate();
  //无反馈数据, 直接返回
  // ---- 1. 保存最近收到的包 ----
  for (const PacketResult& packet_result : msg.ReceivedWithSendInfo()) {
    last_received_packets_.push_back(packet_result);
    //追加到队尾
  }

  while (last_received_packets_.size() > kNumberOfPacketsToKeep) {
    last_received_packets_.pop_front();
    //保持最多20个包
  }

  // ---- 2. 更新RTT估计 ----
  rtt_tracker_.OnPacketsFeedback(msg.PacketsWithFeedback(), msg.feedback_time);
  // ---- 3. 在线学习刚启动但MI尚未创建时跳过 ----
  if (mode_ == Mode::kOnlineLearning &&
      monitor_intervals_bitrates_.size() < 2) {
    return NetworkControlUpdate();
    //在线学习需要2个MI, 但尚未准备好, 跳过
  }

  // ---- 4. 将反馈路由到MI ----
  if (!IsFeedbackCollectionDone() && !monitor_intervals_.empty()) {
    while (complete_feedback_monitor_interval_number_ <
           monitor_intervals_.size()) {
      // 将反馈喂给当前第一个未完成的MI

      monitor_intervals_[complete_feedback_monitor_interval_number_]
          .OnPacketsFeedback(msg.PacketsWithFeedback());
      if (!monitor_intervals_[complete_feedback_monitor_interval_number_]
               .IsFeedbackCollectionDone())
        break;
      //当前MI还没收集完 → 停止(等待更多反馈)
      ++complete_feedback_monitor_interval_number_;
      // 当前MI收集完毕 → 推进到下一个MI
    }
  }

  // ---- 5. 所有MI反馈收集完毕 → 触发决策 ----
  if (IsFeedbackCollectionDone()) {
    if (mode_ == Mode::kDoubleCheck) {
      mode_ = Mode::kOnlineLearning;
      //DoubleCheck验证完成 → 回到在线学习
    } else if (NeedDoubleCheckMeasurments()) {
      mode_ = Mode::kDoubleCheck;
      //检测到异常(低速率高丢包) → 进入DoubleCheck模式
      // 下一轮会用相同的两个探测速率再测一次
    }

    if (mode_ != Mode::kDoubleCheck)
      UpdateSendingRateAndMode();
    //不需要复测时 → 更新发送速率和模式
    // DoubleCheck模式下跳过更新(直接用相同速率再测一轮)
  }
  return NetworkControlUpdate();
}

// ═══════════════════════════════════════════════════
// 双重验证判断: 低速率反而高丢包 → 测量不可靠
// ═══════════════════════════════════════════════════
bool PccNetworkController::NeedDoubleCheckMeasurments() const {
  if (mode_ == Mode::kSlowStart) {
    return false;
    //慢启动只有1个MI, 无法比较, 不需要
  }

  double first_loss_rate = monitor_intervals_[0].GetLossRate();
  //第一个MI的丢包率
  double second_loss_rate = monitor_intervals_[1].GetLossRate();
  //第二个MI的丢包率
  DataRate first_bitrate = monitor_intervals_[0].GetTargetSendingRate();
  // 第一个MI的目标速率
  DataRate second_bitrate = monitor_intervals_[1].GetTargetSendingRate();
  //第二个MI的目标速率

  if ((first_bitrate.bps() - second_bitrate.bps()) *
          (first_loss_rate - second_loss_rate) <
      0) {
    return true;
    //(速率差) × (丢包差) < 0
    // 含义: 速率更高的MI反而丢包更少 → 违反直觉 → 测量不可靠
    // 例: r₁=1.05Mbps, L₁=1%, r₂=0.95Mbps, L₂=3%
    // (1.05-0.95) × (0.01-0.03) = 0.1 × (-0.02) = -0.002 < 0
    // → 需要复测
  }
  return false;
}

// ═══════════════════════════════════════════════════
// 根据MI结果更新发送速率和工作模式
// ═══════════════════════════════════════════════════

void PccNetworkController::UpdateSendingRateAndMode() {
  if (monitor_intervals_.empty() || !IsFeedbackCollectionDone()) {
    return;
    //无MI或反馈未完成, 跳过
  }
  if (mode_ == Mode::kSlowStart) {
    // ---- 慢启动模式 ----
    DataRate old_bandwidth_estimate = bandwidth_estimate_;
    //记录旧带宽估计
    bandwidth_estimate_ =
        bitrate_controller_
            .ComputeRateUpdateForSlowStartMode(monitor_intervals_[0])
            .value_or(bandwidth_estimate_);
    //效用增长 → 返回MI速率作为新估计
    // 效用未增长 → 返回nullopt → .value_or保持旧估计不变
    if (bandwidth_estimate_ <= old_bandwidth_estimate)
      mode_ = Mode::kOnlineLearning;
    //带宽没有增长 →退出慢启动, 进入在线学习

  } else {
    // ---- 在线学习模式 ----
    RTC_DCHECK(mode_ == Mode::kOnlineLearning);
    bandwidth_estimate_ =
        bitrate_controller_.ComputeRateUpdateForOnlineLearningMode(
            monitor_intervals_, bandwidth_estimate_);
    // 核心 两点梯度 → 步长 → 动态边界 → 新速率
    // 内部执行:
    // gradient = [U(r₁)-U(r₂)] / [r₁-r₂]
    // Δr = gradient × stepSize
    // Δr = ApplyDynamicBoundary(Δr)
    // new_r = max(0, old_r + Δr)
  }
}

// ═══════════════════════════════════════════════════
// 以下接口PCC不使用, 返回空更新
// ═══════════════════════════════════════════════════
NetworkControlUpdate PccNetworkController::OnNetworkAvailability(
    NetworkAvailability msg) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnNetworkRouteChange(
    NetworkRouteChange msg) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnProcessInterval(
    ProcessInterval msg) {
  return CreateRateUpdate(msg.at_time);

  // 定时回调: 返回当前速率(不改变状态)
}

NetworkControlUpdate PccNetworkController::OnTargetRateConstraints(
    TargetRateConstraints msg) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnRemoteBitrateReport(
    RemoteBitrateReport) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnRoundTripTimeUpdate(
    RoundTripTimeUpdate) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnTransportLossReport(
    TransportLossReport) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnStreamsConfig(StreamsConfig msg) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnReceivedPacket(
    ReceivedPacket msg) {
  return NetworkControlUpdate();
}

NetworkControlUpdate PccNetworkController::OnNetworkStateEstimate(
    NetworkStateEstimate msg) {
  return NetworkControlUpdate();
}

}  // namespace pcc

}  // namespace webrtc

八、PccFactory --- 工厂类

pcc_factory.h

cpp 复制代码
namespace webrtc {

// PCC控制器工厂, 实现 NetworkControllerFactoryInterface 接口

class PccNetworkControllerFactory : public NetworkControllerFactoryInterface {
 public:
  PccNetworkControllerFactory();
  // 创建PCC控制器实例
  std::unique_ptr<NetworkControllerInterface> Create(
      NetworkControllerConfig config) override;
  // 返回定时回调间隔
  TimeDelta GetProcessInterval() const override;
};
}  // namespace webrtc

pcc_factory.cc

cpp 复制代码
namespace webrtc {

PccNetworkControllerFactory::PccNetworkControllerFactory() {}
std::unique_ptr<NetworkControllerInterface> PccNetworkControllerFactory::Create(
    NetworkControllerConfig config) {
  return std::make_unique<pcc::PccNetworkController>(config);
  //创建PCC控制器实例
}

TimeDelta PccNetworkControllerFactory::GetProcessInterval() const {
  return TimeDelta::PlusInfinity();
  // 返回正无穷 → PCC不依赖定时器驱动
  // 完全由包事件(OnSentPacket / OnTransportPacketsFeedback)驱动
  // 这与GCC/BBR依赖定时器的设计不同
}
}  // namespace webrtc

九、核心数学公式汇总

十、算法整体执行流程

cpp 复制代码
OnSentPacket(发包触发)
    │
    ├─ 首包 ? → 初始化,创建 Startup MI(500ms, 300kbps)
    │
    ├─ 更新发包间隔EWMA
    │
    ├─ 当前MI结束且还有下一个 ? → 启动下一个MI
    │
    ├─ 超时(> RTT×2) ? → bandwidth = min(bw×0 .5, 接收速率)
    │
    ├─ Startup到期(500ms) ? → 估算接收速率 → 进入 SlowStart
    │
    └─ 所有MI反馈收完 或 超时 ? → 开始新一轮 :
         ├─ SlowStart      : 创建 1个MI, 速率 = 1.5 × bw
         └─ OnlineLearning : 创建 2个MI, 速率 = r(1±5 %)
cpp 复制代码
OnTransportPacketsFeedback(反馈触发)
    │
    ├─ 保存最近20包,
                          更新RTT
    │
    ├─ 将反馈路由到各MI → 标记完成的MI
    │
    └─ 所有MI完成 ?
        ├─ 检查是否需要 DoubleCheck(低速率高丢包异常)
        │   ├─ 需要 → 进入DoubleCheck, 用相同速率再测一轮
        │   └─ 不需要 → 调用 UpdateSendingRateAndMode() :
        │       ├─ SlowStart : 效用增长 ? → 采纳速率, 继续
        │       │ 效用不增长 ? → 退出 → OnlineLearning
        │       └─ OnlineLearning :
        │ gradient = [U(r + ε) - U(r - ε)] / [2ε·r]
        │ Δr = gradient × stepSize
        │ Δr = ApplyDynamicBoundary(Δr)
        │ new_r = max(0, old_r + Δr)
        └─ DoubleCheck完成 → 回到OnlineLearning

十一、WebRTC PCC 算法存在哪些不足

编号 维度 不足之处 源码 实际影响
1 丢包处理 不区分拥塞丢包与随机丢包,所有丢包统一惩罚 utility_function.cc 效用函数中 loss_coefficient_ * bitrate * loss_rate,直接使用总丢包率 L 在无线/卫星等有随机丢包的链路上,误判为拥塞 → 速率被过度压低,利用率极差
2 收敛速度 Startup 阶段浪费 500ms 以固定 300kbps 发送,不做任何速率调整 kStartupDuration = 500mskInitialBandwidthKbps = 300,Startup 结束才切换到 SlowStart 高带宽链路(如 100Mbps)需要极长时间才能探测到实际容量
3 收敛速度 慢启动仅 1.5x 增长,且每轮只有 1 个 MI kSlowStartModeIncrease = 1.5,慢启动只创建 1 个 MI 从 300kbps 增长到 50Mbps 需要 ≈30 轮慢启动,若每轮 200ms 则需要 6 秒以上
4 RTT 测量 使用反馈批次中的最大 RTT而非最小 RTT rtt_tracker.cc: packet_rtt = std::max(packet_rtt, ...) 排队延迟、处理延迟会拉高估计值,不能准确反映传播时延
5 RTT 跟踪 无 base RTT(最小 RTT)跟踪,仅维护 EWMA 平滑值 RttTracker 仅有 rtt_estimate_,无 min_rtt_ 成员 无法判断当前 RTT 偏离基线多远,无法做主动排空/延迟预算
6 延迟控制 无硬性延迟预算(Delay Budget)机制 代码中无任何 base_rtt * multiplier 的限制逻辑 RTT 可能无限膨胀,在长肥管道中排队延迟可达数百毫秒
7 紧急响应 无紧急回退机制,即使丢包率飙升到 50% 也需要等 MI 结束后才反应 OnTransportPacketsFeedback 中只在所有 MI 完成后才调用 UpdateSendingRateAndMode 突发拥塞时响应延迟 = MI 时长 + 反馈延迟,可能数百毫秒到数秒
8 超时处理 超时处理过于粗暴:直接减半且无渐进恢复 bandwidth_estimate_ = std::min(bw * 0.5, receiving_rate) 超时后速率骤降 50%,无平滑过渡;恢复也依赖慢速梯度上升
9 采样步长 ε=0.05 硬编码,不自适应 kDefaultSamplingStep = 0.05 低速率时 5% 变化太小(如 100kbps → ±5kbps),高速率时探测幅度可能过大
10 探测方式 两个 MI 串行执行,网络条件可能在两个 MI 之间发生变化 先运行 MI[0](r+ε),等完成后再运行 MI[1](r-ε) 如果带宽在两个 MI 之间变化,梯度计算结果可能失真
11 DoubleCheck 异常检测只复测一次,不具备持续鲁棒性 DoubleCheck 完成后直接 mode_ = kOnlineLearning,不再检查 如果网络持续不稳定(如高抖动),单次复测不足以得出可靠结论
12 步长控制 步长放大器可无限增长(2n-3),无上限 step_size_amplifier = 2 * abs(n) - 3,n 可任意大 连续多次同向调整后,步长可能极大 → 速率剧烈跳变 → 震荡
13 动态边界 方向切换时边界立即重置为最小值(10%) consecutive_boundary_adjustments_number_ = 0 在平衡点附近频繁切换方向时,边界反复收缩 → 调整幅度被限制 → 收敛缓慢
14 吞吐量估算 效用函数使用目标发送速率 r 而非实际吞吐量 bitrate = monitor_interval.GetTargetSendingRate().bps() 当实际吞吐量远低于发送速率时(如严重拥塞),效用值不能准确反映网络状况
15 噪声过滤 时延梯度仅靠阈值 0.01 过滤,无 EWMA 平滑 if (abs(rtt_gradient) < 0.01) rtt_gradient = 0 单个 MI 内的梯度受突发抖动影响大,可能产生虚假的正/负梯度信号
16 丢包率统计 每个 MI 独立计算丢包率,无跨 MI 的 EWMA 平滑 GetLossRate() 仅计算本 MI 内的 lost/(lost+received) 小样本(20 个包中丢 1 个 = 5%)方差极大,统计不可靠
17 接收速率限制 仅在超时时考虑接收速率,正常情况下不做限速 超时代码 min(bw*0.5, receiving_rate),但 UpdateSendingRateAndMode 中无此逻辑 梯度上升可能将速率推到远超链路容量,造成持续丢包和排队
18 公平性 无显式公平性机制,多流竞争时无保障 代码中无任何公平性相关逻辑 多条 PCC 流共享瓶颈时,可能出现严重不公平
19 随机种子 随机种子固定为 100,行为完全确定性 const uint64_t kRandomSeed = 100 多条 PCC 流使用相同种子 → 探测方向同步 → 同时升速或同时降速 → 加剧震荡
20 MI 时长策略 默认使用固定策略(基于包数),不考虑 RTT monitor_interval_length_strategy_ = kFixed,时长 = 发包间隔 × 20 高 RTT 链路(如 300ms):MI 可能只有几十毫秒,在收到第一个反馈前已结束多个 MI
21 抖动处理 无任何抖动(Jitter)检测或补偿机制 时延梯度直接用原始时延做线性回归,无去抖动处理 高抖动环境下(如 WiFi),时延梯度噪声极大,导致频繁误判
22 负梯度截断 时延下降(队列排空)时奖励被截断在 -0.1 rtt_gradient = max(gradient, -0.1) 当网络从拥塞中快速恢复时,算法不能充分利用时延下降信号来加速升速
23 MI 结束判断 依赖收到发送时间超出 MI 结束时间的包才标记完成 if (send_time > start_time_ + duration) { done = true; } 如果 MI 结束后恰好无包发送(如应用层暂停),则 MI 永远不会完成 → 状态卡死
24 效用函数参数 所有效用函数参数硬编码,无自适应调节 kRttGradientCoefficientBps=0.005, kLossCoefficientBps=10 等均为常量 对不同类型网络(有线/无线/卫星)不能自动适配,需要人工调参
25 接口实现 多个 NetworkController 接口返回空实现 OnNetworkRouteChange, OnTargetRateConstraints 等全部返回空 不响应路由变更、速率约束等外部信号,无法与 WebRTC 其他模块协同

十二、不足分类汇总

类别 涉及编号 核心问题
时延控制薄弱 4, 5, 6, 15, 21, 22 无 base RTT、无延迟预算、无抖动处理、梯度噪声大
丢包处理粗糙 1, 16 不区分丢包类型、小样本统计方差大
收敛速度慢 2, 3, 9, 13, 20 Startup浪费500ms、慢启动仅1.5x、步长不自适应
鲁棒性不足 7, 8, 10, 11, 23 无紧急回退、超时处理粗暴、串行探测易受非平稳干扰
稳态震荡 12, 14, 17 步长无上限、效用用目标速率而非实际吞吐、无接收速率限速
多流/部署 18, 19, 24, 25 无公平性、固定种子、参数硬编码、接口不完整

十三、基于webrtc pcc算法的不足进行改进的pcc++算法

作者对webrtc pcc原生算法针对rtc场景下进行的了改进。直接看效果

PCC++ vs WebRTC PCC (稳态指标)

|----------------------------|----------------|--------|----------------|--------|-------------------------------------|
| 场景 | webrtc pcc | | pcc++ | | 对比结果 |
| | Loss / RTT | Util | Loss / RTT | Util | |
| Stable Wired (50M/20ms) | 0.0%/20.9ms | 15.05% | 0.0%/21.74ms | 91.63% | 丢包持平 rtt+0.84ms 效用值更优+76.58% |
| Wireless (10M/50ms/2%) | 3.57%/52.78ms | 3.11% | 3.34%/54.49ms | 5.56% | 丢包更优-0.23% rtt+1.71ms 效用值更优+2.45% |
| Satellite (20M/300ms/0.5%) | 0.72%/305.33ms | 5.28% | 0.51%/307.24ms | 63.95% | 丢包更优-0.21% rtt+1.91ms 效用值更优+58.67% |
| Dynamic BW (30→10M) | 1.34%/42.05ms | 4.24% | 1.35%/42.82ms | 20.96% | 丢包+0.01% rtt+0.77ms 效用值更优+16.72% |
| Low BW (1.5M/100ms/1%) | 1.99%/108.65ms | 58.40% | 1.58%/104.90ms | 59.65% | 丢包更优-0.41% rtt更优-3.75ms 效用值更优+1.25% |
| High Jitter (5M/30+50ms) | 1.19%/32.07ms | 12.92% | 3.61%/35.04ms | 2.05% | 丢包+2.42% rtt+2.97ms 效用值-10.04 |
| Long Fat Pipe (100M/150ms) | 0.04%/154.20ms | 2.62% | 0.09%/154.28ms | 76.23% | 丢包+0.05% rtt+0.08ms 效用值+73.61 |
| | | | | | |

关键改进成果

丢包率:7 个场景中 4 个优于或持平 WebRTC PCC,其余 3 个差距均 < 2.42%

RTT 控制:5/7 场景与 WebRTC PCC 的 RTT 差距 < 3ms;Low BW 场景 PCC++ 的 RTT 反而更低

带宽利用率:6/7 场景 PCC++ 更高,卫星链路 63.95% vs 5.28%,长肥管道 76.23% vs 2.62%

测试demo:链接: https://pan.baidu.com/s/1CBR1M7-n9ySYWEosM1vABA 提取码: cyqc

相关推荐
北顾笙9802 小时前
day20-数据结构力扣
数据结构·算法·leetcode
bIo7lyA8v2 小时前
算法稳定性分析中的数值误差传播机制的技术5
算法
初遇见2 小时前
【DGX Spark v3.0:基于多智能体交互网络与 Alpaca 实盘集成的企业级量化交易系统】
大数据·网络·spark·nvidia
码云数智-大飞2 小时前
解耦的艺术:.NET 中依赖注入(DI)的核心原理与实战
网络·网络协议·rpc
生信研究猿2 小时前
leetcode 121.买卖股票的最佳时机
算法·leetcode·职场和发展
云边云科技_云网融合2 小时前
网关接入异常监测预警:从固定阈值到 AI 动态感知的技术革新
运维·服务器·网络·人工智能
CoovallyAIHub2 小时前
不需要Memory Bank:CMDR-IAD用2D+3D双分支重建做工业异常检测,MVTec 3D 97.3%
算法·架构·github
zmj3203243 小时前
以太网和CAN,WIFI
网络