Make class of static functions in rtp_to_ntp.h:
- UpdateRtcpList
- RtpToNtp

class RtpToNtpEstimator
- UpdateMeasurements
- Estimate

List with rtcp measurements is now private.

BUG=none

Review-Url: https://codereview.webrtc.org/2574133003
Cr-Commit-Position: refs/heads/master@{#15762}
diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc
index e03c26d..782b45c 100644
--- a/webrtc/call/call_perf_tests.cc
+++ b/webrtc/call/call_perf_tests.cc
@@ -24,7 +24,6 @@
 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/include/metrics_default.h"
-#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
 #include "webrtc/test/call_test.h"
 #include "webrtc/test/direct_transport.h"
 #include "webrtc/test/drifting_clock.h"
diff --git a/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h b/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
index cab488f..118df4c 100644
--- a/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
+++ b/webrtc/modules/rtp_rtcp/include/remote_ntp_time_estimator.h
@@ -14,7 +14,7 @@
 #include <memory>
 
 #include "webrtc/base/constructormagic.h"
-#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
+#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
 
 namespace webrtc {
 
@@ -43,7 +43,7 @@
  private:
   Clock* clock_;
   std::unique_ptr<TimestampExtrapolator> ts_extrapolator_;
-  RtcpMeasurements rtcp_list_;
+  RtpToNtpEstimator rtp_to_ntp_;
   int64_t last_timing_log_ms_;
   RTC_DISALLOW_COPY_AND_ASSIGN(RemoteNtpTimeEstimator);
 };
diff --git a/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc b/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
index 69a8f23..c78a8bc 100644
--- a/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
+++ b/webrtc/modules/rtp_rtcp/source/remote_ntp_time_estimator.cc
@@ -33,8 +33,8 @@
                                                  uint32_t ntp_frac,
                                                  uint32_t rtcp_timestamp) {
   bool new_rtcp_sr = false;
-  if (!UpdateRtcpList(
-      ntp_secs, ntp_frac, rtcp_timestamp, &rtcp_list_, &new_rtcp_sr)) {
+  if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtcp_timestamp,
+                                      &new_rtcp_sr)) {
     return false;
   }
   if (!new_rtcp_sr) {
@@ -52,7 +52,7 @@
 
 int64_t RemoteNtpTimeEstimator::Estimate(uint32_t rtp_timestamp) {
   int64_t sender_capture_ntp_ms = 0;
-  if (!RtpToNtpMs(rtp_timestamp, rtcp_list_, &sender_capture_ntp_ms)) {
+  if (!rtp_to_ntp_.Estimate(rtp_timestamp, &sender_capture_ntp_ms)) {
     return -1;
   }
   uint32_t timestamp = sender_capture_ntp_ms * 90;
diff --git a/webrtc/system_wrappers/BUILD.gn b/webrtc/system_wrappers/BUILD.gn
index 7f56fd8..745867b 100644
--- a/webrtc/system_wrappers/BUILD.gn
+++ b/webrtc/system_wrappers/BUILD.gn
@@ -28,7 +28,7 @@
     "include/logging.h",
     "include/metrics.h",
     "include/ntp_time.h",
-    "include/rtp_to_ntp.h",
+    "include/rtp_to_ntp_estimator.h",
     "include/rw_lock_wrapper.h",
     "include/sleep.h",
     "include/static_instance.h",
@@ -50,7 +50,7 @@
     "source/event_timer_win.h",
     "source/file_impl.cc",
     "source/logging.cc",
-    "source/rtp_to_ntp.cc",
+    "source/rtp_to_ntp_estimator.cc",
     "source/rw_lock.cc",
     "source/rw_lock_posix.cc",
     "source/rw_lock_posix.h",
@@ -179,7 +179,7 @@
       "source/metrics_default_unittest.cc",
       "source/metrics_unittest.cc",
       "source/ntp_time_unittest.cc",
-      "source/rtp_to_ntp_unittest.cc",
+      "source/rtp_to_ntp_estimator_unittest.cc",
       "source/stringize_macros_unittest.cc",
     ]
     configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/webrtc/system_wrappers/include/rtp_to_ntp.h b/webrtc/system_wrappers/include/rtp_to_ntp.h
deleted file mode 100644
index c1e7ab6..0000000
--- a/webrtc/system_wrappers/include/rtp_to_ntp.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_
-#define SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_
-
-#include <list>
-
-#include "webrtc/system_wrappers/include/ntp_time.h"
-#include "webrtc/typedefs.h"
-
-namespace webrtc {
-
-struct RtcpMeasurement {
-  RtcpMeasurement();
-  RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp);
-  bool IsEqual(const RtcpMeasurement& other) const;
-
-  NtpTime ntp_time;
-  uint32_t rtp_timestamp;
-};
-
-struct RtcpMeasurements {
-  RtcpMeasurements();
-  ~RtcpMeasurements();
-  bool Contains(const RtcpMeasurement& other) const;
-  bool IsValid(const RtcpMeasurement& other) const;
-  void UpdateParameters();
-
-  // Estimated parameters from RTP and NTP timestamp pairs in |list|.
-  struct RtpToNtpParameters {
-    double frequency_khz = 0.0;
-    double offset_ms = 0.0;
-    bool calculated = false;
-  };
-
-  std::list<RtcpMeasurement> list;
-  RtpToNtpParameters params;
-};
-
-// Updates |list| in |rtcp_measurements| with timestamps from the RTCP SR.
-// |new_rtcp_sr| will be set to true if these are the timestamps which have
-// never be added to |list|.
-// |rtcp_measurements.params| are estimated from the RTP and NTP timestamp pairs
-// in the |list| when a new RTCP SR is inserted.
-bool UpdateRtcpList(uint32_t ntp_secs,
-                    uint32_t ntp_frac,
-                    uint32_t rtp_timestamp,
-                    RtcpMeasurements* rtcp_measurements,
-                    bool* new_rtcp_sr);
-
-// Converts an RTP timestamp to the NTP domain in milliseconds using the
-// estimated |rtcp_measurements.params|.
-bool RtpToNtpMs(int64_t rtp_timestamp,
-                const RtcpMeasurements& rtcp_measurements,
-                int64_t* rtp_timestamp_in_ms);
-
-// Returns 1 there has been a forward wrap around, 0 if there has been no wrap
-// around and -1 if there has been a backwards wrap around (i.e. reordering).
-int CheckForWrapArounds(uint32_t rtp_timestamp, uint32_t rtcp_rtp_timestamp);
-
-}  // namespace webrtc
-
-#endif  // SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_H_
diff --git a/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h b/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h
new file mode 100644
index 0000000..a17428b
--- /dev/null
+++ b/webrtc/system_wrappers/include/rtp_to_ntp_estimator.h
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
+#define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
+
+#include <list>
+
+#include "webrtc/system_wrappers/include/ntp_time.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+// Class for converting an RTP timestamp to the NTP domain in milliseconds.
+// The class needs to be trained with (at least 2) RTP/NTP timestamp pairs from
+// RTCP sender reports before the convertion can be done.
+class RtpToNtpEstimator {
+ public:
+  RtpToNtpEstimator();
+  ~RtpToNtpEstimator();
+
+  // RTP and NTP timestamp pair from a RTCP SR report.
+  struct RtcpMeasurement {
+    RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp);
+    bool IsEqual(const RtcpMeasurement& other) const;
+
+    NtpTime ntp_time;
+    uint32_t rtp_timestamp;
+  };
+
+  // Estimated parameters from RTP and NTP timestamp pairs in |measurements_|.
+  struct Parameters {
+    double frequency_khz = 0.0;
+    double offset_ms = 0.0;
+    bool calculated = false;
+  };
+
+  // Updates measurements with RTP/NTP timestamp pair from a RTCP sender report.
+  // |new_rtcp_sr| is set to true if a new report is added.
+  bool UpdateMeasurements(uint32_t ntp_secs,
+                          uint32_t ntp_frac,
+                          uint32_t rtp_timestamp,
+                          bool* new_rtcp_sr);
+
+  // Converts an RTP timestamp to the NTP domain in milliseconds.
+  // Returns true on success, false otherwise.
+  bool Estimate(int64_t rtp_timestamp, int64_t* rtp_timestamp_ms) const;
+
+  const Parameters& params() const { return params_; }
+
+ private:
+  void UpdateParameters();
+
+  std::list<RtcpMeasurement> measurements_;
+  Parameters params_;
+};
+
+// Returns:
+//  1: forward wrap around.
+//  0: no wrap around.
+// -1: backwards wrap around (i.e. reordering).
+int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp);
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_RTP_TO_NTP_ESTIMATOR_H_
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp.cc b/webrtc/system_wrappers/source/rtp_to_ntp.cc
deleted file mode 100644
index cbd5020..0000000
--- a/webrtc/system_wrappers/source/rtp_to_ntp.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
-
-#include "webrtc/base/logging.h"
-#include "webrtc/system_wrappers/include/clock.h"
-
-namespace webrtc {
-namespace {
-// Number of RTCP SR reports to use to map between RTP and NTP.
-const size_t kNumRtcpReportsToUse = 2;
-
-// Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
-bool CalculateFrequency(int64_t rtcp_ntp_ms1,
-                        uint32_t rtp_timestamp1,
-                        int64_t rtcp_ntp_ms2,
-                        uint32_t rtp_timestamp2,
-                        double* frequency_khz) {
-  if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) {
-    return false;
-  }
-  *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
-      static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2);
-  return true;
-}
-
-// Detects if there has been a wraparound between |old_timestamp| and
-// |new_timestamp|, and compensates by adding 2^32 if that is the case.
-bool CompensateForWrapAround(uint32_t new_timestamp,
-                             uint32_t old_timestamp,
-                             int64_t* compensated_timestamp) {
-  int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
-  if (wraps < 0) {
-    // Reordering, don't use this packet.
-    return false;
-  }
-  *compensated_timestamp = new_timestamp + (wraps << 32);
-  return true;
-}
-}  // namespace
-
-// Class holding RTP and NTP timestamp from a RTCP SR report.
-RtcpMeasurement::RtcpMeasurement() : ntp_time(0, 0), rtp_timestamp(0) {}
-
-RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
-                                 uint32_t ntp_frac,
-                                 uint32_t timestamp)
-    : ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {}
-
-bool RtcpMeasurement::IsEqual(const RtcpMeasurement& other) const {
-  // Use || since two equal timestamps will result in zero frequency and in
-  // RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency.
-  return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp);
-}
-
-// Class holding list of RTP and NTP timestamp pairs.
-RtcpMeasurements::RtcpMeasurements() {}
-RtcpMeasurements::~RtcpMeasurements() {}
-
-bool RtcpMeasurements::Contains(const RtcpMeasurement& other) const {
-  for (const auto& it : list) {
-    if (it.IsEqual(other))
-      return true;
-  }
-  return false;
-}
-
-bool RtcpMeasurements::IsValid(const RtcpMeasurement& other) const {
-  if (!other.ntp_time.Valid())
-    return false;
-
-  int64_t ntp_ms_new = other.ntp_time.ToMs();
-  for (const auto& it : list) {
-    if (ntp_ms_new <= it.ntp_time.ToMs()) {
-      // Old report.
-      return false;
-    }
-    int64_t timestamp_new = other.rtp_timestamp;
-    if (!CompensateForWrapAround(timestamp_new, it.rtp_timestamp,
-                                 &timestamp_new)) {
-      return false;
-    }
-    if (timestamp_new <= it.rtp_timestamp) {
-      LOG(LS_WARNING) << "Newer RTCP SR report with older RTP timestamp.";
-      return false;
-    }
-  }
-  return true;
-}
-
-void RtcpMeasurements::UpdateParameters() {
-  if (list.size() != kNumRtcpReportsToUse)
-    return;
-
-  int64_t timestamp_new = list.front().rtp_timestamp;
-  int64_t timestamp_old = list.back().rtp_timestamp;
-  if (!CompensateForWrapAround(timestamp_new, timestamp_old, &timestamp_new))
-    return;
-
-  int64_t ntp_ms_new = list.front().ntp_time.ToMs();
-  int64_t ntp_ms_old = list.back().ntp_time.ToMs();
-
-  if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old,
-                          &params.frequency_khz)) {
-    return;
-  }
-  params.offset_ms = timestamp_new - params.frequency_khz * ntp_ms_new;
-  params.calculated = true;
-}
-
-// Updates list holding NTP and RTP timestamp pairs.
-bool UpdateRtcpList(uint32_t ntp_secs,
-                    uint32_t ntp_frac,
-                    uint32_t rtp_timestamp,
-                    RtcpMeasurements* rtcp_measurements,
-                    bool* new_rtcp_sr) {
-  *new_rtcp_sr = false;
-
-  RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp);
-  if (rtcp_measurements->Contains(measurement)) {
-    // RTCP SR report already added.
-    return true;
-  }
-
-  if (!rtcp_measurements->IsValid(measurement)) {
-    // Old report or invalid parameters.
-    return false;
-  }
-
-  // Insert new RTCP SR report.
-  if (rtcp_measurements->list.size() == kNumRtcpReportsToUse)
-    rtcp_measurements->list.pop_back();
-
-  rtcp_measurements->list.push_front(measurement);
-  *new_rtcp_sr = true;
-
-  // List updated, calculate new parameters.
-  rtcp_measurements->UpdateParameters();
-  return true;
-}
-
-// Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp
-// pairs in |rtcp|. The converted timestamp is returned in
-// |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP
-// timestamps and returns false if it can't do the conversion due to reordering.
-bool RtpToNtpMs(int64_t rtp_timestamp,
-                const RtcpMeasurements& rtcp,
-                int64_t* rtp_timestamp_in_ms) {
-  if (!rtcp.params.calculated || rtcp.list.empty())
-    return false;
-
-  uint32_t rtcp_timestamp_old = rtcp.list.back().rtp_timestamp;
-  int64_t rtp_timestamp_unwrapped;
-  if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old,
-                               &rtp_timestamp_unwrapped)) {
-    return false;
-  }
-
-  double rtp_timestamp_ms =
-      (static_cast<double>(rtp_timestamp_unwrapped) - rtcp.params.offset_ms) /
-          rtcp.params.frequency_khz +
-      0.5f;
-  if (rtp_timestamp_ms < 0) {
-    return false;
-  }
-  *rtp_timestamp_in_ms = rtp_timestamp_ms;
-  return true;
-}
-
-int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
-  if (new_timestamp < old_timestamp) {
-    // This difference should be less than -2^31 if we have had a wrap around
-    // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
-    // cast to a int32_t, it should be positive.
-    if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
-      // Forward wrap around.
-      return 1;
-    }
-  } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
-    // This difference should be less than -2^31 if we have had a backward wrap
-    // around. Since it is cast to a int32_t, it should be positive.
-    return -1;
-  }
-  return 0;
-}
-
-}  // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc b/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
new file mode 100644
index 0000000..339635e
--- /dev/null
+++ b/webrtc/system_wrappers/source/rtp_to_ntp_estimator.cc
@@ -0,0 +1,188 @@
+/*
+ *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
+
+#include "webrtc/base/logging.h"
+#include "webrtc/system_wrappers/include/clock.h"
+
+namespace webrtc {
+namespace {
+// Number of RTCP SR reports to use to map between RTP and NTP.
+const size_t kNumRtcpReportsToUse = 2;
+
+// Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
+bool CalculateFrequency(int64_t ntp_ms1,
+                        uint32_t rtp_timestamp1,
+                        int64_t ntp_ms2,
+                        uint32_t rtp_timestamp2,
+                        double* frequency_khz) {
+  if (ntp_ms1 <= ntp_ms2)
+    return false;
+
+  *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
+                   static_cast<double>(ntp_ms1 - ntp_ms2);
+  return true;
+}
+
+// Detects if there has been a wraparound between |old_timestamp| and
+// |new_timestamp|, and compensates by adding 2^32 if that is the case.
+bool CompensateForWrapAround(uint32_t new_timestamp,
+                             uint32_t old_timestamp,
+                             int64_t* compensated_timestamp) {
+  int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
+  if (wraps < 0) {
+    // Reordering, don't use this packet.
+    return false;
+  }
+  *compensated_timestamp = new_timestamp + (wraps << 32);
+  return true;
+}
+
+bool Contains(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements,
+              const RtpToNtpEstimator::RtcpMeasurement& other) {
+  for (const auto& measurement : measurements) {
+    if (measurement.IsEqual(other))
+      return true;
+  }
+  return false;
+}
+
+bool IsValid(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements,
+             const RtpToNtpEstimator::RtcpMeasurement& other) {
+  if (!other.ntp_time.Valid())
+    return false;
+
+  int64_t ntp_ms_new = other.ntp_time.ToMs();
+  for (const auto& measurement : measurements) {
+    if (ntp_ms_new <= measurement.ntp_time.ToMs()) {
+      // Old report.
+      return false;
+    }
+    int64_t timestamp_new = other.rtp_timestamp;
+    if (!CompensateForWrapAround(timestamp_new, measurement.rtp_timestamp,
+                                 &timestamp_new)) {
+      return false;
+    }
+    if (timestamp_new <= measurement.rtp_timestamp) {
+      LOG(LS_WARNING) << "Newer RTCP SR report with older RTP timestamp.";
+      return false;
+    }
+  }
+  return true;
+}
+}  // namespace
+
+RtpToNtpEstimator::RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
+                                                    uint32_t ntp_frac,
+                                                    uint32_t timestamp)
+    : ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {}
+
+bool RtpToNtpEstimator::RtcpMeasurement::IsEqual(
+    const RtcpMeasurement& other) const {
+  // Use || since two equal timestamps will result in zero frequency and in
+  // RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency.
+  return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp);
+}
+
+// Class for converting an RTP timestamp to the NTP domain.
+RtpToNtpEstimator::RtpToNtpEstimator() {}
+RtpToNtpEstimator::~RtpToNtpEstimator() {}
+
+void RtpToNtpEstimator::UpdateParameters() {
+  if (measurements_.size() != kNumRtcpReportsToUse)
+    return;
+
+  int64_t timestamp_new = measurements_.front().rtp_timestamp;
+  int64_t timestamp_old = measurements_.back().rtp_timestamp;
+  if (!CompensateForWrapAround(timestamp_new, timestamp_old, &timestamp_new))
+    return;
+
+  int64_t ntp_ms_new = measurements_.front().ntp_time.ToMs();
+  int64_t ntp_ms_old = measurements_.back().ntp_time.ToMs();
+
+  if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old,
+                          &params_.frequency_khz)) {
+    return;
+  }
+  params_.offset_ms = timestamp_new - params_.frequency_khz * ntp_ms_new;
+  params_.calculated = true;
+}
+
+bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs,
+                                           uint32_t ntp_frac,
+                                           uint32_t rtp_timestamp,
+                                           bool* new_rtcp_sr) {
+  *new_rtcp_sr = false;
+
+  RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp);
+  if (Contains(measurements_, measurement)) {
+    // RTCP SR report already added.
+    return true;
+  }
+  if (!IsValid(measurements_, measurement)) {
+    // Old report or invalid parameters.
+    return false;
+  }
+
+  // Insert new RTCP SR report.
+  if (measurements_.size() == kNumRtcpReportsToUse)
+    measurements_.pop_back();
+
+  measurements_.push_front(measurement);
+  *new_rtcp_sr = true;
+
+  // List updated, calculate new parameters.
+  UpdateParameters();
+  return true;
+}
+
+bool RtpToNtpEstimator::Estimate(int64_t rtp_timestamp,
+                                 int64_t* rtp_timestamp_ms) const {
+  if (!params_.calculated || measurements_.empty())
+    return false;
+
+  uint32_t rtp_timestamp_old = measurements_.back().rtp_timestamp;
+  int64_t rtp_timestamp_unwrapped;
+  if (!CompensateForWrapAround(rtp_timestamp, rtp_timestamp_old,
+                               &rtp_timestamp_unwrapped)) {
+    return false;
+  }
+
+  double rtp_ms =
+      (static_cast<double>(rtp_timestamp_unwrapped) - params_.offset_ms) /
+          params_.frequency_khz +
+      0.5f;
+
+  if (rtp_ms < 0)
+    return false;
+
+  *rtp_timestamp_ms = rtp_ms;
+  return true;
+}
+
+int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
+  if (new_timestamp < old_timestamp) {
+    // This difference should be less than -2^31 if we have had a wrap around
+    // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
+    // cast to a int32_t, it should be positive.
+    if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
+      // Forward wrap around.
+      return 1;
+    }
+  } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
+    // This difference should be less than -2^31 if we have had a backward wrap
+    // around. Since it is cast to a int32_t, it should be positive.
+    return -1;
+  }
+  return 0;
+}
+
+}  // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc b/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
new file mode 100644
index 0000000..09b47b4
--- /dev/null
+++ b/webrtc/system_wrappers/source/rtp_to_ntp_estimator_unittest.cc
@@ -0,0 +1,252 @@
+/*
+ *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+namespace {
+const uint32_t kOneMsInNtpFrac = 4294967;
+const uint32_t kTimestampTicksPerMs = 90;
+}  // namespace
+
+TEST(WrapAroundTests, NoWrap) {
+  EXPECT_EQ(0, CheckForWrapArounds(0xFFFFFFFF, 0xFFFFFFFE));
+  EXPECT_EQ(0, CheckForWrapArounds(1, 0));
+  EXPECT_EQ(0, CheckForWrapArounds(0x00010000, 0x0000FFFF));
+}
+
+TEST(WrapAroundTests, ForwardWrap) {
+  EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFFFFFF));
+  EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFF0000));
+  EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFFFFFF));
+  EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFF0000));
+}
+
+TEST(WrapAroundTests, BackwardWrap) {
+  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0));
+  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0));
+  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0x0000FFFF));
+  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0x0000FFFF));
+}
+
+TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
+  RtpToNtpEstimator estimator;
+  bool new_sr;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 1;
+  uint32_t timestamp = 0;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp -= kTimestampTicksPerMs;
+  // Expected to fail since the older RTCP has a smaller RTP timestamp than the
+  // newer (old:0, new:4294967206).
+  EXPECT_FALSE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+}
+
+TEST(WrapAroundTests, NewRtcpWrapped) {
+  RtpToNtpEstimator estimator;
+  bool new_sr;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 1;
+  uint32_t timestamp = 0xFFFFFFFF;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  int64_t timestamp_ms = -1;
+  EXPECT_TRUE(estimator.Estimate(0xFFFFFFFF, &timestamp_ms));
+  // Since this RTP packet has the same timestamp as the RTCP packet constructed
+  // at time 0 it should be mapped to 0 as well.
+  EXPECT_EQ(0, timestamp_ms);
+}
+
+TEST(WrapAroundTests, RtpWrapped) {
+  RtpToNtpEstimator estimator;
+  bool new_sr;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 1;
+  uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+
+  int64_t timestamp_ms = -1;
+  EXPECT_TRUE(estimator.Estimate(0xFFFFFFFF - 2 * kTimestampTicksPerMs,
+                                 &timestamp_ms));
+  // Since this RTP packet has the same timestamp as the RTCP packet constructed
+  // at time 0 it should be mapped to 0 as well.
+  EXPECT_EQ(0, timestamp_ms);
+  // Two kTimestampTicksPerMs advanced.
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+  EXPECT_EQ(2, timestamp_ms);
+  // Wrapped rtp.
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+  EXPECT_EQ(3, timestamp_ms);
+}
+
+TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
+  RtpToNtpEstimator estimator;
+  bool new_sr;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 1;
+  uint32_t timestamp = 0;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  timestamp -= 2 * kTimestampTicksPerMs;
+  int64_t timestamp_ms = -1;
+  EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
+}
+
+TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
+  RtpToNtpEstimator estimator;
+  bool new_sr;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 1;
+  uint32_t timestamp = 0xFFFFFFFF;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  timestamp -= kTimestampTicksPerMs;
+  int64_t timestamp_ms = -1;
+  EXPECT_TRUE(estimator.Estimate(timestamp, &timestamp_ms));
+  // Constructed at the same time as the first RTCP and should therefore be
+  // mapped to zero.
+  EXPECT_EQ(0, timestamp_ms);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForZeroNtp) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 0;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_FALSE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualNtp) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 699925050;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  // Ntp time already added, list not updated.
+  ++timestamp;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldNtp) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 1;
+  uint32_t ntp_frac = 699925050;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  // Old ntp time, list not updated.
+  ntp_frac -= kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_FALSE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForEqualTimestamp) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 2;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  // Timestamp already added, list not updated.
+  ++ntp_frac;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, FailsForOldRtpTimestamp) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 2;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  // Old timestamp, list not updated.
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp -= kTimestampTicksPerMs;
+  EXPECT_FALSE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_FALSE(new_sr);
+}
+
+TEST(UpdateRtcpMeasurementTests, VerifyParameters) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 1;
+  uint32_t ntp_frac = 2;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  EXPECT_FALSE(estimator.params().calculated);
+  // Add second report, parameters should be calculated.
+  ntp_frac += kOneMsInNtpFrac;
+  timestamp += kTimestampTicksPerMs;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(estimator.params().calculated);
+  EXPECT_DOUBLE_EQ(90.0, estimator.params().frequency_khz);
+  EXPECT_NE(0.0, estimator.params().offset_ms);
+}
+
+TEST(RtpToNtpTests, FailsForNoParameters) {
+  RtpToNtpEstimator estimator;
+  uint32_t ntp_sec = 1;
+  uint32_t ntp_frac = 2;
+  uint32_t timestamp = 0x12345678;
+  bool new_sr;
+  EXPECT_TRUE(
+      estimator.UpdateMeasurements(ntp_sec, ntp_frac, timestamp, &new_sr));
+  EXPECT_TRUE(new_sr);
+  // Parameters are not calculated, conversion of RTP to NTP time should fail.
+  EXPECT_FALSE(estimator.params().calculated);
+  int64_t timestamp_ms = -1;
+  EXPECT_FALSE(estimator.Estimate(timestamp, &timestamp_ms));
+}
+
+};  // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc b/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc
deleted file mode 100644
index bdaaa7d..0000000
--- a/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
-#include "webrtc/test/gtest.h"
-
-namespace webrtc {
-namespace {
-const uint32_t kOneMsInNtpFrac = 4294967;
-const uint32_t kTimestampTicksPerMs = 90;
-}  // namespace
-
-TEST(WrapAroundTests, NoWrap) {
-  EXPECT_EQ(0, CheckForWrapArounds(0xFFFFFFFF, 0xFFFFFFFE));
-  EXPECT_EQ(0, CheckForWrapArounds(1, 0));
-  EXPECT_EQ(0, CheckForWrapArounds(0x00010000, 0x0000FFFF));
-}
-
-TEST(WrapAroundTests, ForwardWrap) {
-  EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFFFFFF));
-  EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFF0000));
-  EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFFFFFF));
-  EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFF0000));
-}
-
-TEST(WrapAroundTests, BackwardWrap) {
-  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0));
-  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0));
-  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0x0000FFFF));
-  EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0x0000FFFF));
-}
-
-TEST(WrapAroundTests, OldRtcpWrapped_OldRtpTimestamp) {
-  RtcpMeasurements rtcp;
-  bool new_sr;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 1;
-  uint32_t timestamp = 0;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp -= kTimestampTicksPerMs;
-  // Expected to fail since the older RTCP has a smaller RTP timestamp than the
-  // newer (old:0, new:4294967206).
-  EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-}
-
-TEST(WrapAroundTests, NewRtcpWrapped) {
-  RtcpMeasurements rtcp;
-  bool new_sr;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 1;
-  uint32_t timestamp = 0xFFFFFFFF;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  int64_t timestamp_ms = -1;
-  EXPECT_TRUE(RtpToNtpMs(rtcp.list.back().rtp_timestamp, rtcp, &timestamp_ms));
-  // Since this RTP packet has the same timestamp as the RTCP packet constructed
-  // at time 0 it should be mapped to 0 as well.
-  EXPECT_EQ(0, timestamp_ms);
-}
-
-TEST(WrapAroundTests, RtpWrapped) {
-  RtcpMeasurements rtcp;
-  bool new_sr;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 1;
-  uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-
-  int64_t timestamp_ms = -1;
-  EXPECT_TRUE(RtpToNtpMs(rtcp.list.back().rtp_timestamp, rtcp, &timestamp_ms));
-  // Since this RTP packet has the same timestamp as the RTCP packet constructed
-  // at time 0 it should be mapped to 0 as well.
-  EXPECT_EQ(0, timestamp_ms);
-  // Two kTimestampTicksPerMs advanced.
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
-  EXPECT_EQ(2, timestamp_ms);
-  // Wrapped rtp.
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
-  EXPECT_EQ(3, timestamp_ms);
-}
-
-TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
-  RtcpMeasurements rtcp;
-  bool new_sr;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 1;
-  uint32_t timestamp = 0;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  timestamp -= 2*kTimestampTicksPerMs;
-  int64_t timestamp_ms = -1;
-  EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
-}
-
-TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
-  RtcpMeasurements rtcp;
-  bool new_sr;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 1;
-  uint32_t timestamp = 0xFFFFFFFF;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  timestamp -= kTimestampTicksPerMs;
-  int64_t timestamp_ms = -1;
-  EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
-  // Constructed at the same time as the first RTCP and should therefore be
-  // mapped to zero.
-  EXPECT_EQ(0, timestamp_ms);
-}
-
-TEST(UpdateRtcpListTests, InjectRtcpSr) {
-  const uint32_t kNtpSec = 10;
-  const uint32_t kNtpFrac = 12345;
-  const uint32_t kTs = 0x12345678;
-  bool new_sr;
-  RtcpMeasurements rtcp;
-  EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac, kTs, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-  EXPECT_EQ(kNtpSec, rtcp.list.front().ntp_time.seconds());
-  EXPECT_EQ(kNtpFrac, rtcp.list.front().ntp_time.fractions());
-  EXPECT_EQ(kTs, rtcp.list.front().rtp_timestamp);
-  // Add second report.
-  EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac + kOneMsInNtpFrac, kTs + 1,
-                             &rtcp, &new_sr));
-  EXPECT_EQ(2u, rtcp.list.size());
-  EXPECT_EQ(kTs + 1, rtcp.list.front().rtp_timestamp);
-  EXPECT_EQ(kTs + 0, rtcp.list.back().rtp_timestamp);
-  // List should contain last two reports.
-  EXPECT_TRUE(UpdateRtcpList(kNtpSec, kNtpFrac + 2 * kOneMsInNtpFrac, kTs + 2,
-                             &rtcp, &new_sr));
-  EXPECT_EQ(2u, rtcp.list.size());
-  EXPECT_EQ(kTs + 2, rtcp.list.front().rtp_timestamp);
-  EXPECT_EQ(kTs + 1, rtcp.list.back().rtp_timestamp);
-}
-
-TEST(UpdateRtcpListTests, FailsForZeroNtp) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 0;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_FALSE(new_sr);
-  EXPECT_EQ(0u, rtcp.list.size());
-}
-
-TEST(UpdateRtcpListTests, FailsForEqualNtp) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 699925050;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-  // Ntp time already added, list not updated.
-  ++timestamp;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_FALSE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-}
-
-TEST(UpdateRtcpListTests, FailsForOldNtp) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 1;
-  uint32_t ntp_frac = 699925050;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-  // Old ntp time, list not updated.
-  ntp_frac -= kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_EQ(1u, rtcp.list.size());
-}
-
-TEST(UpdateRtcpListTests, FailsForEqualTimestamp) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 2;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-  // Timestamp already added, list not updated.
-  ++ntp_frac;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_FALSE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-}
-
-TEST(UpdateRtcpListTests, FailsForOldRtpTimestamp) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 0;
-  uint32_t ntp_frac = 2;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-  // Old timestamp, list not updated.
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp -= kTimestampTicksPerMs;
-  EXPECT_FALSE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_FALSE(new_sr);
-  EXPECT_EQ(1u, rtcp.list.size());
-}
-
-TEST(UpdateRtcpListTests, VerifyParameters) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 1;
-  uint32_t ntp_frac = 2;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(new_sr);
-  EXPECT_FALSE(rtcp.params.calculated);
-  // Add second report, parameters should be calculated.
-  ntp_frac += kOneMsInNtpFrac;
-  timestamp += kTimestampTicksPerMs;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_TRUE(rtcp.params.calculated);
-  EXPECT_DOUBLE_EQ(90.0, rtcp.params.frequency_khz);
-  EXPECT_NE(0.0, rtcp.params.offset_ms);
-}
-
-TEST(RtpToNtpTests, FailsForEmptyList) {
-  RtcpMeasurements rtcp;
-  rtcp.params.calculated = true;
-  // List is empty, conversion of RTP to NTP time should fail.
-  EXPECT_EQ(0u, rtcp.list.size());
-  int64_t timestamp_ms = -1;
-  EXPECT_FALSE(RtpToNtpMs(0, rtcp, &timestamp_ms));
-}
-
-TEST(RtpToNtpTests, FailsForNoParameters) {
-  RtcpMeasurements rtcp;
-  uint32_t ntp_sec = 1;
-  uint32_t ntp_frac = 2;
-  uint32_t timestamp = 0x12345678;
-  bool new_sr;
-  EXPECT_TRUE(UpdateRtcpList(ntp_sec, ntp_frac, timestamp, &rtcp, &new_sr));
-  EXPECT_EQ(1u, rtcp.list.size());
-  // Parameters are not calculated, conversion of RTP to NTP time should fail.
-  EXPECT_FALSE(rtcp.params.calculated);
-  int64_t timestamp_ms = -1;
-  EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_ms));
-}
-
-};  // namespace webrtc
diff --git a/webrtc/video/rtp_streams_synchronizer.cc b/webrtc/video/rtp_streams_synchronizer.cc
index d7fd949..0d026b3 100644
--- a/webrtc/video/rtp_streams_synchronizer.cc
+++ b/webrtc/video/rtp_streams_synchronizer.cc
@@ -41,8 +41,8 @@
   }
 
   bool new_rtcp_sr = false;
-  if (!UpdateRtcpList(ntp_secs, ntp_frac, rtp_timestamp, &stream->rtcp,
-                      &new_rtcp_sr)) {
+  if (!stream->rtp_to_ntp.UpdateMeasurements(ntp_secs, ntp_frac, rtp_timestamp,
+                                             &new_rtcp_sr)) {
     return false;
   }
 
@@ -183,14 +183,14 @@
   }
 
   int64_t latest_audio_ntp;
-  if (!RtpToNtpMs(playout_timestamp, audio_measurement_.rtcp,
-                  &latest_audio_ntp)) {
+  if (!audio_measurement_.rtp_to_ntp.Estimate(playout_timestamp,
+                                              &latest_audio_ntp)) {
     return false;
   }
 
   int64_t latest_video_ntp;
-  if (!RtpToNtpMs(frame.timestamp(), video_measurement_.rtcp,
-                  &latest_video_ntp)) {
+  if (!video_measurement_.rtp_to_ntp.Estimate(frame.timestamp(),
+                                              &latest_video_ntp)) {
     return false;
   }
 
@@ -200,7 +200,7 @@
     latest_video_ntp += time_to_render_ms;
 
   *stream_offset_ms = latest_audio_ntp - latest_video_ntp;
-  *estimated_freq_khz = video_measurement_.rtcp.params.frequency_khz;
+  *estimated_freq_khz = video_measurement_.rtp_to_ntp.params().frequency_khz;
   return true;
 }
 
diff --git a/webrtc/video/stream_synchronization.cc b/webrtc/video/stream_synchronization.cc
index ff38973..145922c 100644
--- a/webrtc/video/stream_synchronization.cc
+++ b/webrtc/video/stream_synchronization.cc
@@ -40,15 +40,13 @@
     int* relative_delay_ms) {
   assert(relative_delay_ms);
   int64_t audio_last_capture_time_ms;
-  if (!RtpToNtpMs(audio_measurement.latest_timestamp,
-                  audio_measurement.rtcp,
-                  &audio_last_capture_time_ms)) {
+  if (!audio_measurement.rtp_to_ntp.Estimate(audio_measurement.latest_timestamp,
+                                             &audio_last_capture_time_ms)) {
     return false;
   }
   int64_t video_last_capture_time_ms;
-  if (!RtpToNtpMs(video_measurement.latest_timestamp,
-                  video_measurement.rtcp,
-                  &video_last_capture_time_ms)) {
+  if (!video_measurement.rtp_to_ntp.Estimate(video_measurement.latest_timestamp,
+                                             &video_last_capture_time_ms)) {
     return false;
   }
   if (video_last_capture_time_ms < 0) {
diff --git a/webrtc/video/stream_synchronization.h b/webrtc/video/stream_synchronization.h
index c700ee3..0b1ad4f 100644
--- a/webrtc/video/stream_synchronization.h
+++ b/webrtc/video/stream_synchronization.h
@@ -13,7 +13,7 @@
 
 #include <list>
 
-#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
+#include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
@@ -21,8 +21,8 @@
 class StreamSynchronization {
  public:
   struct Measurements {
-    Measurements() : rtcp(), latest_receive_time_ms(0), latest_timestamp(0) {}
-    RtcpMeasurements rtcp;
+    Measurements() : latest_receive_time_ms(0), latest_timestamp(0) {}
+    RtpToNtpEstimator rtp_to_ntp;
     int64_t latest_receive_time_ms;
     uint32_t latest_timestamp;
   };
diff --git a/webrtc/video/stream_synchronization_unittest.cc b/webrtc/video/stream_synchronization_unittest.cc
index 770bbf6..d5607a8 100644
--- a/webrtc/video/stream_synchronization_unittest.cc
+++ b/webrtc/video/stream_synchronization_unittest.cc
@@ -34,13 +34,6 @@
       : kNtpJan1970(2208988800UL),
         time_now_ms_(offset) {}
 
-  RtcpMeasurement GenerateRtcp(int frequency, uint32_t offset) const {
-    RtcpMeasurement rtcp;
-    rtcp.ntp_time = GetNowNtp();
-    rtcp.rtp_timestamp = GetNowRtp(frequency, offset);
-    return rtcp;
-  }
-
   NtpTime GetNowNtp() const {
     uint32_t ntp_secs = time_now_ms_ / 1000 + kNtpJan1970;
     int64_t remainder_ms = time_now_ms_ % 1000;
@@ -104,29 +97,29 @@
     StreamSynchronization::Measurements audio;
     StreamSynchronization::Measurements video;
     // Generate NTP/RTP timestamp pair for both streams corresponding to RTCP.
-    RtcpMeasurement rtcp =
-        send_time_->GenerateRtcp(audio_frequency, audio_offset);
-    EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
-                               rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
-                               &audio.rtcp, &new_sr));
+    NtpTime ntp_time = send_time_->GetNowNtp();
+    uint32_t rtp_timestamp =
+        send_time_->GetNowRtp(audio_frequency, audio_offset);
+    EXPECT_TRUE(audio.rtp_to_ntp.UpdateMeasurements(
+        ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
     send_time_->IncreaseTimeMs(100);
     receive_time_->IncreaseTimeMs(100);
-    rtcp = send_time_->GenerateRtcp(video_frequency, video_offset);
-    EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
-                               rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
-                               &video.rtcp, &new_sr));
+    ntp_time = send_time_->GetNowNtp();
+    rtp_timestamp = send_time_->GetNowRtp(video_frequency, video_offset);
+    EXPECT_TRUE(video.rtp_to_ntp.UpdateMeasurements(
+        ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
     send_time_->IncreaseTimeMs(900);
     receive_time_->IncreaseTimeMs(900);
-    rtcp = send_time_->GenerateRtcp(audio_frequency, audio_offset);
-    EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
-                               rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
-                               &audio.rtcp, &new_sr));
+    ntp_time = send_time_->GetNowNtp();
+    rtp_timestamp = send_time_->GetNowRtp(audio_frequency, audio_offset);
+    EXPECT_TRUE(audio.rtp_to_ntp.UpdateMeasurements(
+        ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
     send_time_->IncreaseTimeMs(100);
     receive_time_->IncreaseTimeMs(100);
-    rtcp = send_time_->GenerateRtcp(video_frequency, video_offset);
-    EXPECT_TRUE(UpdateRtcpList(rtcp.ntp_time.seconds(),
-                               rtcp.ntp_time.fractions(), rtcp.rtp_timestamp,
-                               &video.rtcp, &new_sr));
+    ntp_time = send_time_->GetNowNtp();
+    rtp_timestamp = send_time_->GetNowRtp(video_frequency, video_offset);
+    EXPECT_TRUE(video.rtp_to_ntp.UpdateMeasurements(
+        ntp_time.seconds(), ntp_time.fractions(), rtp_timestamp, &new_sr));
 
     send_time_->IncreaseTimeMs(900);
     receive_time_->IncreaseTimeMs(900);