| Index: webrtc/system_wrappers/source/rtp_to_ntp.cc
 | 
| diff --git a/webrtc/system_wrappers/source/rtp_to_ntp.cc b/webrtc/system_wrappers/source/rtp_to_ntp.cc
 | 
| index 05091461d4123ff9bfbea041bd18187a0c411e02..8290749f132390e0de9ad409030daf79957b9c33 100644
 | 
| --- a/webrtc/system_wrappers/source/rtp_to_ntp.cc
 | 
| +++ b/webrtc/system_wrappers/source/rtp_to_ntp.cc
 | 
| @@ -10,27 +10,17 @@
 | 
|  
 | 
|  #include "webrtc/system_wrappers/include/rtp_to_ntp.h"
 | 
|  
 | 
| +#include "webrtc/base/logging.h"
 | 
|  #include "webrtc/system_wrappers/include/clock.h"
 | 
|  
 | 
| -#include <assert.h>
 | 
| -
 | 
|  namespace webrtc {
 | 
| -
 | 
| -RtcpMeasurement::RtcpMeasurement()
 | 
| -    : ntp_secs(0), ntp_frac(0), rtp_timestamp(0) {}
 | 
| -
 | 
| -RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac,
 | 
| -                                 uint32_t timestamp)
 | 
| -    : ntp_secs(ntp_secs), ntp_frac(ntp_frac), rtp_timestamp(timestamp) {}
 | 
| -
 | 
| -// Calculates the RTP timestamp frequency from two pairs of NTP and 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) {
 | 
| +namespace {
 | 
| +// 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;
 | 
|    }
 | 
