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