WebRTC pacing模块中的RoundRobinPacketQueue分析

  WebRTC中的pacing模块主要负责拥塞控制,其中RoundRobinPacketQueue是模块里的核心数据结构,项目开发中也要做类似的拥塞控制模块,WebRTC中的RoundRobinPacketQueue设计思路也很值得借鉴。

1、模块定义

  RoundRobinPacketQueue名字中已经给出了答案,这是一个特殊的队列,用于管理数据包。Pacing大概的调用关系如图所示,上游模块把数据包扔给Pacing模块,Pacing模块最终会将数据包放入自己维护的RoundRobinPacketQueue对象中,然后Pacing内部启动了一个定时器,每个5ms会根据带宽情况合理的从RoundRobinPacketQueue中pop数据,然后发送出去。

2、RoundRobinPacketQueue接口定义

RoundRobinPacketQueue的对外接口定义如下,从对外接口看,关键是实现push和pop,RoundRobinPacketQueue内部实现对数据包的有效管理,对外就是一个queue的接口调用。

class RoundRobinPacketQueue {
 public:
  //构造函数
  RoundRobinPacketQueue(Timestamp start_time,
                        const WebRtcKeyValueConfig* field_trials);
  ~RoundRobinPacketQueue();
   
  // push具有不同优先级的数据
  void Push(int priority,
            Timestamp enqueue_time,
            uint64_t enqueue_order,
            std::unique_ptr<RtpPacketToSend> packet);
  
  // 弹出一个最高优先级的数据包
  std::unique_ptr<RtpPacketToSend> Pop();

  // 是否为空
  bool Empty() const;

  // 数据包的数量
  size_t SizeInPackets() const;

  // 数据包的总字节数
  DataSize Size() const;

  // 当前最高优先级的数据包如果是音频包,则返回该数据包的入队时间戳,
  // 如果不是音频包,则返回nullopt
  // If the next packet, that would be returned by Pop() if called
  // now, is an audio packet this method returns the enqueue time
  // of that packet. If queue is empty or top packet is not audio,
  // returns nullopt.
  absl::optional<Timestamp> LeadingAudioPacketEnqueueTime() const;
  
  // 队列中的最早的入队时间
  Timestamp OldestEnqueueTime() const;
  TimeDelta AverageQueueTime() const;
  void UpdateQueueTime(Timestamp now); 
  void SetPauseState(bool paused, Timestamp now);
  void SetIncludeOverhead();
  void SetTransportOverhead(DataSize overhead_per_packet);
  ...
};

3、QueuedPacket对象

Pacing模块通过push接口将数据包压入到RoundRobinPacketQueue中,RoundRobinPacketQueue定义了一个QueuePacket对象用于包裹外部传进来的数据包数据。

  struct QueuedPacket {
   public:
    QueuedPacket(int priority,
                 Timestamp enqueue_time,
                 uint64_t enqueue_order,
                 std::multiset<Timestamp>::iterator enqueue_time_it,
                 std::unique_ptr<RtpPacketToSend> packet);
    QueuedPacket(const QueuedPacket& rhs);
    ~QueuedPacket();
    
    // 此函数很关键,用于进行优先级队列的比较
    bool operator<(const QueuedPacket& other) const;
   
    int Priority() const;
    RtpPacketMediaType Type() const;
    uint32_t Ssrc() const;
    Timestamp EnqueueTime() const;
    bool IsRetransmission() const;
    uint64_t EnqueueOrder() const;
    RtpPacketToSend* RtpPacket() const;

    std::multiset<Timestamp>::iterator EnqueueTimeIterator() const;
    void UpdateEnqueueTimeIterator(std::multiset<Timestamp>::iterator it);
    void SubtractPauseTime(TimeDelta pause_time_sum);

   private:
    int priority_;
    Timestamp enqueue_time_;  // Absolute time of pacer queue entry.
    uint64_t enqueue_order_;
    bool is_retransmission_;  // Cached for performance.

    // 此字段汉关键,用于记录当前对象的时间戳插入到enqueue_times_中的位置
    // 当改数据包pop时,该字段用于将enqueue_times_中的相应时间戳删除
    std::multiset<Timestamp>::iterator enqueue_time_it_;

    // 原始的数据包
    // Raw pointer since priority_queue doesn't allow for moving
    // out of the container.
    RtpPacketToSend* owned_packet_;
  };

4、基于Stream的优先级队列

RoundRobinPacketQueue内部是以Stream为单位进行数据包管理的,每个Stream对应一路独立的SSRC数据流,相当于每路数据流,有一个Stream与之对应。Stream的类成员变量有一个SSRC用于标识流的SSRC数值。每个Stream对象都维护了一个基于C++标准库的优先级队列。

<
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值