剑痴乎

  • 首页
  • 文章分类
    • 音视频
    • WebRTC
    • 编程之美
    • Linux
    • Windows
    • 生活点滴
    • 校园生活
  • 参考
    • API参考
    • 实用工具
    • 测试音视频
    • 文档
  • 留言板
  • 关于
剑痴乎
代码为剑,如痴如醉
  1. 首页
  2. WebRTC
  3. 正文

WebRTC研究:Transport-cc之RTP及RTCP

2020年4月25日 10244点热度 26人点赞 17条评论

Transport-cc指的是Transport-wide Congestion Control。WebRTC最新的拥塞控制算法(Sendside BWE)基于Transport-cc,接收端记录数据包到达时间,构造相关RTCP包,然后反馈给发送端,在发送端做带宽估计,从而进行拥塞控制。之所以基于Transport-cc,放到发送端进行带宽估计,除了方便维护,也增加了相关算法的灵活性,因为大多数处理逻辑都放到了发送端。WebRTC中为了使用Transport-cc,需要RTP报头扩展以及相关RTCP的配套支持。这里我们介绍下支撑Transport-cc的RTP以及RTCP。

RTP Header扩展

Transport sequence number

首先我们先来复习下RTP固定报头结构:

1
2
3
4
5
6
7
8
9
10
11
12
    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|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

可以看到有一个sequence number字段,用于记录RTP包的序列号。一般情况下我们一个传输通道(PeerConnection)只包含一路视频流,这个sequence number能满足大多数需求。但是在一些情况下,我们一个连接可能传输多个视频流,这些视频流复用一个传输通道,例如simulcast或者single PC场景,一个PeerConnection可能包含多个不同的视频流。在这些视频流中,RTP报头的sequence number是单独计数的。

这里举个例子,假设同一个PeerConnection下,我们传输两个视频流A与B,它们的RTP包记为Ra(n),Rb(n),n表示sequence number,这样我们观察同一个PeerConnection下,视频流按如下形式传输:
Ra(1),Ra(2),Rb(1),Rb(2),Ra(3),Ra(4),Rb(3),Rb(4)

在对某条PeerConnection进行带宽估计时,我们需要估计整条PeerConnection下所有视频流,而不是单独某个流。这样为了做一个RTP session(传输层)级别的带宽估计,原有各个流的sequence number就不能满足我们需要了。

为此Transport-cc中,使用了RTP报头扩展,用于记录transport sequence number,同一个PeerConnection连接下的所有流的transport sequence number,使用统一的计数器进行计数,方便进行同一个PeerConnection下的带宽估计。

这里我们使用前面的例子,视频流A与B,它们的RTP包记为Ra(n,m),Rb(n,m),n表示sequence number,m表示transport sequence number,这样同一个PeerConnection下,视频流按如下形式传输:
Ra(1,1),Ra(2,2),Rb(1,3),Rb(2,4),Ra(3,5),Ra(4,6),Rb(3,7),Rb(4,8)

这样进行带宽估计时,通过transport sequence number我们就能关心到这条传输通道下所有数据包的情况了。

RTP transport sequence number报头定义如下:

1
2
3
4
5
6
7
     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  |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

由于属于RTP报头扩展,所以可以看到以0xBEDE固定字段开头,表示One-Byte Header类型的扩展。

One-Byte Header相关知识请参考:WebRTC研究:RTP报头扩展

transport sequence number占两个字节,存储在One-Byte Header的Extension data字段。由于按4字节对齐,所以还有值为0的填充数据。

对于同一个PeerConnection下的每个包,这个transport sequence number是从1开始递增的。这里我们看下Wireshark中对带transport sequence numberRTP报头扩展的解析:

One-Byte Header中Extension data字段为0x0028,可知该RTP包的transport sequence number为0x0028。

代码导读

WebRTC中,要发送的数据都会经过Pacing模块,用于平滑发送处理,要发送数据会送到pacer thread,在pacer thread中的PacketRouter::SendPacket,对要发送的RTP数据包打上统一计数的TransportSequenceNumber扩展。

