WEBRTC浅析(八)GCC:: Transport-wide Congestion Control的协议简析

本文深入剖析了WebRTC中的Transport-wide Congestion Control (TWCC),包括SDP协商过程、RTP扩展头Transport Sequence Number的发送与接收,以及TWCC反馈报文的打包和解析。通过TWCC,发送端可以在RTP包中附加序列号,并通过RTCP反馈报文接收端传递包状态和延迟信息,用于实时调整网络拥塞控制策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WEBRTC浅析(八)GCC:: Transport-wide Congestion Control的协议简析

Transport-wide Congestion Control

参考文档:https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

一:SDP协商

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

二:RTP扩展头::TransportSequenceNumber

发送端在

 0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |       0xBE    |    0xDE       |           length=1            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  ID   | L=1   |transport-wide sequence number | zero padding  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

An RTP header extension with a 16 bits sequence number attached to
all packets sent. This sequence number is incremented by 1 for each
packet being sent over the same socket.

  • 在webrt中的TWCC报文实现:

      //   0                   1                   2
      //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
      //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      //  |  ID   | L=1   |transport wide sequence number |
      //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      constexpr RTPExtensionType TransportSequenceNumber::kId;
      constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
      constexpr const char* TransportSequenceNumber::kUri;
      
      bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
                                          uint16_t* value) {
        if (data.size() != 2)
          return false;
        *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
        return true;
      }
      
      bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
      
        ByteWriter<uint16_t>::WriteBigEndian(data, value);
        return true;
      }
    
  • 发送端:TransportSequenceNumber RTP扩展头的发送

      bool RTPSender::UpdateTransportSequenceNumber(RtpPacketToSend* packet,
                                                    int* packet_id) const {
      		......
      		
      	  *packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
      	
      	  if (!packet->SetExtension<TransportSequenceNumber>(*packet_id)) {
      	    return false;
      	  }
      	  
      	  return true;
      }
    
  • 接收端:TransportSequenceNumber RTP扩展头的解析

      void Packet::GetHeader(RTPHeader* header) const {
      
      	  header->markerBit = Marker();
      	  header->payloadType = PayloadType();
      	  header->sequenceNumber = SequenceNumber();
      	  header->timestamp = Timestamp();
      	  header->ssrc = Ssrc();
      		......
      	  header->extension.hasAbsoluteSendTime =
      	      GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
      	  header->extension.hasTransportSequenceNumber =
      	      GetExtension<TransportSequenceNumber>(
      	          &header->extension.transportSequenceNumber);
      		......
      			
      }
    

