diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc index 93f534e0c4..d00a9a9469 100644 --- a/audio/channel_receive.cc +++ b/audio/channel_receive.cc @@ -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 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 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); } } } diff --git a/audio/voip/audio_ingress.cc b/audio/voip/audio_ingress.cc index 8aa552bb28..71026e84e0 100644 --- a/audio/voip/audio_ingress.cc +++ b/audio/voip/audio_ingress.cc @@ -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); } } diff --git a/modules/rtp_rtcp/include/remote_ntp_time_estimator.h b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h index f31503dc4e..2c1eeb35af 100644 --- a/modules/rtp_rtcp/include/remote_ntp_time_estimator.h +++ b/modules/rtp_rtcp/include/remote_ntp_time_estimator.h @@ -13,7 +13,10 @@ #include +#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 EstimateRemoteToLocalClockOffsetMs(); + ABSL_DEPRECATED("Use EstimateRemoteToLocalClockOffset.") + absl::optional EstimateRemoteToLocalClockOffsetMs() { + if (absl::optional 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 EstimateRemoteToLocalClockOffset(); private: Clock* clock_; + // Offset is measured with the same precision as NtpTime: in 1/2^32 seconds ~= + // 0.2 ns. MovingMedianFilter ntp_clocks_offset_estimator_; RtpToNtpEstimator rtp_to_ntp_; - int64_t last_timing_log_ms_; + Timestamp last_timing_log_ = Timestamp::MinusInfinity(); }; } // namespace webrtc diff --git a/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc b/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc index b1602e5dcd..6f90cd175c 100644 --- a/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc +++ b/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc @@ -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(minuend); + uint64_t b = static_cast(subtrahend); + return a >= b ? static_cast(a - b) : -static_cast(b - a); +} + +NtpTime Add(NtpTime lhs, int64_t rhs) { + uint64_t result = static_cast(lhs); + if (rhs >= 0) { + result += static_cast(rhs); + } else { + result -= static_cast(-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 -RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffsetMs() { +RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffset() { if (ntp_clocks_offset_estimator_.GetNumberOfSamplesStored() < kMinimumNumberOfSamples) { return absl::nullopt; diff --git a/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc index 73c3e9b9b8..8dbfaec940 100644 --- a/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc +++ b/modules/rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc @@ -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(NtpTime::kFractionsPerSecond) / - 1000; - NtpTime ntp(static_cast(GetRemoteNtpTime()) + + int64_t ntp_error_fractions = ToNtpUnits(ntp_error); + NtpTime ntp(static_cast(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 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 diff --git a/modules/rtp_rtcp/source/time_util.h b/modules/rtp_rtcp/source/time_util.h index fba2dd9ff4..5e72bba3b9 100644 --- a/modules/rtp_rtcp/source/time_util.h +++ b/modules/rtp_rtcp/source/time_util.h @@ -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 diff --git a/modules/rtp_rtcp/source/time_util_unittest.cc b/modules/rtp_rtcp/source/time_util_unittest.cc index 983155e8a3..f77c3c6e5d 100644 --- a/modules/rtp_rtcp/source/time_util_unittest.cc +++ b/modules/rtp_rtcp/source/time_util_unittest.cc @@ -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 diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc index 04484b91cc..5a268398f7 100644 --- a/video/rtp_video_stream_receiver.cc +++ b/video/rtp_video_stream_receiver.cc @@ -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 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 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); } } diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc index 9956760c3b..46fa2d94e7 100644 --- a/video/rtp_video_stream_receiver2.cc +++ b/video/rtp_video_stream_receiver2.cc @@ -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 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 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); } }