webrtc中的FEC配置

void VideoSendStreamImpl::ConfigureProtection() {
  RTC_DCHECK_RUN_ON(worker_queue_);

  // Consistency of FlexFEC parameters is checked in MaybeCreateFlexfecSender.
  const bool flexfec_enabled = (flexfec_sender_ != nullptr);

  // Consistency of NACK and RED+ULPFEC parameters is checked in this function.
  const bool nack_enabled = config_->rtp.nack.rtp_history_ms > 0;
  int red_payload_type = config_->rtp.ulpfec.red_payload_type;
  int ulpfec_payload_type = config_->rtp.ulpfec.ulpfec_payload_type;

  // Shorthands.
  auto IsRedEnabled = [&]() { return red_payload_type >= 0; };
  auto DisableRed = [&]() { red_payload_type = -1; };
  auto IsUlpfecEnabled = [&]() { return ulpfec_payload_type >= 0; };
  auto DisableUlpfec = [&]() { ulpfec_payload_type = -1; };

  // If enabled, FlexFEC takes priority over RED+ULPFEC.
  if (flexfec_enabled) {
    // We can safely disable RED here, because if the remote supports FlexFEC,
    // we know that it has a receiver without the RED/RTX workaround.
    // See http://crbug.com/webrtc/6650 for more information.
    if (IsRedEnabled()) {
      LOG(LS_INFO) << "Both FlexFEC and RED are configured. Disabling RED.";
      DisableRed();
    }
    if (IsUlpfecEnabled()) {
      LOG(LS_INFO)
          << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC.";
      DisableUlpfec();
    }
  }

  // Payload types without picture ID cannot determine that a stream is complete
  // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance)
  // is a waste of bandwidth since FEC packets still have to be transmitted.
  // Note that this is not the case with FlexFEC.
  if (nack_enabled && IsUlpfecEnabled() &&
      !PayloadTypeSupportsSkippingFecPackets(
          config_->encoder_settings.payload_name)) {
    LOG(LS_WARNING)
        << "Transmitting payload type without picture ID using "
           "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets "
           "also have to be retransmitted. Disabling ULPFEC.";
    DisableUlpfec();
  }

  // Verify payload types.
  //
  // Due to how old receivers work, we need to always send RED if it has been
  // negotiated. This is a remnant of an old RED/RTX workaround, see
  // https://codereview.webrtc.org/2469093003.
  // TODO(brandtr): This change went into M56, so we can remove it in ~M59.
  // At that time, we can disable RED whenever ULPFEC is disabled, as there is
  // no point in using RED without ULPFEC.
  if (IsRedEnabled()) {
    RTC_DCHECK_GE(red_payload_type, 0);
    RTC_DCHECK_LE(red_payload_type, 127);
  }
  if (IsUlpfecEnabled()) {
    RTC_DCHECK_GE(ulpfec_payload_type, 0);
    RTC_DCHECK_LE(ulpfec_payload_type, 127);
    if (!IsRedEnabled()) {
      LOG(LS_WARNING)
          << "ULPFEC is enabled but RED is disabled. Disabling ULPFEC.";
      DisableUlpfec();
    }
  }

  for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
    // Set NACK.
    rtp_rtcp->SetStorePacketsStatus(
        true,
        kMinSendSidePacketHistorySize);
    // Set RED/ULPFEC information.
    for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
      rtp_rtcp->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
    }
  }

  // Currently, both ULPFEC and FlexFEC use the same FEC rate calculation logic,
  // so enable that logic if either of those FEC schemes are enabled.
  protection_bitrate_calculator_.SetProtectionMethod(
      flexfec_enabled || IsUlpfecEnabled(), nack_enabled);
}

 

简单说明:

如果用 flexfec_enabled, 那么禁用  Red 和 Ulpfec,     DisableRed();     DisableUlpfec();

 

webrtc中,flex fec还属于草案,默认开启的是Ulpfec;

 

关于webrtc中的Ulpfec可以参考这篇文章:

《ULPFEC在WebRTC中的实现》

https://www.jianshu.com/p/06a27ebacec7?from=timeline

 

ULPFEC报文可采取两种方式发送:1)使用独立的RTP流发送;2)封装在RED报文中随源媒体数据一起发送。WebRTC采用第二种方式。RED(Redundant Coding)是针对RTP负载数据的二次封装,所以叫冗余编码,其定义在RFC2198[5]中。RED有两种数据封装格式:Primary Data Block和Redundant Data Block


 

 

丢包重传的方式 nack 和 rtx;

from: https://blog.csdn.net/sonysuqin/article/details/82021185

正文
NACK、RTX是WebRTC里丢包重传策略,两个策略之间有一定的联系。
NACK:接收端通过RTCP将丢包的序列号通知给发送端,让发送端重传该包。
RTX:发送端在新的SSRC上发送重传包或者冗余包。

两者均需要通过sdp协商开启,在支持的服务端(例如Janus)修改SDP即可开启。

要点
重传包不一定通过RTX发送;
RTX包不一定用来重传丢失的包。
解释
在发送端收到NACK后,要重发接收端丢掉的包,发送的模式有两种:

RTX模式
在接收端通过SDP使能发送端的RTX以后,重发的包封装到RTX包里发送,RTX包与原RTP有不同的SSRC,这样有助于避免SRTP的重放攻击,也能让接收端更好的估算带宽;
普通模式
在没有使能RTX时,发送端只是简单的重发原来的RTP包,这种模式会影响接收端的RTCP统计,比如会出现负的丢包率。
另外,RTX包有两种

