1 /*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/rtp_rtcp/include/remote_ntp_time_estimator.h"
12
13 #include <cstdint>
14
15 #include "modules/rtp_rtcp/source/time_util.h"
16 #include "rtc_base/logging.h"
17 #include "system_wrappers/include/clock.h"
18 #include "system_wrappers/include/ntp_time.h"
19
20 namespace webrtc {
21
22 namespace {
23
24 constexpr int kMinimumNumberOfSamples = 2;
25 constexpr TimeDelta kTimingLogInterval = TimeDelta::Seconds(10);
26 constexpr int kClocksOffsetSmoothingWindow = 100;
27
28 // Subtracts two NtpTime values keeping maximum precision.
Subtract(NtpTime minuend,NtpTime subtrahend)29 int64_t Subtract(NtpTime minuend, NtpTime subtrahend) {
30 uint64_t a = static_cast<uint64_t>(minuend);
31 uint64_t b = static_cast<uint64_t>(subtrahend);
32 return a >= b ? static_cast<int64_t>(a - b) : -static_cast<int64_t>(b - a);
33 }
34
Add(NtpTime lhs,int64_t rhs)35 NtpTime Add(NtpTime lhs, int64_t rhs) {
36 uint64_t result = static_cast<uint64_t>(lhs);
37 if (rhs >= 0) {
38 result += static_cast<uint64_t>(rhs);
39 } else {
40 result -= static_cast<uint64_t>(-rhs);
41 }
42 return NtpTime(result);
43 }
44
45 } // namespace
46
47 // TODO(wu): Refactor this class so that it can be shared with
48 // vie_sync_module.cc.
RemoteNtpTimeEstimator(Clock * clock)49 RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock)
50 : clock_(clock),
51 ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow) {}
52
UpdateRtcpTimestamp(TimeDelta rtt,NtpTime sender_send_time,uint32_t rtp_timestamp)53 bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(TimeDelta rtt,
54 NtpTime sender_send_time,
55 uint32_t rtp_timestamp) {
56 switch (rtp_to_ntp_.UpdateMeasurements(sender_send_time, rtp_timestamp)) {
57 case RtpToNtpEstimator::kInvalidMeasurement:
58 return false;
59 case RtpToNtpEstimator::kSameMeasurement:
60 // No new RTCP SR since last time this function was called.
61 return true;
62 case RtpToNtpEstimator::kNewMeasurement:
63 break;
64 }
65
66 // Assume connection is symmetric and thus time to deliver the packet is half
67 // the round trip time.
68 int64_t deliver_time_ntp = ToNtpUnits(rtt) / 2;
69
70 // Update extrapolator with the new arrival time.
71 NtpTime receiver_arrival_time = clock_->CurrentNtpTime();
72 int64_t remote_to_local_clocks_offset =
73 Subtract(receiver_arrival_time, sender_send_time) - deliver_time_ntp;
74 ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset);
75 return true;
76 }
77
EstimateNtp(uint32_t rtp_timestamp)78 NtpTime RemoteNtpTimeEstimator::EstimateNtp(uint32_t rtp_timestamp) {
79 NtpTime sender_capture = rtp_to_ntp_.Estimate(rtp_timestamp);
80 if (!sender_capture.Valid()) {
81 return sender_capture;
82 }
83
84 int64_t remote_to_local_clocks_offset =
85 ntp_clocks_offset_estimator_.GetFilteredValue();
86 NtpTime receiver_capture = Add(sender_capture, remote_to_local_clocks_offset);
87
88 Timestamp now = clock_->CurrentTime();
89 if (now - last_timing_log_ > kTimingLogInterval) {
90 RTC_LOG(LS_INFO) << "RTP timestamp: " << rtp_timestamp
91 << " in NTP clock: " << sender_capture.ToMs()
92 << " estimated time in receiver NTP clock: "
93 << receiver_capture.ToMs();
94 last_timing_log_ = now;
95 }
96
97 return receiver_capture;
98 }
99
100 absl::optional<int64_t>
EstimateRemoteToLocalClockOffset()101 RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffset() {
102 if (ntp_clocks_offset_estimator_.GetNumberOfSamplesStored() <
103 kMinimumNumberOfSamples) {
104 return absl::nullopt;
105 }
106 return ntp_clocks_offset_estimator_.GetFilteredValue();
107 }
108
109 } // namespace webrtc
110