WebRTC专题开嗨鸭 !!!
一、 WebRTC 线程模型
1、WebRTC中线程模型和常见线程模型介绍
2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用
二、 WebRTC媒体协商
1、WebRTC媒体协商之SDP中JsepSessionDescription类结构分析
2、WebRTC媒体协商之CreatePeerConnectionFactory、CreatePeerConnection、CreateOffer
3、WebRTC之证书(certificate)生成的时机分析
4、WebRTC源码之RtpTransceiver添加视频轨道的AddTrack函数中桥接模式的流程分析
三、 WebRTC 音频数据采集
1、WebRTC源码之音频设备播放流程源码分析
2、WebRTC源码之音频设备的录制流程源码分析
四、 WebRTC 音频引擎(编解码和3A算法)
五、 WebRTC 视频数据采集
六、 WebRTC 视频引擎( 编解码)
七、 WebRTC 网络传输
1、WebRTC的ICE之STUN协议
2、WebRTC的ICE之Dtls/SSL/TLSv1.x协议详解
八、 WebRTC服务质量(Qos)
1、WebRTC中RTCP协议详解
2、WebRTC中RTP协议详解
3、WebRTC之NACK、RTX 在什么时机判断丢包发送NACK请求和RTX丢包重传
4、WebRTC源码之视频质量统计数据的数据结构分析
5、WebRTC源码之RTCPReceiver源码分析
九、 NetEQ
十、 Simulcast与SVC
WebRTC是音视频行业的标杆, 如果要学习音视频, WebRTC是进入音视频行业最好方法, 里面可以有成熟方案, 例如:音频中3A 算法、网络评估、自适应码流、Simulcast、SVC等等 , 非常适合刚刚进入音视频行业小伙伴哈_ 我也是哦, 以后再音视频行业长期打算的小伙伴的学习项目。 里面有大量知识点
提示:以下是本篇文章正文内容,下面案例可供参考
AllocationSequence::OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us)
UDPPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& remote_addr, int64_t packet_time_us)
UDPPort::OnReadPacket(rtc::AsyncPacketSocket* socket, const char* data, size_t size, const rtc::SocketAddress& remote_addr, const int64_t& packet_time_us)
onnection::OnReadPacket(const char* data, size_t size, int64_t packet_time_us)
P2PTransportChannel::OnReadPacket(Connection* connection, const char* data, size_t len, int64_t packet_time_us)
DtlsTransport::OnReadPacket(rtc::PacketTransportInternal* transport, const char* data, size_t size, const int64_t& packet_time_us, int flags)
RtpTransport::OnReadPacket(rtc::PacketTransportInternal* transport, const char* data, size_t len, const int64_t& packet_time_us, int flags)
SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet, int64_t packet_time_us)
RtpTransport::DemuxPacket(rtc::CopyOnWriteBuffer packet, int64_t packet_time_us)
RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet)
BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet)
BaseChannel::OnPacketReceived(bool rtcp, const rtc::CopyOnWriteBuffer& packet, int64_t packet_time_us)
invoker_.AsyncInvoke<void>(
RTC_FROM_HERE, worker_thread_,
Bind(&BaseChannel::ProcessPacket, this, rtcp, packet, packet_time_us));
]
// received
BaseChannel::ProcessPacket(bool rtcp, const rtc::CopyOnWriteBuffer& packet, int64_t packet_time_us)
WebRtcVideoChannel::OnRtcpReceived
Call::DeliverPacket
Call::DeliverRtcp
VideoSendStream::DeliverRtcp
VideoSendStreamImpl::DeliverRtcp
RtpVideoSender::DeliverRtcp
ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet, const size_t length)
RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) --> RTCPReceiver模块接受数据并读取数据格式
RTCPReceiver::TriggerCallbacksFromRtcpPacket(const PacketInformation& packet_information)
RtpTransportControllerSend::OnTransportFeedback(const rtcp::TransportFeedback& feedback)
GoogCcNetworkController::OnTransportPacketsFeedback(TransportPacketsFeedback report)
void RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
if (packet_size == 0) {
RTC_LOG(LS_WARNING) << "Incoming empty RTCP packet";
return;
}
// TODO@chensong 20220909 根据对端反馈信息处理
// TODO@chensong 2022-10-19 解析RTCP 数据包的格式
PacketInformation packet_information;
if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information)) {
return;
}
TriggerCallbacksFromRtcpPacket(packet_information);
}
CommonHeader rtcp_block;
for (const uint8_t* next_block = packet_begin; next_block != packet_end; next_block = rtcp_block.NextPacket())
{
ptrdiff_t remaining_blocks_size = packet_end - next_block;
RTC_DCHECK_GT(remaining_blocks_size, 0);
//rtcp包有统一头格式读取方法
if (!rtcp_block.Parse(next_block, remaining_blocks_size))
{
if (next_block == packet_begin)
{
// Failed to parse 1st header, nothing was extracted from this packet.
RTC_LOG(LS_WARNING) << "Incoming invalid RTCP packet";
return false;
}
++num_skipped_packets_;
break;
}
***
}
// webrtc\src\modules\rtp_rtcp\source\rtcp_packet\common_header.cc
// 0 1 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 0 |V=2|P| C/F |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 1 | Packet Type |
// ----------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 2 | length |
// --------------------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// TODO@chensong 2022-12-25
// Common header for all RTCP packets, 4 octets.
bool CommonHeader::Parse(const uint8_t* buffer, size_t size_bytes)
{
const uint8_t kVersion = 2;
if (size_bytes < kHeaderSizeBytes)
{
RTC_LOG(LS_WARNING)
<< "Too little data (" << size_bytes << " byte"
<< (size_bytes != 1 ? "s" : "")
<< ") remaining in buffer to parse RTCP header (4 bytes).";
return false;
}
// rtcp 版本
uint8_t version = buffer[0] >> 6;
if (version != kVersion)
{
RTC_LOG(LS_WARNING) << "Invalid RTCP header: Version must be "
<< static_cast<int>(kVersion) << " but was "
<< static_cast<int>(version);
return false;
}
// 是否有扩展的数据包
bool has_padding = (buffer[0] & 0x20) != 0;
count_or_format_ = buffer[0] & 0x1F;
// rtcp 包类型
packet_type_ = buffer[1];
// rtcp 包中数据大小 读取4个字节 就是32bit
payload_size_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) * 4;
// rtcp 包中实际数据开始地址的位置
payload_ = buffer + kHeaderSizeBytes /*default kHeaderSizeBytes = 4*/;
padding_size_ = 0;
if (size_bytes < kHeaderSizeBytes + payload_size_)
{
RTC_LOG(LS_WARNING) << "Buffer too small (" << size_bytes
<< " bytes) to fit an RtcpPacket with a header and "
<< payload_size_ << " bytes.";
return false;
}
if (has_padding)
{
if (payload_size_ == 0)
{
RTC_LOG(LS_WARNING)
<< "Invalid RTCP header: Padding bit set but 0 payload "
"size specified.";
return false;
}
padding_size_ = payload_[payload_size_ - 1];
if (padding_size_ == 0)
{
RTC_LOG(LS_WARNING)
<< "Invalid RTCP header: Padding bit set but 0 padding "
"size specified.";
return false;
}
if (padding_size_ > payload_size_)
{
RTC_LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
<< padding_size_ << ") for a packet payload size of "
<< payload_size_ << " bytes.";
return false;
}
payload_size_ -= padding_size_;
}
return true;
}
然后根据packet_type的不同类型进行处理
Sender report (SR) (RFC 3550).
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| RC | PT=SR=200 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 | SSRC of sender |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
4 | NTP timestamp, most significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 | NTP timestamp, least significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 | RTP timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | sender's packet count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | sender's octet count |
24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
bool SenderReport::Parse(const CommonHeader& packet)
{
RTC_DCHECK_EQ(packet.type(), kPacketType);
const uint8_t report_block_count = packet.count();
if (packet.payload_size_bytes() < kSenderBaseLength/*24*/ + report_block_count * ReportBlock::kLength /*24*/)
{
RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data.";
return false;
}
// Read SenderReport header.
const uint8_t* const payload = packet.payload();
// 发送端ssrc
sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&payload[0]);
uint32_t secs = ByteReader<uint32_t>::ReadBigEndian(&payload[4]);
uint32_t frac = ByteReader<uint32_t>::ReadBigEndian(&payload[8]);
ntp_.Set(secs, frac);
// rtp 网络时间戳
rtp_timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&payload[12]);
// 发送的总包数
sender_packet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[16]);
// 总共发送数据包量
sender_octet_count_ = ByteReader<uint32_t>::ReadBigEndian(&payload[20]);
report_blocks_.resize(report_block_count);
const uint8_t* next_block = payload + kSenderBaseLength;
for (ReportBlock& block : report_blocks_)
{
bool block_parsed = block.Parse(next_block, ReportBlock::kLength);
RTC_DCHECK(block_parsed);
next_block += ReportBlock::kLength;
}
// Double check we didn't read beyond provided buffer.
RTC_DCHECK_LE(next_block - payload, static_cast<ptrdiff_t>(packet.payload_size_bytes()));
return true;
}
From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
RTCP report block (RFC 3550).
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
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
0 | SSRC_1 (SSRC of first source) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | fraction lost | cumulative number of packets lost |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 | extended highest sequence number received |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 | interarrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | last SR (LSR) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | delay since last SR (DLSR) |
24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
bool ReportBlock::Parse(const uint8_t* buffer, size_t length)
{
RTC_DCHECK(buffer != nullptr);
if (length < ReportBlock::kLength)
{
RTC_LOG(LS_ERROR) << "Report Block should be 24 bytes long";
return false;
}
// 接收到的媒体源ssrc
source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[0]);
// TODO@chensong 2022-10-19 丢包率 fraction_lost
fraction_lost_ = buffer[4];
// 接收开始丢包总数, 迟到包不算丢包,重传有可以导致负数
cumulative_lost_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[5]);
// 低16位表示收到的最大seq,高16位表示seq循环次数
extended_high_seq_num_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
// rtp包到达时间间隔的统计方差
jitter_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[12]);
// ntp时间戳的中间32位
last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[16]);
// 记录上一个接收SR的时间与上一个发送SR的时间差
delay_since_last_sr_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[20]);
return true;
}
大致是包RTCP report block包数据进行再加工 重要处理rtt, 然后把 RTCP report blocb包全部数据包抛到gcc模块中去
void RTCPReceiver::HandleSenderReport(const CommonHeader& rtcp_block, PacketInformation* packet_information)
{
rtcp::SenderReport sender_report;
if (!sender_report.Parse(rtcp_block))
{
++num_skipped_packets_;
return;
}
const uint32_t remote_ssrc = sender_report.sender_ssrc();
packet_information->remote_ssrc = remote_ssrc;
UpdateTmmbrRemoteIsAlive(remote_ssrc);
// Have I received RTP packets from this party?
if (remote_ssrc_ == remote_ssrc)
{
// Only signal that we have received a SR when we accept one.
packet_information->packet_type_flags |= kRtcpSr;
remote_sender_ntp_time_ = sender_report.ntp();
remote_sender_rtp_time_ = sender_report.rtp_timestamp();
last_received_sr_ntp_ = TimeMicrosToNtp(clock_->TimeInMicroseconds());
}
else
{
// We will only store the send report from one source, but
// we will store all the receive blocks.
packet_information->packet_type_flags |= kRtcpRr;
}
for (const rtcp::ReportBlock& report_block : sender_report.report_blocks())
{
HandleReportBlock(report_block, packet_information, remote_ssrc);
}
}
void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, PacketInformation* packet_information, uint32_t remote_ssrc)
{
// This will be called once per report block in the RTCP packet.
// We filter out all report blocks that are not for us.
// Each packet has max 31 RR blocks.
//
// We can calc RTT if we send a send report and get a report block back.
// |report_block.source_ssrc()| is the SSRC identifier of the source to
// which the information in this reception report block pertains.
// Filter out all report blocks that are not for us.
// TODO@chensong 2022-12-26
//这将在RTCP数据包中的每个报告块调用一次。
//我们过滤掉所有不适合我们的报告块。
//每个数据包最多有31个RR块。
//如果我们发送发送报告并得到报告块,我们可以计算RTT。
//|report_block.source_ssrc()|是源的ssrc标识符
//该接收报告块中的信息与之相关。
//过滤掉所有不适合我们的报告块。
if (registered_ssrcs_.count(report_block.source_ssrc()) == 0)
{
return;
}
last_received_rb_ms_ = clock_->TimeInMilliseconds();
// TODO@chensong 2022-12-26 没有该ssrc在received_report_blocks_中map中正好插入
ReportBlockWithRtt* report_block_info = &received_report_blocks_[report_block.source_ssrc()][remote_ssrc];
report_block_info->report_block.sender_ssrc = remote_ssrc;
report_block_info->report_block.source_ssrc = report_block.source_ssrc();
report_block_info->report_block.fraction_lost = report_block.fraction_lost();
report_block_info->report_block.packets_lost = report_block.cumulative_lost_signed();
if (report_block.extended_high_seq_num() > report_block_info->report_block.extended_highest_sequence_number)
{
// We have successfully delivered new RTP packets to the remote side after
// the last RR was sent from the remote side.
last_increased_sequence_number_ms_ = clock_->TimeInMilliseconds();
}
report_block_info->report_block.extended_highest_sequence_number = report_block.extended_high_seq_num();
report_block_info->report_block.jitter = report_block.jitter();
report_block_info->report_block.delay_since_last_sender_report = report_block.delay_since_last_sr();
report_block_info->report_block.last_sender_report_timestamp = report_block.last_sr();
int64_t rtt_ms = 0;
uint32_t send_time_ntp = report_block.last_sr();
// RFC3550, section 6.4.1, LSR field discription states:
// If no SR has been received yet, the field is set to zero.
// Receiver rtp_rtcp module is not expected to calculate rtt using
// Sender Reports even if it accidentally can.
// TODO(nisse): Use this way to determine the RTT only when |receiver_only_|
// is false. However, that currently breaks the tests of the
// googCaptureStartNtpTimeMs stat for audio receive streams. To fix, either
// delete all dependencies on RTT measurements for audio receive streams, or
// ensure that audio receive streams that need RTT and stats that depend on it
// are configured with an associated audio send stream.
if (send_time_ntp != 0)
{
uint32_t delay_ntp = report_block.delay_since_last_sr();
// Local NTP time.
// 微妙
uint32_t receive_time_ntp = CompactNtp(TimeMicrosToNtp(clock_->TimeInMicroseconds()));
// RTT in 1/(2^16) seconds.
uint32_t rtt_ntp = receive_time_ntp - delay_ntp /*发送时间与接收到时间差值*/ - send_time_ntp;
// Convert to 1/1000 seconds (milliseconds).
// 微妙转换 毫秒级
rtt_ms = CompactNtpRttToMs(rtt_ntp);
if (rtt_ms > report_block_info->max_rtt_ms)
{
report_block_info->max_rtt_ms = rtt_ms;
}
if (report_block_info->num_rtts == 0 || rtt_ms < report_block_info->min_rtt_ms)
{
report_block_info->min_rtt_ms = rtt_ms;
}
report_block_info->last_rtt_ms = rtt_ms;
report_block_info->sum_rtt_ms += rtt_ms;
++report_block_info->num_rtts;
packet_information->rtt_ms = rtt_ms;
}
packet_information->report_blocks.push_back(report_block_info->report_block);
}
RTCP receiver report (RFC 3550).
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| RC | PT=RR=201 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of packet sender |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| report block(s) |
| .... |
bool ReceiverReport::Parse(const CommonHeader& packet)
{
RTC_DCHECK_EQ(packet.type(), kPacketType);
const uint8_t report_blocks_count = packet.count();
if (packet.payload_size_bytes() < kRrBaseLength + report_blocks_count * ReportBlock::kLength)
{
RTC_LOG(LS_WARNING) << "Packet is too small to contain all the data.";
return false;
}
// 发送者ssrc
sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(packet.payload());
const uint8_t* next_report_block = packet.payload() + kRrBaseLength;
report_blocks_.resize(report_blocks_count);
for (ReportBlock& block : report_blocks_)
{
block.Parse(next_report_block, ReportBlock::kLength);
next_report_block += ReportBlock::kLength;
}
RTC_DCHECK_LE(next_report_block - packet.payload(),
static_cast<ptrdiff_t>(packet.payload_size_bytes()));
return true;
}
void RTCPReceiver::HandleReceiverReport(const CommonHeader& rtcp_block, PacketInformation* packet_information)
{
rtcp::ReceiverReport receiver_report;
if (!receiver_report.Parse(rtcp_block))
{
++num_skipped_packets_;
return;
}
const uint32_t remote_ssrc = receiver_report.sender_ssrc();
packet_information->remote_ssrc = remote_ssrc;
UpdateTmmbrRemoteIsAlive(remote_ssrc);
packet_information->packet_type_flags |= kRtcpRr;
for (const ReportBlock& report_block : receiver_report.report_blocks())
{
// TODO@chensong 2022-12-26 和SR包反馈包的处理流程一样的然后抛到GCC模块中去了
HandleReportBlock(report_block, packet_information, remote_ssrc);
}
}
RFC 4585: Feedback format.
Common packet format:
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 | PT | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 | SSRC of packet sender |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | SSRC of media source |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: Feedback Control Information (FCI) :
: :
Generic NACK (RFC 4585).
FCI:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PID | BLP |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
看上面主要的Generic NACK格式是丢包数据(32bit)
void Nack::Unpack()
{
RTC_DCHECK(packet_ids_.empty());
RTC_DCHECK(!packed_.empty());
for (const PackedNack& item : packed_)
{
packet_ids_.push_back(item.first_pid);
uint16_t pid = item.first_pid + 1;
// first_pid : 是记录第一个包seq的
// bitmask : 是掩码 1bit 是0 是没有丢包, 是1是丢包了
for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid)
{
if (bitmask & 1)
{
packet_ids_.push_back(pid);
}
}
}
}
bool Nack::Parse(const CommonHeader& packet)
{
RTC_DCHECK_EQ(packet.type(), kPacketType);
RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) {
RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
<< " is too small for a Nack.";
return false;
}
// nack 结点的个数 nack数据的大小是固定的 --> nack item 一个 4bit
size_t nack_items = (packet.payload_size_bytes() - kCommonFeedbackLength /*8*/) / kNackItemLength /*4*/;
// 读取sender ssrc 4个bit
// media ssrc 4个bit
ParseCommonFeedback(packet.payload());
const uint8_t* next_nack = packet.payload() + kCommonFeedbackLength;
packet_ids_.clear();
packed_.resize(nack_items);
for (size_t index = 0; index < nack_items; ++index)
{
packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack);
packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2);
next_nack += kNackItemLength;
}
// 解码nack的数据包 ->丢包的数据放到packet_ids中去
Unpack();
return true;
}
void RTCPReceiver::HandleNack(const CommonHeader& rtcp_block,
PacketInformation* packet_information) {
rtcp::Nack nack;
if (!nack.Parse(rtcp_block))
{
++num_skipped_packets_;
return;
}
if (receiver_only_ || main_ssrc_ != nack.media_ssrc()) // Not to us.
{
return;
}
// 把丢包的seq插入nack_sequence_numbers中去请求重新发送seq包
packet_information->nack_sequence_numbers.insert(packet_information->nack_sequence_numbers.end(), nack.packet_ids().begin(), nack.packet_ids().end());
// 把丢包的seq的序号放到数据统计中去
for (uint16_t packet_id : nack.packet_ids())
{
nack_stats_.ReportRequest(packet_id);
}
if (!nack.packet_ids().empty())
{
packet_information->packet_type_flags |= kRtcpNack;
// 记录nack丢包请求的次数
++packet_type_counter_.nack_packets;
// 记录总共nack包数量
packet_type_counter_.nack_requests = nack_stats_.requests();
// 超时的包
packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
}
}
// TODO@chensong 发送RTX丢包信息
if (!receiver_only_ && (packet_information.packet_type_flags & kRtcpNack))
{
if (!packet_information.nack_sequence_numbers.empty())
{
RTC_LOG(LS_VERBOSE) << "Incoming NACK length: " << packet_information.nack_sequence_numbers.size();
// 请求重新发送seq的包 ModuleRtpRtcpImpl->OnReceivedNack
rtp_rtcp_->OnReceivedNack(packet_information.nack_sequence_numbers);
}
}
rtp_rtcp_impl.cc
void ModuleRtpRtcpImpl::OnReceivedNack(const std::vector<uint16_t>& nack_sequence_numbers)
{
if (!rtp_sender_)
{
return;
}
// TODO@chensong 2022-12-20 发送包掉包的数据统计模块
for (uint16_t nack_sequence_number : nack_sequence_numbers)
{
send_loss_stats_.AddLostPacket(nack_sequence_number);
}
// TODO@chensong 2022-12-20 判断是否符合重新发送seq的数据包
if (!rtp_sender_->StorePackets() || nack_sequence_numbers.size() == 0)
{
return;
}
// Use RTT from RtcpRttStats class if provided.
int64_t rtt = rtt_ms();
if (rtt == 0)
{
rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL);
}
// TODO@chensong 2022-12-20 重新发送包插入到发送队列中去 RTPSender->OnReceivedNack
rtp_sender_->OnReceivedNack(nack_sequence_numbers, rtt);
}
rtp_sender
int32_t RTPSender::ReSendPacket(uint16_t packet_id) {
// Try to find packet in RTP packet history. Also verify RTT here, so that we
// don't retransmit too often.
absl::optional<RtpPacketHistory::PacketState> stored_packet = packet_history_.GetPacketState(packet_id);
if (!stored_packet)
{
// Packet not found.
return 0;
}
const int32_t packet_size = static_cast<int32_t>(stored_packet->packet_size);
// Skip retransmission rate check if not configured.
if (retransmission_rate_limiter_)
{
// Check if we're overusing retransmission bitrate.
// TODO(sprang): Add histograms for nack success or failure reasons.
if (!retransmission_rate_limiter_->TryUseRate(packet_size))
{
return -1;
}
}
// TODO@chensong 2022-12-20 发送seq sum包 插入到发送队列中去
if (paced_sender_)
{
// Convert from TickTime to Clock since capture_time_ms is based on
// TickTime.
// 把要发送包seq序号队列中去插入发送队列中去
int64_t corrected_capture_tims_ms = stored_packet->capture_time_ms + clock_delta_ms_;
paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority, stored_packet->ssrc, stored_packet->rtp_sequence_number, corrected_capture_tims_ms, stored_packet->packet_size, true);
return packet_size;
}
std::unique_ptr<RtpPacketToSend> packet = packet_history_.GetPacketAndSetSendTime(packet_id);
if (!packet) {
// Packet could theoretically time out between the first check and this one.
return 0;
}
const bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
if (!PrepareAndSendPacket(std::move(packet), rtx, true, PacedPacketInfo()))
{
return -1;
}
return packet_size;
}
void RTPSender::OnReceivedNack( const std::vector<uint16_t>& nack_sequence_numbers, int64_t avg_rtt)
{
// 这边为什么要平均增加+5呢 ????
packet_history_.SetRtt(5 + avg_rtt);
for (uint16_t seq_no : nack_sequence_numbers)
{
const int32_t bytes_sent = ReSendPacket(seq_no);
if (bytes_sent < 0)
{
// Failed to send one Sequence number. Give up the rest in this nack.
RTC_LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no
<< ", Discard rest of packets.";
break;
}
}
}
WebRTC源码分析地址:https://github.com/chensongpoixs/cwebrtc