| @@ -44,7 +34,6 @@ bool CalculateFrequency(
 | 
|  bool CompensateForWrapAround(uint32_t new_timestamp,
 | 
|                               uint32_t old_timestamp,
 | 
|                               int64_t* compensated_timestamp) {
 | 
| -  assert(compensated_timestamp);
 | 
|    int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
 | 
|    if (wraps < 0) {
 | 
|      // Reordering, don't use this packet.
 | 
| @@ -53,39 +42,111 @@ bool CompensateForWrapAround(uint32_t new_timestamp,
 | 
|    *compensated_timestamp = new_timestamp + (wraps << 32);
 | 
|    return true;
 | 
|  }
 | 
| +}  // namespace
 | 
| +
 | 
| +// Class holding RTP and NTP timestamp from a RTCP SR report.
 | 
| +RtcpMeasurement::RtcpMeasurement()
 | 
| +    : ntp_secs(0), ntp_frac(0), rtp_timestamp(0) {}
 | 
| +
 | 
| +RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs,
 | 
| +                                 uint32_t ntp_frac,
 | 
| +                                 uint32_t timestamp)
 | 
| +    : ntp_secs(ntp_secs), ntp_frac(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_secs == other.ntp_secs && ntp_frac == other.ntp_frac) ||
 | 
| +         (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_secs == 0 && other.ntp_frac == 0) {
 | 
| +    // Invalid or not defined.
 | 
| +    return false;
 | 
| +  }
 | 
| +  int64_t ntp_ms_new = Clock::NtpToMs(other.ntp_secs, other.ntp_frac);
 | 
| +  for (const auto& it : list) {
 | 
| +    if (ntp_ms_new <= Clock::NtpToMs(it.ntp_secs, it.ntp_frac)) {
 | 
| +      // Old report.
 | 
| +      return false;
 | 
| +    }
 | 
| +    int64_t timestamp_new = other.rtp_timestamp;
 | 
| +    if (!CompensateForWrapAround(timestamp_new, it.rtp_timestamp,
 | 
| +                                 ×tamp_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() != 2)
 | 
| +    return;
 | 
| +
 | 
| +  int64_t timestamp_new = list.front().rtp_timestamp;
 | 
| +  int64_t timestamp_old = list.back().rtp_timestamp;
 | 
| +  if (!CompensateForWrapAround(timestamp_new, timestamp_old, ×tamp_new))
 | 
| +    return;
 | 
| +
 | 
| +  int64_t ntp_ms_new =
 | 
| +      Clock::NtpToMs(list.front().ntp_secs, list.front().ntp_frac);
 | 
| +  int64_t ntp_ms_old =
 | 
| +      Clock::NtpToMs(list.back().ntp_secs, list.back().ntp_frac);
 | 
| +
 | 
| +  if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old,
 | 
| +                          ¶ms.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,
 | 
| -                    RtcpList* rtcp_list,
 | 
| +                    RtcpMeasurements* rtcp_measurements,
 | 
|                      bool* new_rtcp_sr) {
 | 
|    *new_rtcp_sr = false;
 | 
| -  if (ntp_secs == 0 && ntp_frac == 0) {
 | 
| -    return false;
 | 
| -  }
 | 
|  
 | 
| -  RtcpMeasurement measurement;
 | 
| -  measurement.ntp_secs = ntp_secs;
 | 
| -  measurement.ntp_frac = ntp_frac;
 | 
| -  measurement.rtp_timestamp = rtp_timestamp;
 | 
| -
 | 
| -  for (RtcpList::iterator it = rtcp_list->begin();
 | 
| -       it != rtcp_list->end(); ++it) {
 | 
| -    if ((measurement.ntp_secs == (*it).ntp_secs &&
 | 
| -         measurement.ntp_frac == (*it).ntp_frac) ||
 | 
| -        (measurement.rtp_timestamp == (*it).rtp_timestamp)) {
 | 
| -      // This RTCP has already been added to the list.
 | 
| -      return true;
 | 
| -    }
 | 
| +  RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp);
 | 
| +  if (rtcp_measurements->Contains(measurement)) {
 | 
| +    // RTCP SR report already added.
 | 
| +    return true;
 | 
|    }
 | 
|  
 | 
| -  // We need two RTCP SR reports to map between RTP and NTP. More than two will
 | 
| -  // not improve the mapping.
 | 
| -  if (rtcp_list->size() == 2) {
 | 
| -    rtcp_list->pop_back();
 | 
| +  if (!rtcp_measurements->IsValid(measurement)) {
 | 
| +    // Old report or invalid parameters.
 | 
| +    return false;
 | 
|    }
 | 
| -  rtcp_list->push_front(measurement);
 | 
| +
 | 
| +  // Two RTCP SR reports are needed to map between RTP and NTP.
 | 
| +  // More than two will not improve the mapping.
 | 
| +  if (rtcp_measurements->list.size() == 2)
 | 
| +    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;
 | 
|  }
 | 
|  
 | 
| @@ -94,45 +155,26 @@ bool UpdateRtcpList(uint32_t ntp_secs,
 | 
|  // |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 RtcpList& rtcp,
 | 
| +                const RtcpMeasurements& rtcp,
 | 
|                  int64_t* rtp_timestamp_in_ms) {
 | 
| -  if (rtcp.size() != 2)
 | 
| -    return false;
 | 
| -
 | 
| -  int64_t rtcp_ntp_ms_new = Clock::NtpToMs(rtcp.front().ntp_secs,
 | 
| -                                           rtcp.front().ntp_frac);
 | 
| -  int64_t rtcp_ntp_ms_old = Clock::NtpToMs(rtcp.back().ntp_secs,
 | 
| -                                           rtcp.back().ntp_frac);
 | 
| -  int64_t rtcp_timestamp_new = rtcp.front().rtp_timestamp;
 | 
| -  int64_t rtcp_timestamp_old = rtcp.back().rtp_timestamp;
 | 
| -  if (!CompensateForWrapAround(rtcp_timestamp_new,
 | 
| -                               rtcp_timestamp_old,
 | 
| -                               &rtcp_timestamp_new)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -  if (rtcp_timestamp_new < rtcp_timestamp_old)
 | 
| +  if (!rtcp.params.calculated || rtcp.list.empty())
 | 
|      return false;
 | 
|  
 | 
| -  double freq_khz;
 | 
| -  if (!CalculateFrequency(rtcp_ntp_ms_new,
 | 
| -                          rtcp_timestamp_new,
 | 
| -                          rtcp_ntp_ms_old,
 | 
| -                          rtcp_timestamp_old,
 | 
| -                          &freq_khz)) {
 | 
| -    return false;
 | 
| -  }
 | 
| -  double offset = rtcp_timestamp_new - freq_khz * rtcp_ntp_ms_new;
 | 
| +  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_ntp_ms = (static_cast<double>(rtp_timestamp_unwrapped) -
 | 
| -      offset) / freq_khz + 0.5f;
 | 
| -  if (rtp_timestamp_ntp_ms < 0) {
 | 
| +
 | 
| +  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_ntp_ms;
 | 
| +  *rtp_timestamp_in_ms = rtp_timestamp_ms;
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| 
 |