Migrate RemoteNtpTimeEstimator to more precise time representations
Bug: webrtc:13757 Change-Id: I880ab3cc6e4f72da587ae42ddca051332907c07f Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261311 Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Emil Lundmark <lndmrk@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36817}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
14d01508be
commit
a154a15c97
@ -748,12 +748,13 @@ void ChannelReceive::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
|
||||
|
||||
{
|
||||
MutexLock lock(&ts_stats_lock_);
|
||||
ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset_ms =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffsetMs();
|
||||
if (remote_to_local_clock_offset_ms.has_value()) {
|
||||
ntp_estimator_.UpdateRtcpTimestamp(
|
||||
TimeDelta::Millis(rtt), NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffset();
|
||||
if (remote_to_local_clock_offset.has_value()) {
|
||||
capture_clock_offset_updater_.SetRemoteToLocalClockOffset(
|
||||
Int64MsToQ32x32(*remote_to_local_clock_offset_ms));
|
||||
*remote_to_local_clock_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +226,8 @@ void AudioIngress::ReceivedRTCPPacket(
|
||||
|
||||
{
|
||||
MutexLock lock(&lock_);
|
||||
ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
|
||||
ntp_estimator_.UpdateRtcpTimestamp(
|
||||
TimeDelta::Millis(rtt), NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "rtc_base/numerics/moving_median_filter.h"
|
||||
#include "system_wrappers/include/rtp_to_ntp_estimator.h"
|
||||
|
||||
@ -28,32 +31,63 @@ class Clock;
|
||||
class RemoteNtpTimeEstimator {
|
||||
public:
|
||||
explicit RemoteNtpTimeEstimator(Clock* clock);
|
||||
|
||||
~RemoteNtpTimeEstimator();
|
||||
|
||||
RemoteNtpTimeEstimator(const RemoteNtpTimeEstimator&) = delete;
|
||||
RemoteNtpTimeEstimator& operator=(const RemoteNtpTimeEstimator&) = delete;
|
||||
~RemoteNtpTimeEstimator() = default;
|
||||
|
||||
// Updates the estimator with round trip time `rtt`, NTP seconds `ntp_secs`,
|
||||
// NTP fraction `ntp_frac` and RTP timestamp `rtp_timestamp`.
|
||||
ABSL_DEPRECATED(
|
||||
"Use UpdateRtcpTimestamp with strict time types: TimeDelta and NtpTime.")
|
||||
bool UpdateRtcpTimestamp(int64_t rtt,
|
||||
uint32_t ntp_secs,
|
||||
uint32_t ntp_frac,
|
||||
uint32_t rtp_timestamp) {
|
||||
return UpdateRtcpTimestamp(TimeDelta::Millis(rtt),
|
||||
NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
|
||||
}
|
||||
|
||||
bool UpdateRtcpTimestamp(TimeDelta rtt,
|
||||
NtpTime sender_send_time,
|
||||
uint32_t rtp_timestamp);
|
||||
|
||||
// Estimates the NTP timestamp in local timebase from `rtp_timestamp`.
|
||||
// Returns the NTP timestamp in ms when success. -1 if failed.
|
||||
int64_t Estimate(uint32_t rtp_timestamp);
|
||||
int64_t Estimate(uint32_t rtp_timestamp) {
|
||||
NtpTime ntp_time = EstimateNtp(rtp_timestamp);
|
||||
if (!ntp_time.Valid()) {
|
||||
return -1;
|
||||
}
|
||||
return ntp_time.ToMs();
|
||||
}
|
||||
|
||||
// Estimates the NTP timestamp in local timebase from `rtp_timestamp`.
|
||||
// Returns invalid NtpTime (i.e. NtpTime(0)) on failure.
|
||||
NtpTime EstimateNtp(uint32_t rtp_timestamp);
|
||||
|
||||
// Estimates the offset, in milliseconds, between the remote clock and the
|
||||
// local one. This is equal to local NTP clock - remote NTP clock.
|
||||
absl::optional<int64_t> EstimateRemoteToLocalClockOffsetMs();
|
||||
ABSL_DEPRECATED("Use EstimateRemoteToLocalClockOffset.")
|
||||
absl::optional<int64_t> EstimateRemoteToLocalClockOffsetMs() {
|
||||
if (absl::optional<int64_t> offset = EstimateRemoteToLocalClockOffset()) {
|
||||
return (*offset * 1'000) / (int64_t{1} << 32);
|
||||
}
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
// Estimates the offset between the remote clock and the
|
||||
// local one. This is equal to local NTP clock - remote NTP clock.
|
||||
// The offset is returned in ntp time resolution, i.e. 1/2^32 sec ~= 0.2 ns.
|
||||
// Returns nullopt on failure.
|
||||
absl::optional<int64_t> EstimateRemoteToLocalClockOffset();
|
||||
|
||||
private:
|
||||
Clock* clock_;
|
||||
// Offset is measured with the same precision as NtpTime: in 1/2^32 seconds ~=
|
||||
// 0.2 ns.
|
||||
MovingMedianFilter<int64_t> ntp_clocks_offset_estimator_;
|
||||
RtpToNtpEstimator rtp_to_ntp_;
|
||||
int64_t last_timing_log_ms_;
|
||||
Timestamp last_timing_log_ = Timestamp::MinusInfinity();
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -22,25 +22,37 @@ namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr int kMinimumNumberOfSamples = 2;
|
||||
constexpr int kTimingLogIntervalMs = 10000;
|
||||
constexpr TimeDelta kTimingLogInterval = TimeDelta::Seconds(10);
|
||||
constexpr int kClocksOffsetSmoothingWindow = 100;
|
||||
|
||||
// Subtracts two NtpTime values keeping maximum precision.
|
||||
int64_t Subtract(NtpTime minuend, NtpTime subtrahend) {
|
||||
uint64_t a = static_cast<uint64_t>(minuend);
|
||||
uint64_t b = static_cast<uint64_t>(subtrahend);
|
||||
return a >= b ? static_cast<int64_t>(a - b) : -static_cast<int64_t>(b - a);
|
||||
}
|
||||
|
||||
NtpTime Add(NtpTime lhs, int64_t rhs) {
|
||||
uint64_t result = static_cast<uint64_t>(lhs);
|
||||
if (rhs >= 0) {
|
||||
result += static_cast<uint64_t>(rhs);
|
||||
} else {
|
||||
result -= static_cast<uint64_t>(-rhs);
|
||||
}
|
||||
return NtpTime(result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(wu): Refactor this class so that it can be shared with
|
||||
// vie_sync_module.cc.
|
||||
RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock)
|
||||
: clock_(clock),
|
||||
ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow),
|
||||
last_timing_log_ms_(-1) {}
|
||||
ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow) {}
|
||||
|
||||
RemoteNtpTimeEstimator::~RemoteNtpTimeEstimator() {}
|
||||
|
||||
bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
|
||||
uint32_t ntp_secs,
|
||||
uint32_t ntp_frac,
|
||||
bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(TimeDelta rtt,
|
||||
NtpTime sender_send_time,
|
||||
uint32_t rtp_timestamp) {
|
||||
NtpTime sender_send_time(ntp_secs, ntp_frac);
|
||||
switch (rtp_to_ntp_.UpdateMeasurements(sender_send_time, rtp_timestamp)) {
|
||||
case RtpToNtpEstimator::kInvalidMeasurement:
|
||||
return false;
|
||||
@ -51,42 +63,42 @@ bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
|
||||
break;
|
||||
}
|
||||
|
||||
// Assume connection is symmetric and thus time to deliver the packet is half
|
||||
// the round trip time.
|
||||
int64_t deliver_time_ntp = ToNtpUnits(rtt) / 2;
|
||||
|
||||
// Update extrapolator with the new arrival time.
|
||||
// The extrapolator assumes the ntp time.
|
||||
int64_t receiver_arrival_time_ms = clock_->CurrentNtpInMilliseconds();
|
||||
int64_t sender_arrival_time_ms = sender_send_time.ToMs() + rtt / 2;
|
||||
NtpTime receiver_arrival_time = clock_->CurrentNtpTime();
|
||||
int64_t remote_to_local_clocks_offset =
|
||||
receiver_arrival_time_ms - sender_arrival_time_ms;
|
||||
Subtract(receiver_arrival_time, sender_send_time) - deliver_time_ntp;
|
||||
ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
|
||||
NtpTime RemoteNtpTimeEstimator::EstimateNtp(uint32_t rtp_timestamp) {
|
||||
NtpTime sender_capture = rtp_to_ntp_.Estimate(rtp_timestamp);
|
||||
if (!sender_capture.Valid()) {
|
||||
return -1;
|
||||
return sender_capture;
|
||||
}
|
||||
int64_t sender_capture_ntp_ms = sender_capture.ToMs();
|
||||
|
||||
int64_t remote_to_local_clocks_offset =
|
||||
ntp_clocks_offset_estimator_.GetFilteredValue();
|
||||
int64_t receiver_capture_ntp_ms =
|
||||
sender_capture_ntp_ms + remote_to_local_clocks_offset;
|
||||
NtpTime receiver_capture = Add(sender_capture, remote_to_local_clocks_offset);
|
||||
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
if (now_ms - last_timing_log_ms_ > kTimingLogIntervalMs) {
|
||||
Timestamp now = clock_->CurrentTime();
|
||||
if (now - last_timing_log_ > kTimingLogInterval) {
|
||||
RTC_LOG(LS_INFO) << "RTP timestamp: " << rtp_timestamp
|
||||
<< " in NTP clock: " << sender_capture_ntp_ms
|
||||
<< " in NTP clock: " << sender_capture.ToMs()
|
||||
<< " estimated time in receiver NTP clock: "
|
||||
<< receiver_capture_ntp_ms;
|
||||
last_timing_log_ms_ = now_ms;
|
||||
<< receiver_capture.ToMs();
|
||||
last_timing_log_ = now;
|
||||
}
|
||||
|
||||
return receiver_capture_ntp_ms;
|
||||
return receiver_capture;
|
||||
}
|
||||
|
||||
absl::optional<int64_t>
|
||||
RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffsetMs() {
|
||||
RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffset() {
|
||||
if (ntp_clocks_offset_estimator_.GetNumberOfSamplesStored() <
|
||||
kMinimumNumberOfSamples) {
|
||||
return absl::nullopt;
|
||||
|
@ -9,32 +9,29 @@
|
||||
*/
|
||||
|
||||
#include "modules/rtp_rtcp/include/remote_ntp_time_estimator.h"
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "modules/rtp_rtcp/source/time_util.h"
|
||||
#include "system_wrappers/include/clock.h"
|
||||
#include "system_wrappers/include/ntp_time.h"
|
||||
#include "test/gmock.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
constexpr int64_t kTestRtt = 10;
|
||||
constexpr int64_t kLocalClockInitialTimeMs = 123;
|
||||
constexpr int64_t kRemoteClockInitialTimeMs = 345;
|
||||
constexpr TimeDelta kTestRtt = TimeDelta::Millis(10);
|
||||
constexpr Timestamp kLocalClockInitialTime = Timestamp::Millis(123);
|
||||
constexpr Timestamp kRemoteClockInitialTime = Timestamp::Millis(373);
|
||||
constexpr uint32_t kTimestampOffset = 567;
|
||||
constexpr int64_t kRemoteToLocalClockOffsetMs =
|
||||
kLocalClockInitialTimeMs - kRemoteClockInitialTimeMs;
|
||||
constexpr int64_t kRemoteToLocalClockOffsetNtp =
|
||||
ToNtpUnits(kLocalClockInitialTime - kRemoteClockInitialTime);
|
||||
|
||||
class RemoteNtpTimeEstimatorTest : public ::testing::Test {
|
||||
protected:
|
||||
RemoteNtpTimeEstimatorTest()
|
||||
: local_clock_(kLocalClockInitialTimeMs * 1000),
|
||||
remote_clock_(kRemoteClockInitialTimeMs * 1000),
|
||||
estimator_(new RemoteNtpTimeEstimator(&local_clock_)) {}
|
||||
~RemoteNtpTimeEstimatorTest() override = default;
|
||||
|
||||
void AdvanceTimeMilliseconds(int64_t ms) {
|
||||
local_clock_.AdvanceTimeMilliseconds(ms);
|
||||
remote_clock_.AdvanceTimeMilliseconds(ms);
|
||||
void AdvanceTime(TimeDelta delta) {
|
||||
local_clock_.AdvanceTime(delta);
|
||||
remote_clock_.AdvanceTime(delta);
|
||||
}
|
||||
|
||||
uint32_t GetRemoteTimestamp() {
|
||||
@ -42,107 +39,90 @@ class RemoteNtpTimeEstimatorTest : public ::testing::Test {
|
||||
kTimestampOffset;
|
||||
}
|
||||
|
||||
NtpTime GetRemoteNtpTime() { return remote_clock_.CurrentNtpTime(); }
|
||||
|
||||
void SendRtcpSr() {
|
||||
uint32_t rtcp_timestamp = GetRemoteTimestamp();
|
||||
NtpTime ntp = GetRemoteNtpTime();
|
||||
NtpTime ntp = remote_clock_.CurrentNtpTime();
|
||||
|
||||
AdvanceTimeMilliseconds(kTestRtt / 2);
|
||||
ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
|
||||
AdvanceTime(kTestRtt / 2);
|
||||
RTC_DCHECK(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp));
|
||||
}
|
||||
|
||||
void SendRtcpSrInaccurately(int64_t ntp_error_ms,
|
||||
int64_t networking_delay_ms) {
|
||||
void SendRtcpSrInaccurately(TimeDelta ntp_error, TimeDelta networking_delay) {
|
||||
uint32_t rtcp_timestamp = GetRemoteTimestamp();
|
||||
int64_t ntp_error_fractions =
|
||||
ntp_error_ms * static_cast<int64_t>(NtpTime::kFractionsPerSecond) /
|
||||
1000;
|
||||
NtpTime ntp(static_cast<uint64_t>(GetRemoteNtpTime()) +
|
||||
int64_t ntp_error_fractions = ToNtpUnits(ntp_error);
|
||||
NtpTime ntp(static_cast<uint64_t>(remote_clock_.CurrentNtpTime()) +
|
||||
ntp_error_fractions);
|
||||
AdvanceTimeMilliseconds(kTestRtt / 2 + networking_delay_ms);
|
||||
ReceiveRtcpSr(kTestRtt, rtcp_timestamp, ntp.seconds(), ntp.fractions());
|
||||
AdvanceTime(kTestRtt / 2 + networking_delay);
|
||||
RTC_DCHECK(estimator_.UpdateRtcpTimestamp(kTestRtt, ntp, rtcp_timestamp));
|
||||
}
|
||||
|
||||
void UpdateRtcpTimestamp(int64_t rtt,
|
||||
uint32_t ntp_secs,
|
||||
uint32_t ntp_frac,
|
||||
uint32_t rtp_timestamp,
|
||||
bool expected_result) {
|
||||
EXPECT_EQ(expected_result, estimator_->UpdateRtcpTimestamp(
|
||||
rtt, ntp_secs, ntp_frac, rtp_timestamp));
|
||||
}
|
||||
|
||||
void ReceiveRtcpSr(int64_t rtt,
|
||||
uint32_t rtcp_timestamp,
|
||||
uint32_t ntp_seconds,
|
||||
uint32_t ntp_fractions) {
|
||||
UpdateRtcpTimestamp(rtt, ntp_seconds, ntp_fractions, rtcp_timestamp, true);
|
||||
}
|
||||
|
||||
SimulatedClock local_clock_;
|
||||
SimulatedClock remote_clock_;
|
||||
std::unique_ptr<RemoteNtpTimeEstimator> estimator_;
|
||||
SimulatedClock local_clock_{kLocalClockInitialTime};
|
||||
SimulatedClock remote_clock_{kRemoteClockInitialTime};
|
||||
RemoteNtpTimeEstimator estimator_{&local_clock_};
|
||||
};
|
||||
|
||||
TEST_F(RemoteNtpTimeEstimatorTest, Estimate) {
|
||||
// Failed without valid NTP.
|
||||
UpdateRtcpTimestamp(kTestRtt, 0, 0, 0, false);
|
||||
TEST_F(RemoteNtpTimeEstimatorTest, FailsWithoutValidNtpTime) {
|
||||
EXPECT_FALSE(
|
||||
estimator_.UpdateRtcpTimestamp(kTestRtt, NtpTime(), /*rtp_timestamp=*/0));
|
||||
}
|
||||
|
||||
AdvanceTimeMilliseconds(1000);
|
||||
TEST_F(RemoteNtpTimeEstimatorTest, Estimate) {
|
||||
// Remote peer sends first RTCP SR.
|
||||
SendRtcpSr();
|
||||
|
||||
// Remote sends a RTP packet.
|
||||
AdvanceTimeMilliseconds(15);
|
||||
AdvanceTime(TimeDelta::Millis(15));
|
||||
uint32_t rtp_timestamp = GetRemoteTimestamp();
|
||||
int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
|
||||
|
||||
// Local peer needs at least 2 RTCP SR to calculate the capture time.
|
||||
const int64_t kNotEnoughRtcpSr = -1;
|
||||
EXPECT_EQ(kNotEnoughRtcpSr, estimator_->Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(absl::nullopt, estimator_->EstimateRemoteToLocalClockOffsetMs());
|
||||
EXPECT_EQ(kNotEnoughRtcpSr, estimator_.Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(estimator_.EstimateRemoteToLocalClockOffset(), absl::nullopt);
|
||||
|
||||
AdvanceTimeMilliseconds(800);
|
||||
AdvanceTime(TimeDelta::Millis(800));
|
||||
// Remote sends second RTCP SR.
|
||||
SendRtcpSr();
|
||||
|
||||
// Local peer gets enough RTCP SR to calculate the capture time.
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
|
||||
estimator_->EstimateRemoteToLocalClockOffsetMs());
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_.Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(estimator_.EstimateRemoteToLocalClockOffset(),
|
||||
kRemoteToLocalClockOffsetNtp);
|
||||
}
|
||||
|
||||
TEST_F(RemoteNtpTimeEstimatorTest, AveragesErrorsOut) {
|
||||
// Remote peer sends first 10 RTCP SR without errors.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
AdvanceTimeMilliseconds(1000);
|
||||
AdvanceTime(TimeDelta::Seconds(1));
|
||||
SendRtcpSr();
|
||||
}
|
||||
|
||||
AdvanceTimeMilliseconds(150);
|
||||
AdvanceTime(TimeDelta::Millis(150));
|
||||
uint32_t rtp_timestamp = GetRemoteTimestamp();
|
||||
int64_t capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
|
||||
// Local peer gets enough RTCP SR to calculate the capture time.
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
|
||||
estimator_->EstimateRemoteToLocalClockOffsetMs());
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_.Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(kRemoteToLocalClockOffsetNtp,
|
||||
estimator_.EstimateRemoteToLocalClockOffset());
|
||||
|
||||
// Remote sends corrupted RTCP SRs
|
||||
AdvanceTimeMilliseconds(1000);
|
||||
SendRtcpSrInaccurately(/*ntp_error_ms=*/2, /*networking_delay_ms=*/-1);
|
||||
AdvanceTimeMilliseconds(1000);
|
||||
SendRtcpSrInaccurately(/*ntp_error_ms=*/-2, /*networking_delay_ms=*/1);
|
||||
AdvanceTime(TimeDelta::Seconds(1));
|
||||
SendRtcpSrInaccurately(/*ntp_error=*/TimeDelta::Millis(2),
|
||||
/*networking_delay=*/TimeDelta::Millis(-1));
|
||||
AdvanceTime(TimeDelta::Seconds(1));
|
||||
SendRtcpSrInaccurately(/*ntp_error=*/TimeDelta::Millis(-2),
|
||||
/*networking_delay=*/TimeDelta::Millis(1));
|
||||
|
||||
// New RTP packet to estimate timestamp.
|
||||
AdvanceTimeMilliseconds(150);
|
||||
AdvanceTime(TimeDelta::Millis(150));
|
||||
rtp_timestamp = GetRemoteTimestamp();
|
||||
capture_ntp_time_ms = local_clock_.CurrentNtpInMilliseconds();
|
||||
|
||||
// Errors should be averaged out.
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_->Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(kRemoteToLocalClockOffsetMs,
|
||||
estimator_->EstimateRemoteToLocalClockOffsetMs());
|
||||
EXPECT_EQ(capture_ntp_time_ms, estimator_.Estimate(rtp_timestamp));
|
||||
EXPECT_EQ(kRemoteToLocalClockOffsetNtp,
|
||||
estimator_.EstimateRemoteToLocalClockOffset());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace webrtc
|
||||
|
@ -34,6 +34,14 @@ inline uint32_t CompactNtp(NtpTime ntp) {
|
||||
// Negative values converted to 0, Overlarge values converted to max uint32_t.
|
||||
uint32_t SaturatedToCompactNtp(TimeDelta delta);
|
||||
|
||||
// Convert interval to the NTP time resolution (1/2^32 seconds ~= 0.2 ns).
|
||||
inline constexpr int64_t ToNtpUnits(TimeDelta delta) {
|
||||
// For better precision `delta` is taken with best TimeDelta precision (us),
|
||||
// then multiplaction and conversion to seconds are swapped to avoid float
|
||||
// arithmetic.
|
||||
return (delta.us() * (int64_t{1} << 32)) / 1'000'000;
|
||||
}
|
||||
|
||||
// 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 are considered negative and are converted to
|
||||
|
@ -95,4 +95,20 @@ TEST(TimeUtilTest, SaturatedToCompactNtp) {
|
||||
5'515, 16);
|
||||
}
|
||||
|
||||
TEST(TimeUtilTest, ToNtpUnits) {
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Zero()), 0);
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Seconds(1)), int64_t{1} << 32);
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Seconds(-1)), -(int64_t{1} << 32));
|
||||
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Millis(500)), int64_t{1} << 31);
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Millis(-1'500)), -(int64_t{3} << 31));
|
||||
|
||||
// Smallest TimeDelta that can be converted without precision loss.
|
||||
EXPECT_EQ(ToNtpUnits(TimeDelta::Micros(15'625)), int64_t{1} << 26);
|
||||
|
||||
// 1 us ~= 4'294.97 NTP units. ToNtpUnits makes no rounding promises.
|
||||
EXPECT_GE(ToNtpUnits(TimeDelta::Micros(1)), 4'294);
|
||||
EXPECT_LE(ToNtpUnits(TimeDelta::Micros(1)), 4'295);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -1122,12 +1122,13 @@ bool RtpVideoStreamReceiver::DeliverRtcp(const uint8_t* rtcp_packet,
|
||||
clock_->CurrentNtpInMilliseconds() - received_ntp.ToMs();
|
||||
// Don't use old SRs to estimate time.
|
||||
if (time_since_received <= 1) {
|
||||
ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset_ms =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffsetMs();
|
||||
if (remote_to_local_clock_offset_ms.has_value()) {
|
||||
ntp_estimator_.UpdateRtcpTimestamp(
|
||||
TimeDelta::Millis(rtt), NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffset();
|
||||
if (remote_to_local_clock_offset.has_value()) {
|
||||
capture_clock_offset_updater_.SetRemoteToLocalClockOffset(
|
||||
Int64MsToQ32x32(*remote_to_local_clock_offset_ms));
|
||||
*remote_to_local_clock_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1042,12 +1042,13 @@ bool RtpVideoStreamReceiver2::DeliverRtcp(const uint8_t* rtcp_packet,
|
||||
clock_->CurrentNtpInMilliseconds() - received_ntp.ToMs();
|
||||
// Don't use old SRs to estimate time.
|
||||
if (time_since_received <= 1) {
|
||||
ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset_ms =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffsetMs();
|
||||
if (remote_to_local_clock_offset_ms.has_value()) {
|
||||
ntp_estimator_.UpdateRtcpTimestamp(
|
||||
TimeDelta::Millis(rtt), NtpTime(ntp_secs, ntp_frac), rtp_timestamp);
|
||||
absl::optional<int64_t> remote_to_local_clock_offset =
|
||||
ntp_estimator_.EstimateRemoteToLocalClockOffset();
|
||||
if (remote_to_local_clock_offset.has_value()) {
|
||||
capture_clock_offset_updater_.SetRemoteToLocalClockOffset(
|
||||
Int64MsToQ32x32(*remote_to_local_clock_offset_ms));
|
||||
*remote_to_local_clock_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user