C++
1
2
3
4
5
6
7
8
9
10
void PacketRouter::SendPacket(std::unique_ptr<RtpPacketToSend> packet,
                              const PacedPacketInfo& cluster_info) {
  rtc::CritScope cs(&modules_crit_);
  // With the new pacer code path, transport sequence numbers are only set here,
  // on the pacer thread. Therefore we don't need atomics/synchronization.
  // 如果当前RTP包注册了TransportSequenceNumber扩展
  if (packet->HasExtension<TransportSequenceNumber>()) {
    packet->SetExtension<TransportSequenceNumber>((++transport_seq_) & 0xFFFF);
  }
}

TransportFeedback RTCP

允许接收端向发送端传递有关媒体流传输质量的信息,包括到达时间,丢包信息。

报文格式

Transport-cc中,收流客户端通过TransportFeedback RTCP向发送端反馈收到的各个RTP包的到达时间,丢包信息。首先我们看下TransportFeedback包格式定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
     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              |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  0 |                     SSRC of packet sender                     |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4 |                      SSRC of media source                     |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  8 |      base sequence number     |      packet status count      |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 |                 reference time                | fb pkt. count |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 |          packet chunk         |         packet chunk          |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    .                                                               .
    .                                                               .
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |         packet chunk          |  recv delta   |  recv delta   |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    .                                                               .
    .                                                               .
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |           recv delta          |  recv delta   | zero padding  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  • FMT:5bits。Feedback message type(FMT)固定为15
  • PT:8bits。由于属于传输层的Feedback Messages,所以payload type(PT)为205
  • base sequence number:2字节,TransportFeedback包中记录的第一个RTP包的transport sequence number,在反馈的各个TransportFeedback RTCP包中,这个字段不一定是递增的,也有可能比之前的RTCP包小
  • packet status count:2字节,表示这个TransportFeedback包记录了多少个RTP包信息,这些RTP的transport sequence number以base sequence number为基准
  • ,比如记录的第一个RTP包的transport sequence number为base sequence number,那么记录的第二个RTP包transport sequence number为base sequence number+1

  • reference time:3字节,表示参考时间,以64ms为单位,RTCP包记录的RTP包到达时间信息以这个reference time为基准进行计算
  • feedback packet count:1字节,用于计数发送的每个TransportFeedback包,相当于RTCP包的序列号。可用于检测TransportFeedback包的丢包情况
  • packet chunk:2字节,记录RTP包的到达状态,记录的这些RTP包transport sequence number通过base sequence number计算得到
  • recv delta: 8bits,对于"packet received"状态的包,也就是收到的RTP包,在recv delta列表中添加对应的的到达时间间隔信息,用于记录RTP包到达时间信息。通过前面的reference time以及recv delta信息,我们就可以得到RTP包到达时间

packet chunk

首先先了解下RTP包状态,目前定义了如下四种状态,每个状态值2bits,用来标识RTP包的到达状态,以及与前面RTP包的时间间隔大小信息:

  • 00-Packet not received
  • 01-Packet received, small delta
  • 10-Packet received, large or negative delta
  • 11-[Reserved]

packet chunk有两种类型,Run length chunk(行程长度编码数据块)与Status vector chunk(状态矢量编码数据块),对应packet chunk结构的两种编码方式。packet chunk的第一bit标识chunk类型。

Run length chunk

这里先来了解下Run length(行程长度)编码。Run length编码是一种简单的数据压缩算法,其基本思想是将重复且连续出现多次的字符使用“连续出现次数+字符”来描述,例如:aaabbbcdddd通过Run length编码就可以压缩为3a3bc4d。Run length chunk中就使用了Run length编码标识连续多个相同状态的包。

Run length chunk第一bit为0,后面跟着packet status以及run length。格式如下:

1
2
3
4
5
       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):1 bit,值为0
packet status symbol (S):2 bits,标识包状态
run length (L):13 bits,行程长度,标识有多少个连续包为相同状态

下面举例子说明下。

1
2
3
4
5
       0                   1
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |0|0 0|0 0 0 0 0 1 1 0 1 1 1 0 1|
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

packet status为00,由前面包状态可知为"Packet not received"状态,run lengh为221(11011101),说明连续有221个包为"Packet not received"状态。

Status Vector Chunk

