WebRTC源码分析之RTP/RTCP(二)

WebRTC中RTP和RTCP共用一个UDP端口


WebRTC中的RTP和RTCP都使用udp传输,并且RTP和RTCP混合使用同一个udp端口,因为打通NAT本来就不是一件容易的事,如果还分开两个端口的话更增加程序复杂度和NAT打洞成功的难度。

WebRTC怎么区分RTP/RTCP包


webrtc/call/call.cc:

PacketReceiver::DeliveryStatus Call::DeliverPacket(
    MediaType media_type,
    rtc::CopyOnWriteBuffer packet,
    const PacketTime& packet_time) {
  RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_);
  if (RtpHeaderParser::IsRtcp(packet.cdata(), packet.size()))
    return DeliverRtcp(media_type, packet.cdata(), packet.size());

  return DeliverRtp(media_type, std::move(packet), packet_time);
}

既然RTP和RTCP都使用同一个UDP端口,那么就要区分出收到的UDP包是RTP还是RTCP包,在上面代码中IsRtcp判断了是否是RTCP包。

RTP/RTCP的相关代码在modules/rtp_rtcp目录下。

RtpHeaderParser::IsRtcp调用了RtpHeaderParser::RTCP()判断是否RTCP包:

webrtc/modules/rtp_rtcp/source/rtp_utility.cc:

bool RtpHeaderParser::RTCP() const {
  // 72 to 76 is reserved for RTP
  // 77 to 79 is not reserver but  they are not assigned we will block them
  // for RTCP 200 SR  == marker bit + 72
  // for RTCP 204 APP == marker bit + 76
  /*
  *       RTCP
  *
  * FIR      full INTRA-frame request             192     [RFC2032]   supported
  * NACK     negative acknowledgement             193     [RFC2032]
  * IJ       Extended inter-arrival jitter report 195     [RFC-ietf-avt-rtp-toff
  * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
  * SR       sender report                        200     [RFC3551]   supported
  * RR       receiver report                      201     [RFC3551]   supported
  * SDES     source description                   202     [RFC3551]   supported
  * BYE      goodbye                              203     [RFC3551]   supported
  * APP      application-defined                  204     [RFC3551]   ignored
  * RTPFB    Transport layer FB message           205     [RFC4585]   supported
  * PSFB     Payload-specific FB message          206     [RFC4585]   supported
  * XR       extended report                      207     [RFC3611]   supported
  */

  /* 205       RFC 5104
   * FMT 1      NACK       supported
   * FMT 2      reserved
   * FMT 3      TMMBR      supported
   * FMT 4      TMMBN      supported
   */

  /* 206      RFC 5104
  * FMT 1:     Picture Loss Indication (PLI)                      supported
  * FMT 2:     Slice Lost Indication (SLI)
  * FMT 3:     Reference Picture Selection Indication (RPSI)
  * FMT 4:     Full Intra Request (FIR) Command                   supported
  * FMT 5:     Temporal-Spatial Trade-off Request (TSTR)
  * FMT 6:     Temporal-Spatial Trade-off Notification (TSTN)
  * FMT 7:     Video Back Channel Message (VBCM)
  * FMT 15:    Application layer FB message
  */

//RTCP最小4字节(kRtcpMinHeaderLength)
  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
  if (length < kRtcpMinHeaderLength) {
    return false;
  }

//RTCP版本号必须等于2(kRtcpExpectedVersion)
  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
  if (V != kRtcpExpectedVersion) {
    return false;
  }

  const uint8_t payloadType = _ptrRTPDataBegin[1];
  switch (payloadType) {
    case 192:
      return true;
    case 193:
      // not supported
      // pass through and check for a potential RTP packet
      return false;
    case 195:
    case 200:
    case 201:
    case 202:
    case 203:
    case 204:
    case 205:
    case 206:
    case 207:
      return true;
    default:
      return false;
  }
}

RTP的第二个字节是:
标记位(M):1比特
有效载荷类型(PT):7比特

RTCP的第二个字节是包类型(PT):8比特

如果第二个字节的值为200,换算成二进制为11001000。
如果是RTCP包则PT=SR
如果是RTP包则:标记位(M)=1,PT=72
但是72-76被规定为RTCP保留使用,所以不可能是RTP包。
具体的RTP Payload types参考:
https://www.ietf.org/assignments/rtp-parameters/rtp-parameters.xml

所以PT等于200-204的值都为RTCP包。
而PT为205-207时,对应RTP为77-79,虽然不是保留给RTCP使用,但是在RTP中也没有定义使用,而RTCP有用到这些值,所以WebRTC中把其当做RTCP。

PT=192,换算为RTP为64
PT=193,换算为RTP为65
PT=195,换算为RTP为66
在RTP中PT值为35-71都没有明确定义使用,但是当等于193,WebRTC认为不是RTCP包,而在RTP中会进一步解析此值。

而在webrtc/pc/rtptransport.cc中判断PT值为63到96之间时直接当做RTCP:

webrtc/pc/rtptransport.cc:

// Check the RTP payload type.  If 63 < payload type < 96, it's RTCP.
// For additional details, see http://tools.ietf.org/html/rfc5761.
bool IsRtcp(const char* data, int len) {
  if (len < 2) {
    return false;
  }
  char pt = data[1] & 0x7F;
  return (63 < pt) && (pt < 96);
}

这个IsRtcp方法只在同一个文件中的void RtpTransport::OnReadPacket里被调用。

你可能感兴趣的:(WebRTC源码分析之RTP/RTCP(二))