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 
19 namespace webrtc {
20 
21 namespace {
22 
23 constexpr int kMinimumNumberOfSamples = 2;
24 constexpr int kTimingLogIntervalMs = 10000;
25 constexpr int kClocksOffsetSmoothingWindow = 100;
26 
27 }  // namespace
28 
29 // TODO(wu): Refactor this class so that it can be shared with
30 // vie_sync_module.cc.
RemoteNtpTimeEstimator(Clock * clock)31 RemoteNtpTimeEstimator::RemoteNtpTimeEstimator(Clock* clock)
32     : clock_(clock),
33       ntp_clocks_offset_estimator_(kClocksOffsetSmoothingWindow),
34       last_timing_log_ms_(-1) {}
35 
~RemoteNtpTimeEstimator()36 RemoteNtpTimeEstimator::~RemoteNtpTimeEstimator() {}
37 
UpdateRtcpTimestamp(int64_t rtt,uint32_t ntp_secs,uint32_t ntp_frac,uint32_t rtp_timestamp)38 bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
39                                                  uint32_t ntp_secs,
40                                                  uint32_t ntp_frac,
41                                                  uint32_t rtp_timestamp) {
42   bool new_rtcp_sr = false;
43   if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtp_timestamp,
44                                       &new_rtcp_sr)) {
45     return false;
46   }
47   if (!new_rtcp_sr) {
48     // No new RTCP SR since last time this function was called.
49     return true;
50   }
51 
52   // Update extrapolator with the new arrival time.
53   // The extrapolator assumes the ntp time.
54   int64_t receiver_arrival_time_ms =
55       clock_->TimeInMilliseconds() + NtpOffsetMs();
56   int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac);
57   int64_t sender_arrival_time_ms = sender_send_time_ms + rtt / 2;
58   int64_t remote_to_local_clocks_offset =
59       receiver_arrival_time_ms - sender_arrival_time_ms;
60   ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset);
61   return true;
62 }
63 
Estimate(uint32_t rtp_timestamp)64 int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
65   int64_t sender_capture_ntp_ms = 0;
66   if (!rtp_to_ntp_.Estimate(rtp_timestamp, &sender_capture_ntp_ms)) {
67     return -1;
68   }
69 
70   int64_t remote_to_local_clocks_offset =
71       ntp_clocks_offset_estimator_.GetFilteredValue();
72   int64_t receiver_capture_ntp_ms =
73       sender_capture_ntp_ms + remote_to_local_clocks_offset;
74 
75   // TODO(bugs.webrtc.org/11327): Clock::CurrentNtpInMilliseconds() was
76   // previously used to calculate the offset between the local and the remote
77   // clock. However, rtc::TimeMillis() + NtpOffsetMs() is now used as the local
78   // ntp clock value. To preserve the old behavior of this method, the return
79   // value is adjusted with the difference between the two local ntp clocks.
80   int64_t now_ms = clock_->TimeInMilliseconds();
81   int64_t offset_between_local_ntp_clocks =
82       clock_->CurrentNtpInMilliseconds() - now_ms - NtpOffsetMs();
83   receiver_capture_ntp_ms += offset_between_local_ntp_clocks;
84 
85   if (now_ms - last_timing_log_ms_ > kTimingLogIntervalMs) {
86     RTC_LOG(LS_INFO) << "RTP timestamp: " << rtp_timestamp
87                      << " in NTP clock: " << sender_capture_ntp_ms
88                      << " estimated time in receiver NTP clock: "
89                      << receiver_capture_ntp_ms;
90     last_timing_log_ms_ = now_ms;
91   }
92   return receiver_capture_ntp_ms;
93 }
94 
95 absl::optional<int64_t>
EstimateRemoteToLocalClockOffsetMs()96 RemoteNtpTimeEstimator::EstimateRemoteToLocalClockOffsetMs() {
97   if (ntp_clocks_offset_estimator_.GetNumberOfSamplesStored() <
98       kMinimumNumberOfSamples) {
99     return absl::nullopt;
100   }
101   return ntp_clocks_offset_estimator_.GetFilteredValue();
102 }
103 
104 }  // namespace webrtc
105