第一bit为1,后面跟着symbol size以及symbol list。格式如下:

1
2
3
4
5
        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 bit,值为1
  • symbol size(S):1 bit,为0表示只包含"packet not received" (0)以及"packet received"(1)状态,每个状态使用1bit表示,这样后面14bits的symbol list能标识14个包的状态。为1表示使用2bits来标识包状态,这样symbol list中我们只能标识7个包的状态
  • symbol list:14 bits,标识一系列包的状态, 总共能标识7或14个包的状态

下面举例子说明下。

例子1:

1
2
3
4
5
        0                   1
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |1|0|0 1 1 1 1 1 0 0 0 1 1 1 0 0|
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

symbol size为0,这样能标识14个包的状态。第一个包状态为"packet not received"(0),接着后面5个包状态为"packet received"(1),再接着三个包状态为"packet not received",再接着三个包状态为"packet received",最后两个包状态为"packet not received"。

例子2:

1
2
3
4
5
        0                   1
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |1|1|0 0 1 1 0 1 0 1 0 1 0 0 0 0|
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

symbol size为1,这样只能标识7个包的状态。第一个包为"packet not received"(00)状态,第二个包为 "packet received, w/o timestamp"(11)状态,再接着三个包为"packet received"(01)状态,最后两个包为"packet not received"(00)状态。

Receive Delta

以250us(0.25ms)为单位,表示RTP包到达时间与前面一个RTP包到达时间的间隔,对于记录的第一个RTP包,该包的时间间隔是相对reference time的。

  • 如果在packet chunk记录了一个"Packet received, small delta"状态的包,那么就会在receive delta列表中添加一个无符号1字节长度receive delta,无符号1字节取值范围[0,255],由于Receive Delta以0.25ms为单位,故此时Receive Delta取值范围[0, 63.75]ms
  • 如果在packet chunk记录了一个"Packet received, large or negative delta"状态的包,那么就会在receive delta列表中添加一个有符号2字节长度的receive delta,范围[-8192.0, 8191.75] ms
  • 如果时间间隔超过了最大限制,那么就会构建一个新的TransportFeedback RTCP包,由于reference time长度为3字节,所以目前的包中3字节长度能够覆盖很大范围了

以上说明总结起来就是:对于收到的RTP包在TransportFeedback RTCP receive delta列表中通过时间间隔记录到达时间,如果与前面包时间间隔小,那么使用1字节表示,否则2字节,超过最大取值范围,就另起新RTCP包了。

对于"Packet received, small delta"状态的包来说,receive delta最大值63.75ms,那么一秒时间跨度最少能标识1000/63.75~=16个包。由于receive delta为250us的倍数,所以一秒时间跨度最多能标识4000个包。

packet chunk以及receive delta的使用是为了尽可能减小RTCP包大小。packet chunk用到了不同编码方式,对于收到的RTP包才添加到达时间信息,而且是通过时间间隔的方式记录到达时间。

代码导读

在RemoteEstimatorProxy中处理RTP包的到达时间,构造Transport-cc报文,反馈给发送端。大概函数调用流程如下:

1
2
3
4
5
6
7
RemoteEstimatorProxy::IncomingPacket
             ↓
RemoteEstimatorProxy::Process
             ↓
RemoteEstimatorProxy::SendPeriodicFeedbacks
             ↓
RemoteEstimatorProxy::BuildFeedbackPacket

RemoteEstimatorProxy::IncomingPacket中,如果RTP包带有TransportSequenceNumber扩展,会记录该RTP包的到达时间,然后添加到构造的Transport-cc报文中。我们看下主要处理代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  if (header.extension.hasTransportSequenceNumber) {
    seq = unwrapper_.Unwrap(header.extension.transportSequenceNumber);
 
    if (send_periodic_feedback_) {
      if (periodic_window_start_seq_ &&
          packet_arrival_times_.lower_bound(*periodic_window_start_seq_) ==
              packet_arrival_times_.end()) {
        // Start new feedback packet, cull old packets.
        for (auto it = packet_arrival_times_.begin();
             it != packet_arrival_times_.end() && it->first < seq &&
             arrival_time_ms - it->second >= send_config_.back_window->ms();) {
          it = packet_arrival_times_.erase(it);
        }
      }
      if (!periodic_window_start_seq_ || seq < *periodic_window_start_seq_) {
        periodic_window_start_seq_ = seq;
      }
    }
 
    // We are only interested in the first time a packet is received.
    if (packet_arrival_times_.find(seq) != packet_arrival_times_.end())
      return;
 
    packet_arrival_times_[seq] = arrival_time_ms;
  }