收到NACK重发的包
如上述;
发送端发送的冗余Padding包
发送端的初始码率在达不到目标码率的情况下,会通过发送RTX包来补充,以能够逼近目标码率,当然这个机制必须启用RTX才能激活。因此,接收端可能会收到两种RTX包,一种是被NACK触发的,一种是发送端用来补充发送码率的冗余包
 

 

《webrtc源码之nack&&rtx详解》

from:https://www.jianshu.com/p/864bd1e27243

1、nack协商

m=video 9 RTP/AVPF 96 97 98 99 100 101127 122 108 109 123

a=rtpmap:96 H264/90000

a=rtcp-fb:96 goog-remb

a=rtcp-fb:96 transport-cc

a=rtcp-fb:96 ccm fir

a=rtcp-fb:96 nack

a=rtcp-fb:96 nack pli

a=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f

a=rtpmap:97 rtx/90000

a=fmtp:97 apt=96

video协商为h264(payload type=96)

从sdp可得到:

1)profile-level-id=42001f

      Profile: 66(hex: 42)

      Level: 3.1(hex:1f)转成十进制,再除以10

2)packetization-mode=1

   表示I帧会拆分成多个rtp包发送,对于264来说,rtppayload的第一个字节(0x7C)的低5bit为(11100),十进制为28,代表此nalutype为FU-A,多包封装类型。

3)RTP/AVPF

   AVPF中的F表示支持RTCP的传输层保护,S表示安全保护(SRTP)

4) a=fmtp:97 apt=96

   表示96类型的rtp包的重传包采用97的payloadtype的rtx包保护,rtx包的rtp header中的sequence num与rtp不一致,但timestamp一致。

   Rtx包的payload的前两个字节为原重传rtp包的rtp sequencenum

2、webrtcpeerconnection_client项目修改项

1)去掉srtp

    a) peerconnectionFactory的setOption接口关闭 encryption选项

      webrtc::PeerConnectionFactoryInterface::Optionsoptions;

   options.disable_encryption=true;

  peer_connection_factory_->SetOptions(options);

  b) peer_connection_factory_->CreatePeerConnection接口关闭dtls srtp选项

 webrtc::PeerConnectionInterface::RTCConfigurationconfig;

 config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;

 config.enable_dtls_srtp= false;

2)去掉FEC

增加关闭FEC的参数

webrtc::field_trial::InitFieldTrialsFromString(FLAG_force_fieldtrials)

FLAG_force_fieldtrials = WebRTC-DisableUlpFecExperiment/Enabled/

3、wireshark抓包分析

1)rtx_rtp.pcapng为20%随机丢包下的webrtc p2p抓包

过滤条件:(ip.src==10.25.8.112 and(rtp.p_type==96 or rtp.p_type==97)) or (rtcp and ip.dst==10.25.8.112 andrtcp.rtpfb.fmt == 1)

rtcp.rtpfb.fmt == 1代表nack报文

2)nack报文结构

81 cd 00 03 a5 1f d8 4a 52 5e 1a 85 34 0f 00 00

a) rtcp header 4bytes(81 cd 00 03)

   100 00001 (81)第一个字节

      高2 bit(10)为vesion应为2

   1bit表示rtcp是否补齐(padding) 0为不需要补齐,为1时,rtcp payload的最后一个字节的值为 paddingsize

  5bit表示rtcp feedback message type(fmt)值为1

     11001101 (cd)第二个字节

   第二个字节表示packet type,值为205

  Packet type(205)和fmt(1)确定此报文为nack报文

   (00 03)第三、四字节

   第三个字节表示rtcp的长度(不包括rtcp header的4 bytes)nack报文长度恒为16(3*4+4)

b) Nack payload(a5 1f d8 4a 52 5e 1a 8534 0f 00 00)

  4 bytes sender SSRC(a5 1f d8 4a),发送RTCP的track的rtp ssrc,如果为(recvonly),此值为0

  4 bytes media source SSRC(52 5e 1a 85),请求重传包对应的rtp ssrc

  2 bytes rtcp transport feedback nack pid(34 0f),确定丢包的起始rtp sequenceNum(13327)

  2 bytes rtcp transport feedback nack bitmask(0000),由起始pid开始的16个包组的丢包情况,此值是转成binary的掩码,bit为1表示丢包,00 00表示只有pid对应的包丢失。

3)rtx重传包

Rtx原理:重发的包封装到RTX包里发送,RTX包与原RTP有不同的SSRC,不同的rtpseq,但是timestamp与丢失包的时间戳相同。

  Rtx优势:rtp重传包在带宽估计时不计入运算,使用rtx比较方便,不使用rtx统计丢包率有时会出现负值

   Rtxpayload:前两个字节代表丢失包的rtp seq,因此rtx包比丢失的rtp包多2个字节

4)webrtc中rtp发送端处理RTCP NACK报文过程见“发送端处理RTCPNACK报文过程.pdf”

5)webrtc中rtp接收端发现丢包,并发送nack请求过程见“rtp接收端发送nack过程.pdf”

 

 

《WebRTC中的前向纠错编码 - Red Packet》 同时可以参考一下其他RED格式文章;

https://blog.csdn.net/volvet/article/details/53573359

你可能感兴趣的:(WebRTC)