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
里被调用。