三:TWCC 反馈报文(Transport-wide RTCP Feedback Message)

        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |V=2|P|  FMT=15 |    PT=205     |           length              |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     SSRC of packet sender                     |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      SSRC of media source                     |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |      base sequence number     |      packet status count      |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                 reference time                | fb pkt. count |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |          packet chunk         |         packet chunk          |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       .                                                               .
       .                                                               .
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |         packet chunk          |  recv delta   |  recv delta   |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       .                                                               .
       .                                                               .
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           recv delta          |  recv delta   | zero padding  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 包状态块解析(packet chunk)
    包状态块,有两种:

    1. Run length chunk:当我们连续收到多个数据包,他们都有相同的到达状态,就可以用这种编码方式

          0                   1
          0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         |T| S |       Run Length        |
         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      
      • chunk type (T): 为0,表示为Run length chunk

      • packet status symbol (S): 包状态符号,有四种:

          00 Packet not received
          01 Packet received, small delta (所谓small detal是指能用一个字节表示的数值)
          10 Packet received, large ornegative delta (large即是能用两个字节表示的数值)
          11 [Reserved]
        
    2. Status vector chunk:这种表示方式用于每个数据包都需要自己的状态表示码。但是这里的S就不是上面的意思。

       0                   1
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |T|S|       symbol list         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      
      • chunk type (T): 为1,表示为Status vector chunk

      • symbol size (S):
        s = 0 时,表示symbollist的每一个bit能表示一个数据包的到达状态

          0 Packet not received
          1 Packet received, small delta
          
          s = 1 时,表示symbollist每两个bit表示一个数据包的状态
          00 Packet not received
          01 Packet received, small delta
          10 Packet received, large ornegative delta
          11 [Reserved]
        
  • 接收时间差(recv delta)

      最后,对于每一个状态为Packet received 的数据包的延迟依次填入|recv delta|字段
      到达状态为1的,recv delta占用一个字节
      到达状态为2的,recv delta占用两个字节
      可以看出以上编码的目的是为了尽量减少该数据包的大小。
    
  • webrtc中TWCC的打包代码:

      // Serialize packet.
      bool TransportFeedback::Create(uint8_t* packet,
                                     size_t* position,
                                     size_t max_length,
                                     PacketReadyCallback* callback) const {
      }
      
      
        static std::unique_ptr<TransportFeedback> ParseFrom(const uint8_t* buffer,
                                                            size_t length);
    
  • webrtc中发送端:打包TWCC报文

      // 在收到RTP包的时候先同步数据
      PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type,
                                              const uint8_t* packet,
                                              size_t length,
                                              const PacketTime& packet_time, bool just_for_bwe) {
        parsed_packet->IdentifyExtensions(it->second.extensions);
      
        NotifyBweOfReceivedPacket(*parsed_packet, media_type);
      
      }
    
      // 传入arrive time和sequence number
      void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,
                                                size_t payload_size,
                                                const RTPHeader& header) {
        if (!header.extension.hasTransportSequenceNumber) {
      
        OnPacketArrival(header.extension.transportSequenceNumber, arrival_time_ms);
       
      }
    
      
      //在收到包后,组包并发送
      void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,
                                                 int64_t arrival_time) {
      
      		。。。。。。
            rtcp::TransportFeedback feedback_packet;
            if (BuildFeedbackPacket(&feedback_packet)) {
              RTC_DCHECK(packet_router_ != nullptr);
      		}
      		。。。。。。
      }
    
  • Webrtc中接收端:接收解析TWCC报文

      	//1. 在rtcp callback的回调中,分析拆解
      	bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin,
                                         const uint8_t* packet_end,
                                         PacketInformation* packet_information) {
      
      	    switch (rtcp_block.type()) {
      	      case rtcp::SenderReport::kPacketType:
      	        HandleSenderReport(rtcp_block, packet_information);
      	        break;
      	      case rtcp::ReceiverReport::kPacketType:
      	        HandleReceiverReport(rtcp_block, packet_information);
      	        break;
      	      case rtcp::Sdes::kPacketType:
      	        HandleSdes(rtcp_block, packet_information);
      	        break;
      	      case rtcp::ExtendedReports::kPacketType:
      	        HandleXr(rtcp_block, packet_information);
      	        break;
      	      case rtcp::Bye::kPacketType:
      	        HandleBye(rtcp_block);
      	        break;
      	      case rtcp::Rtpfb::kPacketType:
      	        switch (rtcp_block.fmt()) {
      	          case rtcp::Nack::kFeedbackMessageType:
      	            HandleNack(rtcp_block, packet_information);
      	            break;
      	          case rtcp::Tmmbr::kFeedbackMessageType:
      	            HandleTmmbr(rtcp_block, packet_information);
      	            break;
      	          case rtcp::Tmmbn::kFeedbackMessageType:
      	            HandleTmmbn(rtcp_block, packet_information);
      	            break;
      	          case rtcp::RapidResyncRequest::kFeedbackMessageType:
      	            HandleSrReq(rtcp_block, packet_information);
      	            break;
      	          case rtcp::TransportFeedback::kFeedbackMessageType:
      	            HandleTransportFeedback(rtcp_block, packet_information);
      	            break;
      	          default:
      	            ++num_skipped_packets_;
      	            break;
      	        }
      
      //2.计算twcc feedback 中,最后一个包的 sendtime和当前时间的差,就可以用来计算实时的rtt
      DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
          std::vector<PacketFeedback>& packet_feedback_vector,
          rtc::Optional<uint32_t> acked_bitrate_bps, rtc::Optional<uint32_t> max_acked_bitrate_bps,
          float loss_rate, float total_loss_rate, float exceed_sent_ratio, bool is_end2end_feedback) {
          
        //Calculate instant rtt frome per feedback
        std::vector<PacketFeedback>::iterator end_feedback = packet_feedback_vector.end();
        if(packet_feedback_vector.begin() != packet_feedback_vector.end())
        {
            end_feedback--;
            double instent_rtt = now_ms - end_feedback->send_time_ms;
            rate_control_.SetRtt(instent_rtt);
            twcc_rtt_ = instent_rtt;
            LOG(LS_VERBOSE) << "#BWE instant_rtt_" << instent_rtt << "  now " << now_ms;
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值