在RTCPReceiver中处理收到的Transport-cc报文,然后送给TransportFeedbackObserver处理。大概函数调用流程如下

1
2
3
4
5
6
7
RTCPReceiver::IncomingPacket
              ↓
RTCPReceiver::TriggerCallbacksFromRtcpPacket
              ↓
TransportFeedbackObserver::OnTransportFeedback
              ↓
RtpTransportControllerSend::OnTransportFeedback

在webrtc::rtcp::TransportFeedback中负责TransportFeedback包的解析以及构造。

总结

本文介绍了WebRTC带宽估计用到的TransportSequenceNumber RTP报头扩展以及TransportFeedback RTCP,并分析了相关代码调用,熟悉这些有助于更好理解WebRTC中的带宽估计机制。

参考

[1] RTP Extensions for Transport-wide Congestion Control draft-holmer-rmcat-transport-wide-cc-extensions-01.https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01.

本文已收录到大话WebRTC专栏,更多精彩请访问《大话WebRTC》。

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
标签: WebRTC 网络 音视频
最后更新:2024年4月17日

Jeff

管理员——代码为剑,如痴如醉

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • 于吉太

    痴乎兄写得很透彻!

    2020年4月29日
    回复
  • Jeffrey

    兄弟请教个问题
    void Call::NotifyBweOfReceivedPacket(const RtpPacketReceived& packet,
    MediaType media_type) {
    auto it = receive_rtp_config_.find(packet.Ssrc());
    bool use_send_side_bwe =
    (it != receive_rtp_config_.end()) && it->second.use_send_side_bwe;
    我的这段代码的use_send_side_bwe 为啥一直返回false,明明双方的sdp有扩展twcc的
    这个为false导致如下:
    if (!use_send_side_bwe && header.extension.hasTransportSequenceNumber) {
    // Inconsistent configuration of send side BWE. Do nothing.
    // TODO(nisse): Without this check, we may produce RTCP feedback
    // packets even when not negotiated. But it would be cleaner to
    // move the check down to RTCPSender::SendFeedbackPacket, which
    // would also help the PacketRouter to select an appropriate rtp
    // module in the case that some, but not all, have RTCP feedback
    // enabled.
    return;
    }
    这样我的接收端收到twcc的包后就不能进行feedback回复了。。。不知道是啥原因

    2020年8月28日
    回复
  • Jeffrey

    具体是在call模块,处理rtp数据的时候

    2020年8月28日
    回复
    • Jeff

      @Jeffrey receive_rtp_config是在Call::CreateVideoReceiveStream中配置的,通过ReceiveRtpConfig(config)获取配置,通过如下判断use_send_side_bwe:
      bool UseSendSideBwe(const std::vector<RtpExtension>& extensions,
      bool transport_cc) {
      if (!transport_cc)
      return false;
      for (const auto& extension : extensions) {
      if (extension.uri == RtpExtension::kTransportSequenceNumberUri ||
      extension.uri == RtpExtension::kTransportSequenceNumberV2Uri)
      return true;
      }
      return false;
      }

      你可以看下这里哪里设置不对,再排查原因。

      2020年8月30日
      回复
  • deng

    写得挺好,走心了。。。

    2021年1月4日
    回复
  • deng

    你可以关注一下mediasoup,用mediasoup做服务器端转发模式更合适。
    webrtc peerconnection适合终端。

    2021年1月4日
    回复
  • Random

    感谢分享,写得很好,学习了

    2021年5月17日
    回复
  • Jeffrey

    再请教两个问题
    1.
    constexpr int kBaseScaleFactor =
    TransportFeedback::kDeltaScaleFactor * (1 << 8);
    constexpr int64_t kTimeWrapPeriodUs = (111 << 24) * kBaseScaleFactor;
    这个111是什么意思
    该段代码,transport_feedback.cc文件中
    2.
    packet_feedback.receive_time =
    current_offset_ + packet_offset.RoundDownTo(TimeDelta::Millis(1));
    twcc feed back的计算包的接收时间在发送端计算,这个
    current_offset_ 该值的取值是以第一次接收到的feedback包作为基准,那岂不是变成这里计算的rtp到达时间多算了rtt/2 ?
    上述代码在transport_feedback_adapter.cc的ProcessTransportFeedbackInner中

    2021年6月30日
    回复
    • Jeff

      @Jeffrey RTP时间问题已在另一个相同问题下答复

      2021年7月6日
      回复
  • 无知之徒

    第一个问题中111是1LL,不是三个1,这个地方主要是处理24位reference time回绕的问题

    2021年7月6日
    回复
  • 小胖子

    请教一个问题,在tcc的包里面的base sequence numbe应该是前面码流rtp包的扩展头里面的一系列transport sequence number。但是我用wireshark抓包的时候发现两个值对不上,我可以看到rtp包里面的扩展头在不断增加,但是tcc的包反馈的base sequence numbe和码流里面transport sequence number差距很大。举个例子:序号15013的包是码流包,他的rtp扩展头里面序号是0x028db。序号15014的包是tcc的包,但是base sequence number是0x5e60。我理解tcc的这个包有点延时性,但这个差距真的是太大了。不解~~

    2022年4月1日
    回复
  • sola

    如果 twcc 的rtcp反馈包丢了不少,发送端怎么靠这个估算接收端的码率.

    2023年8月9日
    回复
    • Jeff

      @sola 有个RobustThroughputEstimator类可以参考,反馈包丢失,会造成两个包间隔时间变大,也就是所谓的receive time gap,RobustThroughputEstimator会尽可能消除这种影响。

      2023年9月28日
      回复
  • 啊非

    reference time:3字节,表示参考时间,以64ms为单位,但是
    代码里面是 TransportFeedback::kDeltaScaleFactor * (1 << 8); 怎么理解?

    2024年12月30日
    回复
  • 啊非

    大神,请教一个问题:
    constexpr int kBaseScaleFactor =
    TransportFeedback::kDeltaScaleFactor * (1 << 8);
    constexpr int64_t kTimeWrapPeriodUs = (111 << 24) * kBaseScaleFactor;

    就是这里的代码里面是 TransportFeedback::kDeltaScaleFactor * (1 << 8); 怎么理解?

    2024年12月30日
    回复
    • 邱国禄

      @啊非 Receive Delta以0.25ms为单位,reference time以64ms为单位,kDeltaScaleFactor=0.25ms,kDeltaScaleFactor*(1<<8) = 0.25ms * 256 = 64ms。

      2025年2月17日
      回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    回复 Jeffrey 取消回复

    这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理。

    版权声明

    为支持原创,创作更好的文章,未经许可,禁止任何形式的转载与抄袭,如需转载请邮件私信!本人保留所有法定权利。违者必究!

    文章目录
    • RTP Header扩展
      • Transport sequence number
      • 代码导读
    • TransportFeedback RTCP
      • 报文格式
      • 代码导读
    • 总结
    • 参考
    最近评论
    ztt 发布于 1 个月前(04月05日) 你好,想看里面的视频和图片为什么没有显示呢?需要下flash吗还是什么。
    huowa222 发布于 2 个月前(03月26日) 同问
    邱国禄 发布于 3 个月前(02月17日) Receive Delta以0.25ms为单位,reference time以64ms为单位,kDe...
    啊非 发布于 4 个月前(12月30日) 大神,请教一个问题: constexpr int kBaseScaleFactor = Tran...
    啊非 发布于 4 个月前(12月30日) reference time:3字节,表示参考时间,以64ms为单位,但是 代码里面是 Trans...
    相关文章
    • WebRTC音视频传输基础:NAT穿透
    • WebRTC研究:丢包判断
    • WebRTC研究:RTP中的序列号以及时间戳比较
    • WebRTC研究:统计参数之往返时延
    • 音视频开发入门:视频基础

    COPYRIGHT © 2024 jianchihu.net. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang