Use TimeDelta to convert to to/from compact ntp time

Bug: webrtc:13757
Change-Id: I1c5f0a666da8e6b30291763d110ff049df573490
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/256103
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36333}
This commit is contained in:
Danil Chapovalov 2022-03-24 18:59:40 +01:00 committed by WebRTC LUCI CQ
parent 1d6de1499c
commit 7ab3ecd4c2
8 changed files with 147 additions and 127 deletions

View File

@ -669,7 +669,6 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
(clock_->CurrentNtpInMilliseconds() - rtc::kNtpJan1970Millisecs) *
rtc::kNumMicrosecsPerMillisec);
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.
@ -691,13 +690,13 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
// 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);
report_block_data->AddRoundTripTimeSample(rtt_ms);
TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp);
report_block_data->AddRoundTripTimeSample(rtt.ms());
if (report_block.source_ssrc() == main_ssrc_) {
rtts_[remote_ssrc].AddRtt(TimeDelta::Millis(rtt_ms));
rtts_[remote_ssrc].AddRtt(rtt);
}
packet_information->rtt_ms = rtt_ms;
packet_information->rtt_ms = rtt.ms();
}
packet_information->report_blocks.push_back(
@ -941,9 +940,10 @@ void RTCPReceiver::HandleXrDlrrReportBlock(uint32_t sender_ssrc,
uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
uint32_t rtt_ntp = now_ntp - delay_ntp - send_time_ntp;
xr_rr_rtt_ms_ = CompactNtpRttToMs(rtt_ntp);
TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp);
xr_rr_rtt_ms_ = rtt.ms();
non_sender_rtts_[sender_ssrc].Update(TimeDelta::Millis(xr_rr_rtt_ms_));
non_sender_rtts_[sender_ssrc].Update(rtt);
}
void RTCPReceiver::HandleXrTargetBitrate(

View File

@ -15,6 +15,7 @@
#include <utility>
#include "api/array_view.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "api/video/video_bitrate_allocation.h"
#include "api/video/video_bitrate_allocator.h"
@ -244,15 +245,15 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesRTT) {
RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
const int64_t kRttMs = 123;
const TimeDelta kRtt = TimeDelta::Millis(123);
const uint32_t kDelayNtp = 0x4321;
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
int64_t rtt_ms = 0;
EXPECT_EQ(-1, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime());
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::SenderReport sr;
sr.SetSenderSsrc(kSenderSsrc);
@ -267,7 +268,7 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesRTT) {
receiver.IncomingPacket(sr.Build());
EXPECT_EQ(0, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
EXPECT_NEAR(kRttMs, rtt_ms, 1);
EXPECT_NEAR(rtt_ms, kRtt.ms(), 1);
}
TEST(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) {
@ -275,15 +276,15 @@ TEST(RtcpReceiverTest, InjectSrPacketCalculatesNegativeRTTAsOne) {
RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
const int64_t kRttMs = -13;
const TimeDelta kRtt = TimeDelta::Millis(-13);
const uint32_t kDelayNtp = 0x4321;
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
int64_t rtt_ms = 0;
EXPECT_EQ(-1, receiver.RTT(kSenderSsrc, &rtt_ms, nullptr, nullptr, nullptr));
uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime());
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::SenderReport sr;
sr.SetSenderSsrc(kSenderSsrc);
@ -308,12 +309,12 @@ TEST(RtcpReceiverTest,
RTCPReceiver receiver(DefaultConfiguration(&mocks), &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
const int64_t kRttMs = 120;
const TimeDelta kRtt = TimeDelta::Millis(120);
const uint32_t kDelayNtp = 123000;
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime());
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::SenderReport sr;
sr.SetSenderSsrc(kSenderSsrc);
@ -328,7 +329,7 @@ TEST(RtcpReceiverTest,
EXPECT_CALL(mocks.rtp_rtcp_impl, OnReceivedRtcpReportBlocks(SizeIs(2)));
EXPECT_CALL(mocks.bandwidth_observer,
OnReceivedRtcpReceiverReport(SizeIs(2), kRttMs, _));
OnReceivedRtcpReceiverReport(SizeIs(2), kRtt.ms(), _));
receiver.IncomingPacket(sr.Build());
}
@ -830,7 +831,7 @@ TEST(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithSubBlock) {
uint32_t compact_ntp_now = CompactNtp(mocks.clock.CurrentNtpTime());
EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms));
uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR;
EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1);
EXPECT_NEAR(CompactNtpRttToTimeDelta(rtt_ntp).ms(), rtt_ms, 1);
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_GT(non_sender_rtt_stats.round_trip_time(), TimeDelta::Zero());
@ -860,7 +861,7 @@ TEST(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithMultipleSubBlocks) {
int64_t rtt_ms = 0;
EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms));
uint32_t rtt_ntp = compact_ntp_now - kDelay - kLastRR;
EXPECT_NEAR(CompactNtpRttToMs(rtt_ntp), rtt_ms, 1);
EXPECT_NEAR(CompactNtpRttToTimeDelta(rtt_ntp).ms(), rtt_ms, 1);
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_GT(non_sender_rtt_stats.round_trip_time(), TimeDelta::Zero());
@ -947,12 +948,12 @@ TEST(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) {
receiver.SetRemoteSSRC(kSenderSsrc);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -962,7 +963,7 @@ TEST(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) {
int64_t rtt_ms = 0;
EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms));
EXPECT_NEAR(kRttMs, rtt_ms, 1);
EXPECT_NEAR(kRtt.ms(), rtt_ms, 1);
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
@ -982,12 +983,12 @@ TEST(RtcpReceiverTest, SetterEnablesReceiverRtt) {
receiver.SetNonSenderRttMeasurement(true);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -997,7 +998,7 @@ TEST(RtcpReceiverTest, SetterEnablesReceiverRtt) {
int64_t rtt_ms = 0;
EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms));
EXPECT_NEAR(rtt_ms, kRttMs, 1);
EXPECT_NEAR(rtt_ms, kRtt.ms(), 1);
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
@ -1017,12 +1018,12 @@ TEST(RtcpReceiverTest, DoesntCalculateRttOnReceivedDlrr) {
receiver.SetNonSenderRttMeasurement(false);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1048,12 +1049,12 @@ TEST(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) {
receiver.SetRemoteSSRC(kSenderSsrc);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(-3600 * 1000, -1);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(-3600 * 1000, -1));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1081,12 +1082,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) {
receiver.SetRemoteSSRC(kSenderSsrc);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1099,7 +1100,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) {
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1);
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1);
EXPECT_EQ(non_sender_rtt_stats.round_trip_time_measurements(), 1);
EXPECT_EQ(non_sender_rtt_stats.total_round_trip_time().ms(),
non_sender_rtt_stats.round_trip_time()->ms());
@ -1107,7 +1108,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) {
// Generate another XR report with the same RTT and delay.
NtpTime now2 = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp2 = CompactNtp(now2);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr2;
xr2.SetSenderSsrc(kSenderSsrc);
@ -1119,9 +1120,10 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleMeasurements) {
// the values are as expected.
non_sender_rtt_stats = receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1);
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1);
EXPECT_EQ(non_sender_rtt_stats.round_trip_time_measurements(), 2);
EXPECT_NEAR(non_sender_rtt_stats.total_round_trip_time().ms(), 2 * kRttMs, 2);
EXPECT_NEAR(non_sender_rtt_stats.total_round_trip_time().ms(), 2 * kRtt.ms(),
2);
}
// Test that the receiver RTT stat resets when receiving a SR without XR. This
@ -1135,12 +1137,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnSrWithoutXr) {
receiver.SetRemoteSSRC(kSenderSsrc);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1151,7 +1153,7 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnSrWithoutXr) {
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1);
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1);
// Generate a SR without XR.
rtcp::ReportBlock rb;
@ -1180,12 +1182,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnDlrrWithZeroTimestamp) {
receiver.SetRemoteSSRC(kSenderSsrc);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1196,12 +1198,12 @@ TEST(RtcpReceiverTest, ReceiverRttResetOnDlrrWithZeroTimestamp) {
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1);
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1);
// Generate an XR+DLRR with zero timestamp.
rtcp::ExtendedReports xr2;
xr2.SetSenderSsrc(kSenderSsrc);
xr2.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0, kDelayMs));
xr2.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, 0, kDelayNtp));
receiver.IncomingPacket(xr2.Build());
@ -1220,12 +1222,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) {
receiver.SetNonSenderRttMeasurement(true);
Random rand(0x0123456789abcdef);
const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
NtpTime now = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp = CompactNtp(now);
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::ExtendedReports xr;
xr.SetSenderSsrc(kSenderSsrc);
@ -1234,12 +1236,12 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) {
receiver.IncomingPacket(xr.Build());
// Generate an XR report for another SSRC.
const int64_t kRttMs2 = rand.Rand(1, 9 * 3600 * 1000);
const TimeDelta kRtt2 = TimeDelta::Millis(rand.Rand(1, 9 * 3600 * 1000));
const uint32_t kDelayNtp2 = rand.Rand(0, 0x7fffffff);
const int64_t kDelayMs2 = CompactNtpRttToMs(kDelayNtp2);
const TimeDelta kDelay2 = CompactNtpRttToTimeDelta(kDelayNtp2);
NtpTime now2 = mocks.clock.CurrentNtpTime();
uint32_t sent_ntp2 = CompactNtp(now2);
mocks.clock.AdvanceTimeMilliseconds(kRttMs2 + kDelayMs2);
mocks.clock.AdvanceTime(kRtt2 + kDelay2);
rtcp::ExtendedReports xr2;
xr2.SetSenderSsrc(kSenderSsrc + 1);
@ -1251,7 +1253,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) {
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRttMs, 1);
EXPECT_NEAR(non_sender_rtt_stats.round_trip_time()->ms(), kRtt.ms(), 1);
EXPECT_FALSE(non_sender_rtt_stats.total_round_trip_time().IsZero());
EXPECT_GT(non_sender_rtt_stats.round_trip_time_measurements(), 0);
@ -1260,7 +1262,7 @@ TEST(RtcpReceiverTest, ReceiverRttWithMultipleRemoteSsrcs) {
RTCPReceiver::NonSenderRttStats non_sender_rtt_stats2 =
receiver.GetNonSenderRTT();
EXPECT_TRUE(non_sender_rtt_stats2.round_trip_time().has_value());
EXPECT_NEAR(non_sender_rtt_stats2.round_trip_time()->ms(), kRttMs2, 1);
EXPECT_NEAR(non_sender_rtt_stats2.round_trip_time()->ms(), kRtt2.ms(), 1);
EXPECT_FALSE(non_sender_rtt_stats2.total_round_trip_time().IsZero());
EXPECT_GT(non_sender_rtt_stats2.round_trip_time_measurements(), 0);
}
@ -1615,12 +1617,12 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) {
RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl);
receiver.SetRemoteSSRC(kSenderSsrc);
const int64_t kRttMs = 120;
const TimeDelta kRtt = TimeDelta::Millis(120);
const uint32_t kDelayNtp = 123000;
const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp);
const TimeDelta kDelay = CompactNtpRttToTimeDelta(kDelayNtp);
uint32_t sent_ntp = CompactNtp(mocks.clock.CurrentNtpTime());
mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs);
mocks.clock.AdvanceTime(kRtt + kDelay);
rtcp::SenderReport sr;
sr.SetSenderSsrc(kSenderSsrc);
@ -1641,10 +1643,10 @@ TEST(RtcpReceiverTest, VerifyRttObtainedFromReportBlockDataObserver) {
EXPECT_EQ(kReceiverMainSsrc,
report_block_data.report_block().source_ssrc);
EXPECT_EQ(1u, report_block_data.num_rtts());
EXPECT_EQ(kRttMs, report_block_data.min_rtt_ms());
EXPECT_EQ(kRttMs, report_block_data.max_rtt_ms());
EXPECT_EQ(kRttMs, report_block_data.sum_rtt_ms());
EXPECT_EQ(kRttMs, report_block_data.last_rtt_ms());
EXPECT_EQ(kRtt.ms(), report_block_data.min_rtt_ms());
EXPECT_EQ(kRtt.ms(), report_block_data.max_rtt_ms());
EXPECT_EQ(kRtt.ms(), report_block_data.sum_rtt_ms());
EXPECT_EQ(kRtt.ms(), report_block_data.last_rtt_ms());
});
EXPECT_CALL(observer, OnReportBlockDataUpdated)
.WillOnce([](ReportBlockData report_block_data) {

View File

@ -446,8 +446,8 @@ void RtcpTransceiverImpl::HandleDlrr(const rtcp::Dlrr& dlrr, Timestamp now) {
if (rti.ssrc != config_.feedback_ssrc)
continue;
uint32_t rtt_ntp = receive_time_ntp - rti.delay_since_last_rr - rti.last_rr;
int64_t rtt_ms = CompactNtpRttToMs(rtt_ntp);
config_.network_link_observer->OnRttUpdate(now, TimeDelta::Millis(rtt_ms));
TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp);
config_.network_link_observer->OnRttUpdate(now, rtt);
}
}
@ -472,7 +472,7 @@ void RtcpTransceiverImpl::ProcessReportBlocks(
uint32_t rtt_ntp = receive_time_ntp - report_block.delay_since_last_sr() -
report_block.last_sr();
rtt_sum += TimeDelta::Millis(CompactNtpRttToMs(rtt_ntp));
rtt_sum += CompactNtpRttToTimeDelta(rtt_ntp);
++num_rtts;
}
// For backward compatibility, do not report rtt based on report blocks to the
@ -788,8 +788,8 @@ std::vector<rtcp::ReportBlock> RtcpTransceiverImpl::CreateReportBlocks(
const SenderReportTimes& last_sender_report =
*it->second.last_received_sender_report;
last_sr = CompactNtp(last_sender_report.remote_sent_time);
last_delay = SaturatedUsToCompactNtp(
now.us() - last_sender_report.local_received_time.us());
last_delay =
SaturatedToCompactNtp(now - last_sender_report.local_received_time);
report_block.SetLastSr(last_sr);
report_block.SetDelayLastSr(last_delay);
}

View File

@ -123,6 +123,12 @@ constexpr TimeDelta kReportPeriod = TimeDelta::Millis(10);
// Use finite timeout to fail tests rather than hang them.
constexpr int kAlmostForeverMs = 1000;
constexpr TimeDelta kTimePrecision = TimeDelta::Millis(1);
MATCHER_P(Near, value, "") {
return arg > value - kTimePrecision && arg < value + kTimePrecision;
}
// Helper to wait for an rtcp packet produced on a different thread/task queue.
class FakeRtcpTransport : public webrtc::Transport {
public:
@ -967,10 +973,12 @@ TEST(RtcpTransceiverImplTest,
// match result of ReceiveStatisticsProvider::RtcpReportBlocks callback,
// but for simplicity of the test asume it is the same.
ASSERT_EQ(report_blocks[0].source_ssrc(), kRemoteSsrc1);
EXPECT_EQ(CompactNtpRttToMs(report_blocks[0].delay_since_last_sr()), 200);
EXPECT_THAT(CompactNtpRttToTimeDelta(report_blocks[0].delay_since_last_sr()),
Near(TimeDelta::Millis(200)));
ASSERT_EQ(report_blocks[1].source_ssrc(), kRemoteSsrc2);
EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
EXPECT_THAT(CompactNtpRttToTimeDelta(report_blocks[1].delay_since_last_sr()),
Near(TimeDelta::Millis(100)));
}
TEST(RtcpTransceiverImplTest, MaySendMultipleReceiverReportInSinglePacket) {
@ -1330,11 +1338,12 @@ TEST(RtcpTransceiverImplTest, PassRttFromDlrrToLinkObserver) {
rtcp::ReceiveTimeInfo rti;
rti.ssrc = kSenderSsrc;
rti.last_rr = CompactNtp(config.clock->ConvertTimestampToNtpTime(send_time));
rti.delay_since_last_rr = SaturatedUsToCompactNtp(10'000); // 10ms
rti.delay_since_last_rr = SaturatedToCompactNtp(TimeDelta::Millis(10));
rtcp::ExtendedReports xr;
xr.AddDlrrItem(rti);
EXPECT_CALL(link_observer, OnRttUpdate(receive_time, TimeDelta::Millis(100)));
EXPECT_CALL(link_observer,
OnRttUpdate(receive_time, Near(TimeDelta::Millis(100))));
rtcp_transceiver.ReceivePacket(xr.Build(), receive_time);
}
@ -1351,15 +1360,15 @@ TEST(RtcpTransceiverImplTest, CalculatesRoundTripTimeFromReportBlocks) {
rtcp::ReportBlock rb1;
rb1.SetLastSr(CompactNtp(config.clock->ConvertTimestampToNtpTime(
receive_time - rtt - TimeDelta::Millis(10))));
rb1.SetDelayLastSr(SaturatedUsToCompactNtp(10'000)); // 10ms
rb1.SetDelayLastSr(SaturatedToCompactNtp(TimeDelta::Millis(10)));
rr.AddReportBlock(rb1);
rtcp::ReportBlock rb2;
rb2.SetLastSr(CompactNtp(config.clock->ConvertTimestampToNtpTime(
receive_time - rtt - TimeDelta::Millis(20))));
rb2.SetDelayLastSr(SaturatedUsToCompactNtp(20'000)); // 20ms
rb2.SetDelayLastSr(SaturatedToCompactNtp(TimeDelta::Millis(20)));
rr.AddReportBlock(rb2);
EXPECT_CALL(link_observer, OnRttUpdate(receive_time, rtt));
EXPECT_CALL(link_observer, OnRttUpdate(receive_time, Near(rtt)));
rtcp_transceiver.ReceivePacket(rr.Build(), receive_time);
}

View File

@ -18,35 +18,37 @@
namespace webrtc {
uint32_t SaturatedUsToCompactNtp(int64_t us) {
uint32_t SaturatedToCompactNtp(TimeDelta delta) {
constexpr uint32_t kMaxCompactNtp = 0xFFFFFFFF;
constexpr int kCompactNtpInSecond = 0x10000;
if (us <= 0)
if (delta <= TimeDelta::Zero())
return 0;
if (us >= kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond)
if (delta.us() >=
kMaxCompactNtp * rtc::kNumMicrosecsPerSec / kCompactNtpInSecond)
return kMaxCompactNtp;
// To convert to compact ntp need to divide by 1e6 to get seconds,
// then multiply by 0x10000 to get the final result.
// To avoid float operations, multiplication and division swapped.
return DivideRoundToNearest(us * kCompactNtpInSecond,
return DivideRoundToNearest(delta.us() * kCompactNtpInSecond,
rtc::kNumMicrosecsPerSec);
}
int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval) {
// Interval to convert expected to be positive, e.g. rtt or delay.
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval) {
static constexpr TimeDelta kMinRtt = TimeDelta::Millis(1);
// Interval to convert expected to be positive, e.g. RTT or delay.
// Because interval can be derived from non-monotonic ntp clock,
// it might become negative that is indistinguishable from very large values.
// Since very large rtt/delay are less likely than non-monotonic ntp clock,
// those values consider to be negative and convert to minimum value of 1ms.
// Since very large RTT/delay is less likely than non-monotonic ntp clock,
// such value is considered negative and converted to minimum value of 1ms.
if (compact_ntp_interval > 0x80000000)
return 1;
return kMinRtt;
// Convert to 64bit value to avoid multiplication overflow.
int64_t value = static_cast<int64_t>(compact_ntp_interval);
// To convert to milliseconds need to divide by 2^16 to get seconds,
// then multiply by 1000 to get milliseconds. To avoid float operations,
// multiplication and division swapped.
int64_t ms = DivideRoundToNearest(value * 1000, 1 << 16);
// Rtt value 0 considered too good to be true and increases to 1.
return std::max<int64_t>(ms, 1);
// To convert to TimeDelta need to divide by 2^16 to get seconds,
// then multiply by 1'000'000 to get microseconds. To avoid float operations,
// multiplication and division are swapped.
int64_t us = DivideRoundToNearest(value * rtc::kNumMicrosecsPerSec, 1 << 16);
// Small RTT value is considered too good to be true and increased to 1ms.
return std::max(TimeDelta::Micros(us), kMinRtt);
}
} // namespace webrtc

View File

@ -13,6 +13,7 @@
#include <stdint.h>
#include "api/units/time_delta.h"
#include "system_wrappers/include/ntp_time.h"
namespace webrtc {
@ -29,14 +30,15 @@ inline uint32_t CompactNtp(NtpTime ntp) {
return (ntp.seconds() << 16) | (ntp.fractions() >> 16);
}
// Converts interval in microseconds to compact ntp (1/2^16 seconds) resolution.
// Converts interval to compact ntp (1/2^16 seconds) resolution.
// Negative values converted to 0, Overlarge values converted to max uint32_t.
uint32_t SaturatedUsToCompactNtp(int64_t us);
uint32_t SaturatedToCompactNtp(TimeDelta delta);
// Converts interval between compact ntp timestamps to milliseconds.
// Converts interval from compact ntp (1/2^16 seconds) resolution to TimeDelta.
// This interval can be up to ~9.1 hours (2^15 seconds).
// Values close to 2^16 seconds consider negative and result in minimum rtt = 1.
int64_t CompactNtpRttToMs(uint32_t compact_ntp_interval);
// Values close to 2^16 seconds are considered negative and are converted to
// minimum value of 1ms.
TimeDelta CompactNtpRttToTimeDelta(uint32_t compact_ntp_interval);
} // namespace webrtc
#endif // MODULES_RTP_RTCP_SOURCE_TIME_UTIL_H_

View File

@ -21,18 +21,16 @@ TEST(TimeUtilTest, CompactNtp) {
EXPECT_EQ(kNtpMid, CompactNtp(kNtp));
}
TEST(TimeUtilTest, CompactNtpRttToMs) {
TEST(TimeUtilTest, CompactNtpRttToTimeDelta) {
const NtpTime ntp1(0x12345, 0x23456);
const NtpTime ntp2(0x12654, 0x64335);
int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1);
}
TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) {
TEST(TimeUtilTest, CompactNtpRttToTimeDeltaWithWrap) {
const NtpTime ntp1(0x1ffff, 0x23456);
const NtpTime ntp2(0x20000, 0x64335);
int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
@ -43,51 +41,58 @@ TEST(TimeUtilTest, CompactNtpRttToMsWithWrap) {
ASSERT_LT(CompactNtp(ntp2), CompactNtp(ntp1));
uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1);
}
TEST(TimeUtilTest, CompactNtpRttToMsLarge) {
TEST(TimeUtilTest, CompactNtpRttToTimeDeltaLarge) {
const NtpTime ntp1(0x10000, 0x00006);
const NtpTime ntp2(0x17fff, 0xffff5);
int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
// Ntp difference close to 2^15 seconds should convert correctly too.
ASSERT_NEAR(ms_diff, ((1 << 15) - 1) * 1000, 1);
uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
EXPECT_NEAR(ms_diff, ntp_to_ms_diff, 1);
EXPECT_NEAR(CompactNtpRttToTimeDelta(ntp_diff).ms(), ms_diff, 1);
}
TEST(TimeUtilTest, CompactNtpRttToMsNegative) {
TEST(TimeUtilTest, CompactNtpRttToTimeDeltaNegative) {
const NtpTime ntp1(0x20000, 0x23456);
const NtpTime ntp2(0x1ffff, 0x64335);
int64_t ms_diff = ntp2.ToMs() - ntp1.ToMs();
ASSERT_GT(0, ms_diff);
// Ntp difference close to 2^16 seconds should be treated as negative.
uint32_t ntp_diff = CompactNtp(ntp2) - CompactNtp(ntp1);
int64_t ntp_to_ms_diff = CompactNtpRttToMs(ntp_diff);
EXPECT_EQ(1, ntp_to_ms_diff);
EXPECT_EQ(CompactNtpRttToTimeDelta(ntp_diff), TimeDelta::Millis(1));
}
TEST(TimeUtilTest, SaturatedUsToCompactNtp) {
TEST(TimeUtilTest, SaturatedToCompactNtp) {
// Converts negative to zero.
EXPECT_EQ(SaturatedUsToCompactNtp(-1), 0u);
EXPECT_EQ(SaturatedUsToCompactNtp(0), 0u);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(-1)), 0u);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Zero()), 0u);
// Converts values just above and just below max uint32_t.
EXPECT_EQ(SaturatedUsToCompactNtp(65536000000), 0xffffffff);
EXPECT_EQ(SaturatedUsToCompactNtp(65535999985), 0xffffffff);
EXPECT_EQ(SaturatedUsToCompactNtp(65535999970), 0xfffffffe);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65536000000)), 0xffffffff);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65535999985)), 0xffffffff);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Micros(65535999970)), 0xfffffffe);
// Converts half-seconds.
EXPECT_EQ(SaturatedUsToCompactNtp(500000), 0x8000u);
EXPECT_EQ(SaturatedUsToCompactNtp(1000000), 0x10000u);
EXPECT_EQ(SaturatedUsToCompactNtp(1500000), 0x18000u);
// Convert us -> compact_ntp -> ms. Compact ntp precision is ~15us.
EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(1516)), 2);
EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(15000)), 15);
EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5485)), 5);
EXPECT_EQ(CompactNtpRttToMs(SaturatedUsToCompactNtp(5515)), 6);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Millis(500)), 0x8000u);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Seconds(1)), 0x10000u);
EXPECT_EQ(SaturatedToCompactNtp(TimeDelta::Millis(1'500)), 0x18000u);
// Convert us -> compact_ntp -> TimeDelta. Compact ntp precision is ~15us.
EXPECT_NEAR(
CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(1'516)))
.us(),
1'516, 16);
EXPECT_NEAR(
CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Millis(15)))
.us(),
15'000, 16);
EXPECT_NEAR(
CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(5'485)))
.us(),
5'485, 16);
EXPECT_NEAR(
CompactNtpRttToTimeDelta(SaturatedToCompactNtp(TimeDelta::Micros(5'515)))
.us(),
5'515, 16);
}
} // namespace webrtc

View File

@ -152,7 +152,7 @@ void LogBasedNetworkControllerSimulation::OnReceiverReport(
CompactNtp(clock->ConvertTimestampToNtpTime(report_log_time));
uint32_t rtt_ntp =
receive_time_ntp - rb.delay_since_last_sr() - rb.last_sr();
rtt = std::min(rtt, TimeDelta::Millis(CompactNtpRttToMs(rtt_ntp)));
rtt = std::min(rtt, CompactNtpRttToTimeDelta(rtt_ntp));
}
}
if (rtt.IsFinite()) {