Return one report block per media ssrc, ignoring sender ssrc.

Webrtc designed to work for point-to-point topology, and thus
each rtcp_receiver handles single remote sender.

While remote sender ssrc may change, it should be ok to assume
the remote endpoint is still the same.

Bug: webrtc:12798
Change-Id: I62aebe7ac802306fc7fa17d7bf3959d6d4cca023
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/224548
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34407}
This commit is contained in:
Danil Chapovalov
2021-07-02 13:51:19 +02:00
committed by WebRTC LUCI CQ
parent 2ba604db5b
commit 510c94cbfb
3 changed files with 85 additions and 67 deletions

View File

@ -260,6 +260,18 @@ uint32_t RTCPReceiver::RemoteSSRC() const {
return remote_ssrc_;
}
void RTCPReceiver::RttStats::AddRtt(TimeDelta rtt) {
last_rtt_ = rtt;
if (rtt < min_rtt_) {
min_rtt_ = rtt;
}
if (rtt > max_rtt_) {
max_rtt_ = rtt;
}
sum_rtt_ += rtt;
++num_rtts_;
}
int32_t RTCPReceiver::RTT(uint32_t remote_ssrc,
int64_t* last_rtt_ms,
int64_t* avg_rtt_ms,
@ -267,32 +279,26 @@ int32_t RTCPReceiver::RTT(uint32_t remote_ssrc,
int64_t* max_rtt_ms) const {
MutexLock lock(&rtcp_receiver_lock_);
auto it = received_report_blocks_.find(main_ssrc_);
if (it == received_report_blocks_.end())
auto it = rtts_.find(remote_ssrc);
if (it == rtts_.end()) {
return -1;
auto it_info = it->second.find(remote_ssrc);
if (it_info == it->second.end())
return -1;
const ReportBlockData* report_block_data = &it_info->second;
if (report_block_data->num_rtts() == 0)
return -1;
if (last_rtt_ms)
*last_rtt_ms = report_block_data->last_rtt_ms();
if (avg_rtt_ms) {
*avg_rtt_ms =
report_block_data->sum_rtt_ms() / report_block_data->num_rtts();
}
if (min_rtt_ms)
*min_rtt_ms = report_block_data->min_rtt_ms();
if (last_rtt_ms) {
*last_rtt_ms = it->second.last_rtt().ms();
}
if (max_rtt_ms)
*max_rtt_ms = report_block_data->max_rtt_ms();
if (avg_rtt_ms) {
*avg_rtt_ms = it->second.average_rtt().ms();
}
if (min_rtt_ms) {
*min_rtt_ms = it->second.min_rtt().ms();
}
if (max_rtt_ms) {
*max_rtt_ms = it->second.max_rtt().ms();
}
return 0;
}
@ -320,26 +326,14 @@ absl::optional<TimeDelta> RTCPReceiver::OnPeriodicRttUpdate(
// amount of time.
MutexLock lock(&rtcp_receiver_lock_);
if (last_received_rb_.IsInfinite() || last_received_rb_ > newer_than) {
// Stow away the report block for the main ssrc. We'll use the associated
// data map to look up each sender and check the last_rtt_ms().
auto main_report_it = received_report_blocks_.find(main_ssrc_);
if (main_report_it != received_report_blocks_.end()) {
const ReportBlockDataMap& main_data_map = main_report_it->second;
int64_t max_rtt = 0;
for (const auto& reports_per_receiver : received_report_blocks_) {
for (const auto& report : reports_per_receiver.second) {
const RTCPReportBlock& block = report.second.report_block();
auto it_info = main_data_map.find(block.sender_ssrc);
if (it_info != main_data_map.end()) {
const ReportBlockData* report_block_data = &it_info->second;
if (report_block_data->num_rtts() > 0) {
max_rtt = std::max(report_block_data->last_rtt_ms(), max_rtt);
}
}
}
TimeDelta max_rtt = TimeDelta::MinusInfinity();
for (const auto& rtt_stats : rtts_) {
if (rtt_stats.second.last_rtt() > max_rtt) {
max_rtt = rtt_stats.second.last_rtt();
}
if (max_rtt)
rtt.emplace(TimeDelta::Millis(max_rtt));
}
if (max_rtt.IsFinite()) {
rtt = max_rtt;
}
}
@ -425,9 +419,9 @@ RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() {
std::vector<ReportBlockData> RTCPReceiver::GetLatestReportBlockData() const {
std::vector<ReportBlockData> result;
MutexLock lock(&rtcp_receiver_lock_);
for (const auto& reports_per_receiver : received_report_blocks_)
for (const auto& report : reports_per_receiver.second)
result.push_back(report.second);
for (const auto& report : received_report_blocks_) {
result.push_back(report.second);
}
return result;
}
@ -610,7 +604,7 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
last_received_rb_ = clock_->CurrentTime();
ReportBlockData* report_block_data =
&received_report_blocks_[report_block.source_ssrc()][remote_ssrc];
&received_report_blocks_[report_block.source_ssrc()];
RTCPReportBlock rtcp_report_block;
rtcp_report_block.sender_ssrc = remote_ssrc;
rtcp_report_block.source_ssrc = report_block.source_ssrc();
@ -654,6 +648,9 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
// Convert to 1/1000 seconds (milliseconds).
rtt_ms = CompactNtpRttToMs(rtt_ntp);
report_block_data->AddRoundTripTimeSample(rtt_ms);
if (report_block.source_ssrc() == main_ssrc_) {
rtts_[remote_ssrc].AddRtt(TimeDelta::Millis(rtt_ms));
}
packet_information->rtt_ms = rtt_ms;
}
@ -811,8 +808,15 @@ void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) {
}
// Clear our lists.
for (auto& reports_per_receiver : received_report_blocks_)
reports_per_receiver.second.erase(bye.sender_ssrc());
rtts_.erase(bye.sender_ssrc());
for (auto it = received_report_blocks_.begin();
it != received_report_blocks_.end();) {
if (it->second.report_block().sender_ssrc == bye.sender_ssrc()) {
received_report_blocks_.erase(it++);
} else {
++it;
}
}
TmmbrInformation* tmmbr_info = GetTmmbrInformation(bye.sender_ssrc());
if (tmmbr_info)

View File

@ -117,9 +117,8 @@ class RTCPReceiver final {
bool sending);
// A snapshot of Report Blocks with additional data of interest to statistics.
// Within this list, the sender-source SSRC pair is unique and per-pair the
// ReportBlockData represents the latest Report Block that was received for
// that pair.
// Within this list, the source SSRC is unique and ReportBlockData represents
// the latest Report Block that was received for that SSRC.
std::vector<ReportBlockData> GetLatestReportBlockData() const;
// Returns true if we haven't received an RTCP RR for several RTCP
@ -225,14 +224,26 @@ class RTCPReceiver final {
uint8_t sequence_number;
};
// TODO(boivie): `ReportBlockDataMap` and `ReportBlockMap` should be converted
// to std::unordered_map, but as there are too many tests that assume a
// specific order, it's not easily done.
class RttStats {
public:
RttStats() = default;
RttStats(const RttStats&) = default;
RttStats& operator=(const RttStats&) = default;
// RTCP report blocks mapped by remote SSRC.
using ReportBlockDataMap = std::map<uint32_t, ReportBlockData>;
// RTCP report blocks map mapped by source SSRC.
using ReportBlockMap = std::map<uint32_t, ReportBlockDataMap>;
void AddRtt(TimeDelta rtt);
TimeDelta last_rtt() const { return last_rtt_; }
TimeDelta min_rtt() const { return min_rtt_; }
TimeDelta max_rtt() const { return max_rtt_; }
TimeDelta average_rtt() const { return sum_rtt_ / num_rtts_; }
private:
TimeDelta last_rtt_ = TimeDelta::Zero();
TimeDelta min_rtt_ = TimeDelta::PlusInfinity();
TimeDelta max_rtt_ = TimeDelta::MinusInfinity();
TimeDelta sum_rtt_ = TimeDelta::Zero();
size_t num_rtts_ = 0;
};
bool ParseCompoundPacket(rtc::ArrayView<const uint8_t> packet,
PacketInformation* packet_information);
@ -369,7 +380,17 @@ class RTCPReceiver final {
std::unordered_map<uint32_t, TmmbrInformation> tmmbr_infos_
RTC_GUARDED_BY(rtcp_receiver_lock_);
ReportBlockMap received_report_blocks_ RTC_GUARDED_BY(rtcp_receiver_lock_);
// Round-Trip Time per remote sender ssrc.
std::unordered_map<uint32_t, RttStats> rtts_
RTC_GUARDED_BY(rtcp_receiver_lock_);
// TODO(boivie): `received_report_blocks_` should be converted
// to std::unordered_map, but as there are too many tests that assume a
// specific order, it's not easily done.
// Report blocks per local source ssrc.
std::map<uint32_t, ReportBlockData> received_report_blocks_
RTC_GUARDED_BY(rtcp_receiver_lock_);
std::unordered_map<uint32_t, LastFirStatus> last_fir_
RTC_GUARDED_BY(rtcp_receiver_lock_);

View File

@ -497,7 +497,8 @@ TEST(RtcpReceiverTest, InjectRrPacketWithTwoReportBlocks) {
kSequenceNumbers[1])))));
}
TEST(RtcpReceiverTest, InjectRrPacketsFromTwoRemoteSsrcs) {
TEST(RtcpReceiverTest,
InjectRrPacketsFromTwoRemoteSsrcsReturnsLatestReportBlock) {
const uint32_t kSenderSsrc2 = 0x20304;
const uint16_t kSequenceNumbers[] = {10, 12423};
const int32_t kCumLost[] = {13, 555};
@ -552,14 +553,6 @@ TEST(RtcpReceiverTest, InjectRrPacketsFromTwoRemoteSsrcs) {
EXPECT_THAT(
receiver.GetLatestReportBlockData(),
UnorderedElementsAre(
Property(
&ReportBlockData::report_block,
AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc),
Field(&RTCPReportBlock::sender_ssrc, kSenderSsrc),
Field(&RTCPReportBlock::fraction_lost, kFracLost[0]),
Field(&RTCPReportBlock::packets_lost, kCumLost[0]),
Field(&RTCPReportBlock::extended_highest_sequence_number,
kSequenceNumbers[0]))),
Property(
&ReportBlockData::report_block,
AllOf(Field(&RTCPReportBlock::source_ssrc, kReceiverMainSsrc),