Handle Receiver Reference Time Report from multiple receivers.
Bug: webrtc:9122 Change-Id: I996f02da26b11a4829fda740fdd452470daf4d24 Reviewed-on: https://webrtc-review.googlesource.com/66781 Commit-Queue: Mirta Dvornicic <mirtad@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22871}
This commit is contained in:
committed by
Commit Bot
parent
68edac7d30
commit
b1f063db32
@ -18,6 +18,7 @@
|
||||
namespace webrtc {
|
||||
namespace rtcp {
|
||||
constexpr uint8_t ExtendedReports::kPacketType;
|
||||
constexpr size_t ExtendedReports::kMaxNumberOfDlrrItems;
|
||||
// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
|
||||
//
|
||||
// Format for XR packets:
|
||||
@ -104,8 +105,13 @@ void ExtendedReports::SetRrtr(const Rrtr& rrtr) {
|
||||
rrtr_block_.emplace(rrtr);
|
||||
}
|
||||
|
||||
void ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
|
||||
bool ExtendedReports::AddDlrrItem(const ReceiveTimeInfo& time_info) {
|
||||
if (dlrr_block_.sub_blocks().size() >= kMaxNumberOfDlrrItems) {
|
||||
RTC_LOG(LS_WARNING) << "Reached maximum number of DLRR items.";
|
||||
return false;
|
||||
}
|
||||
dlrr_block_.AddDlrrItem(time_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExtendedReports::SetVoipMetric(const VoipMetric& voip_metric) {
|
||||
|
||||
@ -28,6 +28,7 @@ class CommonHeader;
|
||||
class ExtendedReports : public RtcpPacket {
|
||||
public:
|
||||
static constexpr uint8_t kPacketType = 207;
|
||||
static constexpr size_t kMaxNumberOfDlrrItems = 50;
|
||||
|
||||
ExtendedReports();
|
||||
~ExtendedReports() override;
|
||||
@ -38,7 +39,7 @@ class ExtendedReports : public RtcpPacket {
|
||||
void SetSenderSsrc(uint32_t ssrc) { sender_ssrc_ = ssrc; }
|
||||
|
||||
void SetRrtr(const Rrtr& rrtr);
|
||||
void AddDlrrItem(const ReceiveTimeInfo& time_info);
|
||||
bool AddDlrrItem(const ReceiveTimeInfo& time_info);
|
||||
void SetVoipMetric(const VoipMetric& voip_metric);
|
||||
void SetTargetBitrate(const TargetBitrate& target_bitrate);
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
using testing::ElementsAre;
|
||||
using testing::ElementsAreArray;
|
||||
using testing::make_tuple;
|
||||
using testing::SizeIs;
|
||||
using webrtc::rtcp::Dlrr;
|
||||
using webrtc::rtcp::ExtendedReports;
|
||||
using webrtc::rtcp::ReceiveTimeInfo;
|
||||
@ -211,6 +212,18 @@ TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithTwoSubBlocks) {
|
||||
EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo1, kTimeInfo2));
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateLimitsTheNumberOfDlrrSubBlocks) {
|
||||
const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
|
||||
ExtendedReports xr;
|
||||
|
||||
for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
|
||||
EXPECT_TRUE(xr.AddDlrrItem(kTimeInfo));
|
||||
EXPECT_FALSE(xr.AddDlrrItem(kTimeInfo));
|
||||
|
||||
EXPECT_THAT(xr.dlrr().sub_blocks(),
|
||||
SizeIs(ExtendedReports::kMaxNumberOfDlrrItems));
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
|
||||
const VoipMetric kVoipMetric = Rand<VoipMetric>();
|
||||
|
||||
@ -228,15 +241,15 @@ TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
|
||||
EXPECT_EQ(kVoipMetric, parsed.voip_metric());
|
||||
}
|
||||
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMultipleReportBlocks) {
|
||||
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMaximumReportBlocks) {
|
||||
const Rrtr kRrtr = Rand<Rrtr>();
|
||||
const ReceiveTimeInfo kTimeInfo = Rand<ReceiveTimeInfo>();
|
||||
const VoipMetric kVoipMetric = Rand<VoipMetric>();
|
||||
|
||||
ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetRrtr(kRrtr);
|
||||
xr.AddDlrrItem(kTimeInfo);
|
||||
for (size_t i = 0; i < ExtendedReports::kMaxNumberOfDlrrItems; ++i)
|
||||
xr.AddDlrrItem(Rand<ReceiveTimeInfo>());
|
||||
xr.SetVoipMetric(kVoipMetric);
|
||||
|
||||
rtc::Buffer packet = xr.Build();
|
||||
@ -247,7 +260,8 @@ TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMultipleReportBlocks) {
|
||||
|
||||
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
|
||||
EXPECT_EQ(kRrtr, parsed.rrtr());
|
||||
EXPECT_THAT(parsed.dlrr().sub_blocks(), ElementsAre(kTimeInfo));
|
||||
EXPECT_THAT(parsed.dlrr().sub_blocks(),
|
||||
ElementsAreArray(xr.dlrr().sub_blocks()));
|
||||
EXPECT_EQ(kVoipMetric, parsed.voip_metric());
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,9 @@ const int64_t kTmmbrTimeoutIntervalMs = 5 * 5000;
|
||||
const int64_t kMaxWarningLogIntervalMs = 10000;
|
||||
const int64_t kRtcpMinFrameLengthMs = 17;
|
||||
|
||||
// Maximum number of received RRTRs that will be stored.
|
||||
const size_t kMaxNumberOfStoredRrtrs = 200;
|
||||
|
||||
} // namespace
|
||||
|
||||
struct RTCPReceiver::PacketInformation {
|
||||
@ -86,6 +89,22 @@ struct RTCPReceiver::TmmbrInformation {
|
||||
std::map<uint32_t, TimedTmmbrItem> tmmbr;
|
||||
};
|
||||
|
||||
// Structure for storing received RRTR RTCP messages (RFC3611, section 4.4).
|
||||
struct RTCPReceiver::RrtrInformation {
|
||||
RrtrInformation(uint32_t ssrc,
|
||||
uint32_t received_remote_mid_ntp_time,
|
||||
uint32_t local_receive_mid_ntp_time)
|
||||
: ssrc(ssrc),
|
||||
received_remote_mid_ntp_time(received_remote_mid_ntp_time),
|
||||
local_receive_mid_ntp_time(local_receive_mid_ntp_time) {}
|
||||
|
||||
uint32_t ssrc;
|
||||
// Received NTP timestamp in compact representation.
|
||||
uint32_t received_remote_mid_ntp_time;
|
||||
// NTP time when the report was received in compact representation.
|
||||
uint32_t local_receive_mid_ntp_time;
|
||||
};
|
||||
|
||||
struct RTCPReceiver::ReportBlockWithRtt {
|
||||
RTCPReportBlock report_block;
|
||||
|
||||
@ -251,22 +270,26 @@ bool RTCPReceiver::NTP(uint32_t* received_ntp_secs,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(
|
||||
rtcp::ReceiveTimeInfo* info) const {
|
||||
RTC_DCHECK(info);
|
||||
std::vector<rtcp::ReceiveTimeInfo>
|
||||
RTCPReceiver::ConsumeReceivedXrReferenceTimeInfo() {
|
||||
rtc::CritScope lock(&rtcp_receiver_lock_);
|
||||
if (!last_received_xr_ntp_.Valid())
|
||||
return false;
|
||||
|
||||
info->ssrc = remote_time_info_.ssrc;
|
||||
info->last_rr = remote_time_info_.last_rr;
|
||||
const size_t last_xr_rtis_size = std::min(
|
||||
received_rrtrs_.size(), rtcp::ExtendedReports::kMaxNumberOfDlrrItems);
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
|
||||
last_xr_rtis.reserve(last_xr_rtis_size);
|
||||
|
||||
// Get the delay since last received report (RFC 3611).
|
||||
uint32_t receive_time_ntp = CompactNtp(last_received_xr_ntp_);
|
||||
uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
|
||||
const uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
|
||||
|
||||
info->delay_since_last_rr = now_ntp - receive_time_ntp;
|
||||
return true;
|
||||
for (size_t i = 0; i < last_xr_rtis_size; ++i) {
|
||||
RrtrInformation& rrtr = received_rrtrs_.front();
|
||||
last_xr_rtis.emplace_back(rrtr.ssrc, rrtr.received_remote_mid_ntp_time,
|
||||
now_ntp - rrtr.local_receive_mid_ntp_time);
|
||||
received_rrtrs_ssrc_it_.erase(rrtr.ssrc);
|
||||
received_rrtrs_.pop_front();
|
||||
}
|
||||
|
||||
return last_xr_rtis;
|
||||
}
|
||||
|
||||
// We can get multiple receive reports when we receive the report from a CE.
|
||||
@ -673,6 +696,11 @@ void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) {
|
||||
|
||||
last_fir_.erase(bye.sender_ssrc());
|
||||
received_cnames_.erase(bye.sender_ssrc());
|
||||
auto it = received_rrtrs_ssrc_it_.find(bye.sender_ssrc());
|
||||
if (it != received_rrtrs_ssrc_it_.end()) {
|
||||
received_rrtrs_.erase(it->second);
|
||||
received_rrtrs_ssrc_it_.erase(it);
|
||||
}
|
||||
xr_rr_rtt_ms_ = 0;
|
||||
}
|
||||
|
||||
@ -698,9 +726,23 @@ void RTCPReceiver::HandleXr(const CommonHeader& rtcp_block,
|
||||
|
||||
void RTCPReceiver::HandleXrReceiveReferenceTime(uint32_t sender_ssrc,
|
||||
const rtcp::Rrtr& rrtr) {
|
||||
remote_time_info_.ssrc = sender_ssrc;
|
||||
remote_time_info_.last_rr = CompactNtp(rrtr.ntp());
|
||||
last_received_xr_ntp_ = clock_->CurrentNtpTime();
|
||||
uint32_t received_remote_mid_ntp_time = CompactNtp(rrtr.ntp());
|
||||
uint32_t local_receive_mid_ntp_time = CompactNtp(clock_->CurrentNtpTime());
|
||||
|
||||
auto it = received_rrtrs_ssrc_it_.find(sender_ssrc);
|
||||
if (it != received_rrtrs_ssrc_it_.end()) {
|
||||
it->second->received_remote_mid_ntp_time = received_remote_mid_ntp_time;
|
||||
it->second->local_receive_mid_ntp_time = local_receive_mid_ntp_time;
|
||||
} else {
|
||||
if (received_rrtrs_.size() < kMaxNumberOfStoredRrtrs) {
|
||||
received_rrtrs_.emplace_back(sender_ssrc, received_remote_mid_ntp_time,
|
||||
local_receive_mid_ntp_time);
|
||||
received_rrtrs_ssrc_it_[sender_ssrc] = std::prev(received_rrtrs_.end());
|
||||
} else {
|
||||
RTC_LOG(LS_WARNING) << "Discarding received RRTR for ssrc " << sender_ssrc
|
||||
<< ", reached maximum number of stored RRTRs.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RTCPReceiver::HandleXrDlrrReportBlock(const rtcp::ReceiveTimeInfo& rti) {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
|
||||
#define MODULES_RTP_RTCP_SOURCE_RTCP_RECEIVER_H_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@ -77,7 +78,7 @@ class RTCPReceiver {
|
||||
uint32_t* rtcp_arrival_time_frac,
|
||||
uint32_t* rtcp_timestamp) const;
|
||||
|
||||
bool LastReceivedXrReferenceTimeInfo(rtcp::ReceiveTimeInfo* info) const;
|
||||
std::vector<rtcp::ReceiveTimeInfo> ConsumeReceivedXrReferenceTimeInfo();
|
||||
|
||||
// Get rtt.
|
||||
int32_t RTT(uint32_t remote_ssrc,
|
||||
@ -115,6 +116,7 @@ class RTCPReceiver {
|
||||
private:
|
||||
struct PacketInformation;
|
||||
struct TmmbrInformation;
|
||||
struct RrtrInformation;
|
||||
struct ReportBlockWithRtt;
|
||||
struct LastFirStatus;
|
||||
// RTCP report blocks mapped by remote SSRC.
|
||||
@ -226,10 +228,13 @@ class RTCPReceiver {
|
||||
// When did we receive the last send report.
|
||||
NtpTime last_received_sr_ntp_ RTC_GUARDED_BY(rtcp_receiver_lock_);
|
||||
|
||||
// Received XR receive time report.
|
||||
rtcp::ReceiveTimeInfo remote_time_info_;
|
||||
// Time when the report was received.
|
||||
NtpTime last_received_xr_ntp_;
|
||||
// Received RRTR information in ascending receive time order.
|
||||
std::list<RrtrInformation> received_rrtrs_
|
||||
RTC_GUARDED_BY(rtcp_receiver_lock_);
|
||||
// Received RRTR information mapped by remote ssrc.
|
||||
std::map<uint32_t, std::list<RrtrInformation>::iterator>
|
||||
received_rrtrs_ssrc_it_ RTC_GUARDED_BY(rtcp_receiver_lock_);
|
||||
|
||||
// Estimated rtt, zero when there is no valid estimate.
|
||||
bool xr_rrtr_status_ RTC_GUARDED_BY(rtcp_receiver_lock_);
|
||||
int64_t xr_rr_rtt_ms_;
|
||||
|
||||
@ -620,6 +620,21 @@ TEST_F(RtcpReceiverTest, InjectByePacket_RemovesReportBlocks) {
|
||||
EXPECT_EQ(2u, received_blocks.size());
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, InjectByePacketRemovesReferenceTimeInfo) {
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
rtcp::Rrtr rrtr;
|
||||
rrtr.SetNtp(NtpTime(0x10203, 0x40506));
|
||||
xr.SetRrtr(rrtr);
|
||||
InjectRtcpPacket(xr);
|
||||
|
||||
rtcp::Bye bye;
|
||||
bye.SetSenderSsrc(kSenderSsrc);
|
||||
InjectRtcpPacket(bye);
|
||||
|
||||
EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, InjectPliPacket) {
|
||||
rtcp::Pli pli;
|
||||
pli.SetMediaSsrc(kReceiverMainSsrc);
|
||||
@ -706,19 +721,17 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsReceiverReferenceTimePacket) {
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
xr.SetRrtr(rrtr);
|
||||
|
||||
ReceiveTimeInfo rrtime;
|
||||
EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
EXPECT_THAT(last_xr_rtis, IsEmpty());
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
|
||||
EXPECT_EQ(rrtime.ssrc, kSenderSsrc);
|
||||
EXPECT_EQ(rrtime.last_rr, CompactNtp(kNtp));
|
||||
EXPECT_EQ(0U, rrtime.delay_since_last_rr);
|
||||
|
||||
system_clock_.AdvanceTimeMilliseconds(1500);
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
|
||||
EXPECT_NEAR(1500, CompactNtpRttToMs(rrtime.delay_since_last_rr), 1);
|
||||
last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
ASSERT_THAT(last_xr_rtis, SizeIs(1));
|
||||
EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
|
||||
EXPECT_EQ(CompactNtp(kNtp), last_xr_rtis[0].last_rr);
|
||||
EXPECT_EQ(0U, last_xr_rtis[0].delay_since_last_rr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, ExtendedReportsDlrrPacketNotToUsIgnored) {
|
||||
@ -788,8 +801,9 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithMultipleReportBlocks) {
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
|
||||
ReceiveTimeInfo rrtime;
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
EXPECT_THAT(last_xr_rtis, SizeIs(1));
|
||||
int64_t rtt_ms = 0;
|
||||
EXPECT_TRUE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
|
||||
}
|
||||
@ -813,8 +827,9 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithUnknownReportBlock) {
|
||||
InjectRtcpPacket(packet);
|
||||
|
||||
// Validate Rrtr was received and processed.
|
||||
ReceiveTimeInfo rrtime;
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&rrtime));
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
EXPECT_THAT(last_xr_rtis, SizeIs(1));
|
||||
// Validate Dlrr report wasn't processed.
|
||||
int64_t rtt_ms = 0;
|
||||
EXPECT_FALSE(rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms));
|
||||
@ -869,12 +884,11 @@ TEST_F(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) {
|
||||
EXPECT_EQ(1, rtt_ms);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) {
|
||||
ReceiveTimeInfo info;
|
||||
EXPECT_FALSE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
|
||||
TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfoInitiallyEmpty) {
|
||||
EXPECT_THAT(rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, GetLastReceivedExtendedReportsReferenceTimeInfo) {
|
||||
TEST_F(RtcpReceiverTest, ConsumeReceivedXrReferenceTimeInfo) {
|
||||
const NtpTime kNtp(0x10203, 0x40506);
|
||||
const uint32_t kNtpMid = CompactNtp(kNtp);
|
||||
|
||||
@ -886,15 +900,69 @@ TEST_F(RtcpReceiverTest, GetLastReceivedExtendedReportsReferenceTimeInfo) {
|
||||
|
||||
InjectRtcpPacket(xr);
|
||||
|
||||
ReceiveTimeInfo info;
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
|
||||
EXPECT_EQ(kSenderSsrc, info.ssrc);
|
||||
EXPECT_EQ(kNtpMid, info.last_rr);
|
||||
EXPECT_EQ(0U, info.delay_since_last_rr);
|
||||
|
||||
system_clock_.AdvanceTimeMilliseconds(1000);
|
||||
EXPECT_TRUE(rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&info));
|
||||
EXPECT_EQ(65536U, info.delay_since_last_rr);
|
||||
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
ASSERT_THAT(last_xr_rtis, SizeIs(1));
|
||||
EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
|
||||
EXPECT_EQ(kNtpMid, last_xr_rtis[0].last_rr);
|
||||
EXPECT_EQ(65536U, last_xr_rtis[0].delay_since_last_rr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest,
|
||||
ReceivedRrtrFromSameSsrcUpdatesReceivedReferenceTimeInfo) {
|
||||
const NtpTime kNtp1(0x10203, 0x40506);
|
||||
const NtpTime kNtp2(0x11223, 0x44556);
|
||||
const int64_t kDelayMs = 2000;
|
||||
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(kSenderSsrc);
|
||||
rtcp::Rrtr rrtr1;
|
||||
rrtr1.SetNtp(kNtp1);
|
||||
xr.SetRrtr(rrtr1);
|
||||
InjectRtcpPacket(xr);
|
||||
system_clock_.AdvanceTimeMilliseconds(kDelayMs);
|
||||
rtcp::Rrtr rrtr2;
|
||||
rrtr2.SetNtp(kNtp2);
|
||||
xr.SetRrtr(rrtr2);
|
||||
InjectRtcpPacket(xr);
|
||||
system_clock_.AdvanceTimeMilliseconds(kDelayMs);
|
||||
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
ASSERT_THAT(last_xr_rtis, SizeIs(1));
|
||||
EXPECT_EQ(kSenderSsrc, last_xr_rtis[0].ssrc);
|
||||
EXPECT_EQ(CompactNtp(kNtp2), last_xr_rtis[0].last_rr);
|
||||
EXPECT_EQ(kDelayMs * 65536 / 1000, last_xr_rtis[0].delay_since_last_rr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, StoresLastReceivedRrtrPerSsrc) {
|
||||
const size_t kNumBufferedReports = 1;
|
||||
const size_t kNumReports =
|
||||
rtcp::ExtendedReports::kMaxNumberOfDlrrItems + kNumBufferedReports;
|
||||
for (size_t i = 0; i < kNumReports; ++i) {
|
||||
rtcp::ExtendedReports xr;
|
||||
xr.SetSenderSsrc(i * 100);
|
||||
rtcp::Rrtr rrtr;
|
||||
rrtr.SetNtp(NtpTime(i * 200, i * 300));
|
||||
xr.SetRrtr(rrtr);
|
||||
InjectRtcpPacket(xr);
|
||||
system_clock_.AdvanceTimeMilliseconds(1000);
|
||||
}
|
||||
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis =
|
||||
rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
ASSERT_THAT(last_xr_rtis,
|
||||
SizeIs(rtcp::ExtendedReports::kMaxNumberOfDlrrItems));
|
||||
for (size_t i = 0; i < rtcp::ExtendedReports::kMaxNumberOfDlrrItems; ++i) {
|
||||
EXPECT_EQ(i * 100, last_xr_rtis[i].ssrc);
|
||||
EXPECT_EQ(CompactNtp(NtpTime(i * 200, i * 300)), last_xr_rtis[i].last_rr);
|
||||
EXPECT_EQ(65536U * (kNumReports - i), last_xr_rtis[i].delay_since_last_rr);
|
||||
}
|
||||
|
||||
last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
ASSERT_THAT(last_xr_rtis, SizeIs(kNumBufferedReports));
|
||||
}
|
||||
|
||||
TEST_F(RtcpReceiverTest, ReceiveReportTimeout) {
|
||||
|
||||
@ -85,9 +85,14 @@ RTCPSender::FeedbackState::FeedbackState()
|
||||
last_rr_ntp_secs(0),
|
||||
last_rr_ntp_frac(0),
|
||||
remote_sr(0),
|
||||
has_last_xr_rr(false),
|
||||
module(nullptr) {}
|
||||
|
||||
RTCPSender::FeedbackState::FeedbackState(const FeedbackState&) = default;
|
||||
|
||||
RTCPSender::FeedbackState::FeedbackState(FeedbackState&&) = default;
|
||||
|
||||
RTCPSender::FeedbackState::~FeedbackState() = default;
|
||||
|
||||
class PacketContainer : public rtcp::CompoundPacket {
|
||||
public:
|
||||
PacketContainer(Transport* transport, RtcEventLog* event_log)
|
||||
@ -644,8 +649,8 @@ std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports(
|
||||
xr->SetRrtr(rrtr);
|
||||
}
|
||||
|
||||
if (ctx.feedback_state_.has_last_xr_rr) {
|
||||
xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
|
||||
for (const rtcp::ReceiveTimeInfo& rti : ctx.feedback_state_.last_xr_rtis) {
|
||||
xr->AddDlrrItem(rti);
|
||||
}
|
||||
|
||||
if (video_bitrate_allocation_) {
|
||||
@ -791,7 +796,7 @@ void RTCPSender::PrepareReport(const FeedbackState& feedback_state) {
|
||||
|
||||
if (generate_report) {
|
||||
if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
|
||||
feedback_state.has_last_xr_rr || video_bitrate_allocation_) {
|
||||
!feedback_state.last_xr_rtis.empty() || video_bitrate_allocation_) {
|
||||
SetFlag(kRtcpAnyExtendedReports, true);
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +59,10 @@ class RTCPSender {
|
||||
public:
|
||||
struct FeedbackState {
|
||||
FeedbackState();
|
||||
FeedbackState(const FeedbackState&);
|
||||
FeedbackState(FeedbackState&&);
|
||||
|
||||
~FeedbackState();
|
||||
|
||||
uint32_t packets_sent;
|
||||
size_t media_bytes_sent;
|
||||
@ -68,8 +72,7 @@ class RTCPSender {
|
||||
uint32_t last_rr_ntp_frac;
|
||||
uint32_t remote_sr;
|
||||
|
||||
bool has_last_xr_rr;
|
||||
rtcp::ReceiveTimeInfo last_xr_rr;
|
||||
std::vector<rtcp::ReceiveTimeInfo> last_xr_rtis;
|
||||
|
||||
// Used when generating TMMBR.
|
||||
ModuleRtpRtcpImpl* module;
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
using ::testing::_;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -608,22 +609,47 @@ TEST_F(RtcpSenderTest, SendXrWithVoipMetric) {
|
||||
TEST_F(RtcpSenderTest, SendXrWithDlrr) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
|
||||
feedback_state.has_last_xr_rr = true;
|
||||
rtcp::ReceiveTimeInfo last_xr_rr;
|
||||
last_xr_rr.ssrc = 0x11111111;
|
||||
last_xr_rr.last_rr = 0x22222222;
|
||||
last_xr_rr.delay_since_last_rr = 0x33333333;
|
||||
feedback_state.last_xr_rr = last_xr_rr;
|
||||
feedback_state.last_xr_rtis.push_back(last_xr_rr);
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
|
||||
EXPECT_EQ(1, parser()->xr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
|
||||
EXPECT_EQ(1U, parser()->xr()->dlrr().sub_blocks().size());
|
||||
ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(1));
|
||||
EXPECT_EQ(last_xr_rr.ssrc, parser()->xr()->dlrr().sub_blocks()[0].ssrc);
|
||||
EXPECT_EQ(last_xr_rr.last_rr, parser()->xr()->dlrr().sub_blocks()[0].last_rr);
|
||||
EXPECT_EQ(last_xr_rr.delay_since_last_rr,
|
||||
parser()->xr()->dlrr().sub_blocks()[0].delay_since_last_rr);
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendXrWithMultipleDlrrSubBlocks) {
|
||||
const size_t kNumReceivers = 2;
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
RTCPSender::FeedbackState feedback_state = rtp_rtcp_impl_->GetFeedbackState();
|
||||
for (size_t i = 0; i < kNumReceivers; ++i) {
|
||||
rtcp::ReceiveTimeInfo last_xr_rr;
|
||||
last_xr_rr.ssrc = i;
|
||||
last_xr_rr.last_rr = (i + 1) * 100;
|
||||
last_xr_rr.delay_since_last_rr = (i + 2) * 200;
|
||||
feedback_state.last_xr_rtis.push_back(last_xr_rr);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
|
||||
EXPECT_EQ(1, parser()->xr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
|
||||
ASSERT_THAT(parser()->xr()->dlrr().sub_blocks(), SizeIs(kNumReceivers));
|
||||
for (size_t i = 0; i < kNumReceivers; ++i) {
|
||||
EXPECT_EQ(feedback_state.last_xr_rtis[i].ssrc,
|
||||
parser()->xr()->dlrr().sub_blocks()[i].ssrc);
|
||||
EXPECT_EQ(feedback_state.last_xr_rtis[i].last_rr,
|
||||
parser()->xr()->dlrr().sub_blocks()[i].last_rr);
|
||||
EXPECT_EQ(feedback_state.last_xr_rtis[i].delay_since_last_rr,
|
||||
parser()->xr()->dlrr().sub_blocks()[i].delay_since_last_rr);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendXrWithRrtr) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state(), false));
|
||||
|
||||
@ -377,8 +377,7 @@ RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() {
|
||||
&state.last_rr_ntp_frac,
|
||||
&state.remote_sr);
|
||||
|
||||
state.has_last_xr_rr =
|
||||
rtcp_receiver_.LastReceivedXrReferenceTimeInfo(&state.last_xr_rr);
|
||||
state.last_xr_rtis = rtcp_receiver_.ConsumeReceivedXrReferenceTimeInfo();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user