WebRTC中RTCP协议详解
@TOC
</font>
<hr style=” border:solid; width:100px; height:1px;” color=#000000 size=1”>
WebRTC中RTCP协议详解 WebRTC专题开嗨鸭 !!!一、 WebRTC 线程模型
2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用
二、 WebRTC媒体协商
1、WebRTC媒体协商之SDP中JsepSessionDescription类结构分析
三、 WebRTC 音频数据采集
四、 WebRTC 音频引擎(编解码和3A算法)
五、 WebRTC 视频数据采集
六、 WebRTC 视频引擎( 编解码)
七、 WebRTC 网络传输
2、WebRTC的ICE之Dtls/SSL/TLSv1.x协议详解
八、 WebRTC服务质量(Qos)
3、WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传
九、 NetEQ
十、 Simulcast与SVC
前言
<font color=#999AAA >RTCP包 </font>
一共1500字节(网络最大包的大小)
- Mac Header:14字节
- Ip Header : 20字节
- UDP Header:8字节
- Data: 可变长度
- Mac Tailer:4字节
<hr style=” border:solid; width:100px; height:1px;” color=#000000 size=1”>
<font color=#999AAA >提示:以下是本篇文章正文内容,下面案例可供参考
一、RTCP Header 头结构
1、 RTCP Header 对应的数据结构
/* Struct for RTCP common header. */
struct CommonHeader
{
#if defined(MS_LITTLE_ENDIAN)
uint8_t count : 5; // 一个包中Report Block个数
uint8_t padding : 1;// 填充标识, 最后一个填充字节是()个数
uint8_t version : 2;
#elif defined(MS_BIG_ENDIAN)
uint8_t version : 2;
uint8_t padding : 1;
uint8_t count : 5;
#endif
uint8_t packetType : 8; // 不同RTCP包的类型
uint16_t length : 16; // 16位,包长度(包括头)。[数值为(N-1)个4字节]
};
2、 RTCP Header 说明
3、 RTCP Header 在代码中解析的流程的为代码
Packet* Packet::Parse(const uint8_t* data, size_t len)
{
MS_TRACE();
// First, Currently parsing and Last RTCP packets in the compound packet.
Packet* first{ nullptr };
Packet* current{ nullptr };
Packet* last{ nullptr };
while (len > 0u)
{
if (!Packet::IsRtcp(data, len))
{
MS_WARN_TAG(rtcp, "data is not a RTCP packet");
return first;
}
auto* header = const_cast<CommonHeader*>(reinterpret_cast<const CommonHeader*>(data));
// 这一步 ??? 是不是很有问题啊 ========> 数据的 要加上头的大小的哈
size_t packetLen = static_cast<size_t>(ntohs(header->length) + 1) * 4;
if (len < packetLen)
{
MS_WARN_TAG(
rtcp,
"packet length exceeds remaining data [len:%zu, "
"packet len:%zu]",
len,
packetLen);
return first;
}
switch (Type(header->packetType))
{
case Type::SR:
{
// 1. PT= 200 发送反馈包
current = SenderReportPacket::Parse(data, packetLen);
if (!current)
break;
if (header->count > 0)
{
Packet* rr = ReceiverReportPacket::Parse(data, packetLen, current->GetSize());
if (!rr)
break;
current->SetNext(rr);
}
break;
}
case Type::RR:
{
//2. PT = 201 接受多少包发送给对端
current = ReceiverReportPacket::Parse(data, packetLen);
break;
}
case Type::SDES:
{
// 3. PT = 202 对媒体源的描述
current = SdesPacket::Parse(data, packetLen);
break;
}
case Type::BYE:
{
// 4. PT = 203 不需要传输的数据
current = ByePacket::Parse(data, packetLen);
break;
}
case Type::APP:
{
// 5. PT = 204 应用自定义信息
current = nullptr;
break;
}
case Type::RTPFB:
{
// 6. PT = 205 反馈信息
current = FeedbackRtpPacket::Parse(data, packetLen);
break;
}
case Type::PSFB:
{
// 7. PT= 206 负载情况 反馈信息
current = FeedbackPsPacket::Parse(data, packetLen);
break;
}
case Type::XR:
{
// 8. PT = 207 扩展头
current = ExtendedReportPacket::Parse(data, packetLen);
break;
}
default:
{
MS_WARN_TAG(rtcp, "unknown RTCP packet type [packetType:%" PRIu8 "]", header->packetType);
current = nullptr;
}
}
if (!current)
{
std::string packetType = Type2String(Type(header->packetType));
if (Type(header->packetType) == Type::PSFB)
{
packetType +=
" " + FeedbackPsPacket::MessageType2String(FeedbackPs::MessageType(header->count));
}
else if (Type(header->packetType) == Type::RTPFB)
{
packetType +=
" " + FeedbackRtpPacket::MessageType2String(FeedbackRtp::MessageType(header->count));
}
MS_WARN_TAG(rtcp, "error parsing %s Packet", packetType.c_str());
return first;
}
data += packetLen;
len -= packetLen;
if (!first)
first = current;
else
last->SetNext(current);
last = current->GetNext() != nullptr ? current->GetNext() : current;
}
return first;
}
二、 RTCP 有哪些 Type类型
1、 RTCP SR
①、 Sender Information block
②、SR 数据结构
/* Struct for RTCP sender report. */
struct Header
{
uint32_t ssrc; // 源
uint32_t ntpSec; // 网络时间戳, 用于不同源之间的同步
uint32_t ntpFrac;
uint32_t rtpTs; // 相于时间戳,于RTP包时间戳一致
uint32_t packetCount; //总发送包数
uint32_t octetCount; // 总发送的数据量
};
③、 接受端的处理
void RtpStreamSend::ReceiveRtcpReceiverReport(RTC::RTCP::ReceiverReport* report)
{
MS_TRACE();
/* Calculate RTT. */
// Get the NTP representation of the current timestamp.
uint64_t nowMs = DepLibUV::GetTimeMs();
auto ntp = Utils::Time::TimeMs2Ntp(nowMs);
// Get the compact NTP representation of the current timestamp.
uint32_t compactNtp = (ntp.seconds & 0x0000FFFF) << 16;
compactNtp |= (ntp.fractions & 0xFFFF0000) >> 16;
uint32_t lastSr = report->GetLastSenderReport();
uint32_t dlsr = report->GetDelaySinceLastSenderReport();
// RTT in 1/2^16 second fractions.
uint32_t rtt{ 0 };
// If no Sender Report was received by the remote endpoint yet, ignore lastSr
// and dlsr values in the Receiver Report.
if (lastSr && dlsr && (compactNtp > dlsr + lastSr))
rtt = compactNtp - dlsr - lastSr;
// RTT in milliseconds.
this->rtt = static_cast<float>(rtt >> 16) * 1000;
this->rtt += (static_cast<float>(rtt & 0x0000FFFF) / 65536) * 1000;
if (this->rtt > 0.0f)
this->hasRtt = true;
this->packetsLost = report->GetTotalLost();
this->fractionLost = report->GetFractionLost();
// Update the score with the received RR.
UpdateScore(report);
}
2、Receiver report block
3、 RTCP SDES
包含CNAME项的SDES包必须包含在美国组合RTCP包中。SDES包可能包括其他源描述项,这要根据特别的应用需要,并同时考虑带宽限制
①、 SDES说明
1、SC: SSRC/CSRC数量 2、Item: 采用TLV存放数据 3、 CNAME: SSRC的规范名
②、 SDES item
③、 WebRTC中使用SDES
- 媒体协商时,为每个源(SSRC)设置了一个CNAME
....
a=ssrc:3121455836 cname:UrMYhDY/S2YpnPSN
....
- 通过RTCP SDES 确认CNAME与SSRC的关系
4、RTCP BYE
不需要ssrc流了 就写ssrc放到ssrc这边 发送方就不会发送哈
5、 RTCP APP
应用的信息
6、 RTCP FB Type
7、 RTCP RTPFB Type
8、 RTCP PSFB Type
9、 RTCP FB Type
总结:
WebRTC源码分析地址:https://github.com/chensongpoixs/cwebrtc