| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/system_wrappers/include/rtp_to_ntp.h" | 11 #include "webrtc/system_wrappers/include/rtp_to_ntp_estimator.h" |
| 12 | 12 |
| 13 #include "webrtc/base/logging.h" | 13 #include "webrtc/base/logging.h" |
| 14 #include "webrtc/system_wrappers/include/clock.h" | 14 #include "webrtc/system_wrappers/include/clock.h" |
| 15 | 15 |
| 16 namespace webrtc { | 16 namespace webrtc { |
| 17 namespace { | 17 namespace { |
| 18 // Number of RTCP SR reports to use to map between RTP and NTP. | 18 // Number of RTCP SR reports to use to map between RTP and NTP. |
| 19 const size_t kNumRtcpReportsToUse = 2; | 19 const size_t kNumRtcpReportsToUse = 2; |
| 20 | 20 |
| 21 // Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps. | 21 // Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps. |
| 22 bool CalculateFrequency(int64_t rtcp_ntp_ms1, | 22 bool CalculateFrequency(int64_t ntp_ms1, |
| 23 uint32_t rtp_timestamp1, | 23 uint32_t rtp_timestamp1, |
| 24 int64_t rtcp_ntp_ms2, | 24 int64_t ntp_ms2, |
| 25 uint32_t rtp_timestamp2, | 25 uint32_t rtp_timestamp2, |
| 26 double* frequency_khz) { | 26 double* frequency_khz) { |
| 27 if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) { | 27 if (ntp_ms1 <= ntp_ms2) |
| 28 return false; | 28 return false; |
| 29 } | 29 |
| 30 *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) / | 30 *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) / |
| 31 static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2); | 31 static_cast<double>(ntp_ms1 - ntp_ms2); |
| 32 return true; | 32 return true; |
| 33 } | 33 } |
| 34 | 34 |
| 35 // Detects if there has been a wraparound between |old_timestamp| and | 35 // Detects if there has been a wraparound between |old_timestamp| and |
| 36 // |new_timestamp|, and compensates by adding 2^32 if that is the case. | 36 // |new_timestamp|, and compensates by adding 2^32 if that is the case. |
| 37 bool CompensateForWrapAround(uint32_t new_timestamp, | 37 bool CompensateForWrapAround(uint32_t new_timestamp, |
| 38 uint32_t old_timestamp, | 38 uint32_t old_timestamp, |
| 39 int64_t* compensated_timestamp) { | 39 int64_t* compensated_timestamp) { |
| 40 int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp); | 40 int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp); |
| 41 if (wraps < 0) { | 41 if (wraps < 0) { |
| 42 // Reordering, don't use this packet. | 42 // Reordering, don't use this packet. |
| 43 return false; | 43 return false; |
| 44 } | 44 } |
| 45 *compensated_timestamp = new_timestamp + (wraps << 32); | 45 *compensated_timestamp = new_timestamp + (wraps << 32); |
| 46 return true; | 46 return true; |
| 47 } | 47 } |
| 48 } // namespace | |
| 49 | 48 |
| 50 // Class holding RTP and NTP timestamp from a RTCP SR report. | 49 bool Contains(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements, |
| 51 RtcpMeasurement::RtcpMeasurement() : ntp_time(0, 0), rtp_timestamp(0) {} | 50 const RtpToNtpEstimator::RtcpMeasurement& other) { |
| 52 | 51 for (const auto& measurement : measurements) { |
| 53 RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, | 52 if (measurement.IsEqual(other)) |
| 54 uint32_t ntp_frac, | |
| 55 uint32_t timestamp) | |
| 56 : ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {} | |
| 57 | |
| 58 bool RtcpMeasurement::IsEqual(const RtcpMeasurement& other) const { | |
| 59 // Use || since two equal timestamps will result in zero frequency and in | |
| 60 // RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency. | |
| 61 return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp); | |
| 62 } | |
| 63 | |
| 64 // Class holding list of RTP and NTP timestamp pairs. | |
| 65 RtcpMeasurements::RtcpMeasurements() {} | |
| 66 RtcpMeasurements::~RtcpMeasurements() {} | |
| 67 | |
| 68 bool RtcpMeasurements::Contains(const RtcpMeasurement& other) const { | |
| 69 for (const auto& it : list) { | |
| 70 if (it.IsEqual(other)) | |
| 71 return true; | 53 return true; |
| 72 } | 54 } |
| 73 return false; | 55 return false; |
| 74 } | 56 } |
| 75 | 57 |
| 76 bool RtcpMeasurements::IsValid(const RtcpMeasurement& other) const { | 58 bool IsValid(const std::list<RtpToNtpEstimator::RtcpMeasurement>& measurements, |
| 59 const RtpToNtpEstimator::RtcpMeasurement& other) { |
| 77 if (!other.ntp_time.Valid()) | 60 if (!other.ntp_time.Valid()) |
| 78 return false; | 61 return false; |
| 79 | 62 |
| 80 int64_t ntp_ms_new = other.ntp_time.ToMs(); | 63 int64_t ntp_ms_new = other.ntp_time.ToMs(); |
| 81 for (const auto& it : list) { | 64 for (const auto& measurement : measurements) { |
| 82 if (ntp_ms_new <= it.ntp_time.ToMs()) { | 65 if (ntp_ms_new <= measurement.ntp_time.ToMs()) { |
| 83 // Old report. | 66 // Old report. |
| 84 return false; | 67 return false; |
| 85 } | 68 } |
| 86 int64_t timestamp_new = other.rtp_timestamp; | 69 int64_t timestamp_new = other.rtp_timestamp; |
| 87 if (!CompensateForWrapAround(timestamp_new, it.rtp_timestamp, | 70 if (!CompensateForWrapAround(timestamp_new, measurement.rtp_timestamp, |
| 88 ×tamp_new)) { | 71 ×tamp_new)) { |
| 89 return false; | 72 return false; |
| 90 } | 73 } |
| 91 if (timestamp_new <= it.rtp_timestamp) { | 74 if (timestamp_new <= measurement.rtp_timestamp) { |
| 92 LOG(LS_WARNING) << "Newer RTCP SR report with older RTP timestamp."; | 75 LOG(LS_WARNING) << "Newer RTCP SR report with older RTP timestamp."; |
| 93 return false; | 76 return false; |
| 94 } | 77 } |
| 95 } | 78 } |
| 96 return true; | 79 return true; |
| 97 } | 80 } |
| 81 } // namespace |
| 98 | 82 |
| 99 void RtcpMeasurements::UpdateParameters() { | 83 RtpToNtpEstimator::RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, |
| 100 if (list.size() != kNumRtcpReportsToUse) | 84 uint32_t ntp_frac, |
| 85 uint32_t timestamp) |
| 86 : ntp_time(ntp_secs, ntp_frac), rtp_timestamp(timestamp) {} |
| 87 |
| 88 bool RtpToNtpEstimator::RtcpMeasurement::IsEqual( |
| 89 const RtcpMeasurement& other) const { |
| 90 // Use || since two equal timestamps will result in zero frequency and in |
| 91 // RtpToNtpMs, |rtp_timestamp_ms| is estimated by dividing by the frequency. |
| 92 return (ntp_time == other.ntp_time) || (rtp_timestamp == other.rtp_timestamp); |
| 93 } |
| 94 |
| 95 // Class for converting an RTP timestamp to the NTP domain. |
| 96 RtpToNtpEstimator::RtpToNtpEstimator() {} |
| 97 RtpToNtpEstimator::~RtpToNtpEstimator() {} |
| 98 |
| 99 void RtpToNtpEstimator::UpdateParameters() { |
| 100 if (measurements_.size() != kNumRtcpReportsToUse) |
| 101 return; | 101 return; |
| 102 | 102 |
| 103 int64_t timestamp_new = list.front().rtp_timestamp; | 103 int64_t timestamp_new = measurements_.front().rtp_timestamp; |
| 104 int64_t timestamp_old = list.back().rtp_timestamp; | 104 int64_t timestamp_old = measurements_.back().rtp_timestamp; |
| 105 if (!CompensateForWrapAround(timestamp_new, timestamp_old, ×tamp_new)) | 105 if (!CompensateForWrapAround(timestamp_new, timestamp_old, ×tamp_new)) |
| 106 return; | 106 return; |
| 107 | 107 |
| 108 int64_t ntp_ms_new = list.front().ntp_time.ToMs(); | 108 int64_t ntp_ms_new = measurements_.front().ntp_time.ToMs(); |
| 109 int64_t ntp_ms_old = list.back().ntp_time.ToMs(); | 109 int64_t ntp_ms_old = measurements_.back().ntp_time.ToMs(); |
| 110 | 110 |
| 111 if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old, | 111 if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old, |
| 112 ¶ms.frequency_khz)) { | 112 ¶ms_.frequency_khz)) { |
| 113 return; | 113 return; |
| 114 } | 114 } |
| 115 params.offset_ms = timestamp_new - params.frequency_khz * ntp_ms_new; | 115 params_.offset_ms = timestamp_new - params_.frequency_khz * ntp_ms_new; |
| 116 params.calculated = true; | 116 params_.calculated = true; |
| 117 } | 117 } |
| 118 | 118 |
| 119 // Updates list holding NTP and RTP timestamp pairs. | 119 bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs, |
| 120 bool UpdateRtcpList(uint32_t ntp_secs, | 120 uint32_t ntp_frac, |
| 121 uint32_t ntp_frac, | 121 uint32_t rtp_timestamp, |
| 122 uint32_t rtp_timestamp, | 122 bool* new_rtcp_sr) { |
| 123 RtcpMeasurements* rtcp_measurements, | |
| 124 bool* new_rtcp_sr) { | |
| 125 *new_rtcp_sr = false; | 123 *new_rtcp_sr = false; |
| 126 | 124 |
| 127 RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp); | 125 RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp); |
| 128 if (rtcp_measurements->Contains(measurement)) { | 126 if (Contains(measurements_, measurement)) { |
| 129 // RTCP SR report already added. | 127 // RTCP SR report already added. |
| 130 return true; | 128 return true; |
| 131 } | 129 } |
| 132 | 130 if (!IsValid(measurements_, measurement)) { |
| 133 if (!rtcp_measurements->IsValid(measurement)) { | |
| 134 // Old report or invalid parameters. | 131 // Old report or invalid parameters. |
| 135 return false; | 132 return false; |
| 136 } | 133 } |
| 137 | 134 |
| 138 // Insert new RTCP SR report. | 135 // Insert new RTCP SR report. |
| 139 if (rtcp_measurements->list.size() == kNumRtcpReportsToUse) | 136 if (measurements_.size() == kNumRtcpReportsToUse) |
| 140 rtcp_measurements->list.pop_back(); | 137 measurements_.pop_back(); |
| 141 | 138 |
| 142 rtcp_measurements->list.push_front(measurement); | 139 measurements_.push_front(measurement); |
| 143 *new_rtcp_sr = true; | 140 *new_rtcp_sr = true; |
| 144 | 141 |
| 145 // List updated, calculate new parameters. | 142 // List updated, calculate new parameters. |
| 146 rtcp_measurements->UpdateParameters(); | 143 UpdateParameters(); |
| 147 return true; | 144 return true; |
| 148 } | 145 } |
| 149 | 146 |
| 150 // Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp | 147 bool RtpToNtpEstimator::Estimate(int64_t rtp_timestamp, |
| 151 // pairs in |rtcp|. The converted timestamp is returned in | 148 int64_t* rtp_timestamp_ms) const { |
| 152 // |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP | 149 if (!params_.calculated || measurements_.empty()) |
| 153 // timestamps and returns false if it can't do the conversion due to reordering. | |
| 154 bool RtpToNtpMs(int64_t rtp_timestamp, | |
| 155 const RtcpMeasurements& rtcp, | |
| 156 int64_t* rtp_timestamp_in_ms) { | |
| 157 if (!rtcp.params.calculated || rtcp.list.empty()) | |
| 158 return false; | 150 return false; |
| 159 | 151 |
| 160 uint32_t rtcp_timestamp_old = rtcp.list.back().rtp_timestamp; | 152 uint32_t rtp_timestamp_old = measurements_.back().rtp_timestamp; |
| 161 int64_t rtp_timestamp_unwrapped; | 153 int64_t rtp_timestamp_unwrapped; |
| 162 if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old, | 154 if (!CompensateForWrapAround(rtp_timestamp, rtp_timestamp_old, |
| 163 &rtp_timestamp_unwrapped)) { | 155 &rtp_timestamp_unwrapped)) { |
| 164 return false; | 156 return false; |
| 165 } | 157 } |
| 166 | 158 |
| 167 double rtp_timestamp_ms = | 159 double rtp_ms = |
| 168 (static_cast<double>(rtp_timestamp_unwrapped) - rtcp.params.offset_ms) / | 160 (static_cast<double>(rtp_timestamp_unwrapped) - params_.offset_ms) / |
| 169 rtcp.params.frequency_khz + | 161 params_.frequency_khz + |
| 170 0.5f; | 162 0.5f; |
| 171 if (rtp_timestamp_ms < 0) { | 163 |
| 164 if (rtp_ms < 0) |
| 172 return false; | 165 return false; |
| 173 } | 166 |
| 174 *rtp_timestamp_in_ms = rtp_timestamp_ms; | 167 *rtp_timestamp_ms = rtp_ms; |
| 175 return true; | 168 return true; |
| 176 } | 169 } |
| 177 | 170 |
| 178 int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) { | 171 int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) { |
| 179 if (new_timestamp < old_timestamp) { | 172 if (new_timestamp < old_timestamp) { |
| 180 // This difference should be less than -2^31 if we have had a wrap around | 173 // This difference should be less than -2^31 if we have had a wrap around |
| 181 // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is | 174 // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is |
| 182 // cast to a int32_t, it should be positive. | 175 // cast to a int32_t, it should be positive. |
| 183 if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) { | 176 if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) { |
| 184 // Forward wrap around. | 177 // Forward wrap around. |
| 185 return 1; | 178 return 1; |
| 186 } | 179 } |
| 187 } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) { | 180 } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) { |
| 188 // This difference should be less than -2^31 if we have had a backward wrap | 181 // This difference should be less than -2^31 if we have had a backward wrap |
| 189 // around. Since it is cast to a int32_t, it should be positive. | 182 // around. Since it is cast to a int32_t, it should be positive. |
| 190 return -1; | 183 return -1; |
| 191 } | 184 } |
| 192 return 0; | 185 return 0; |
| 193 } | 186 } |
| 194 | 187 |
| 195 } // namespace webrtc | 188 } // namespace webrtc |
| OLD | NEW |