OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 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 "webrtc/system_wrappers/include/rtp_to_ntp.h" | |
12 | |
13 #include "webrtc/base/logging.h" | |
14 #include "webrtc/system_wrappers/include/clock.h" | |
15 | |
16 namespace webrtc { | |
17 namespace { | |
18 // Number of RTCP SR reports to use to map between RTP and NTP. | |
19 const size_t kNumRtcpReportsToUse = 2; | |
20 | |
21 // Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps. | |
22 bool CalculateFrequency(int64_t rtcp_ntp_ms1, | |
23 uint32_t rtp_timestamp1, | |
24 int64_t rtcp_ntp_ms2, | |
25 uint32_t rtp_timestamp2, | |
26 double* frequency_khz) { | |
27 if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) { | |
28 return false; | |
29 } | |
30 *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) / | |
31 static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2); | |
32 return true; | |
33 } | |
34 | |
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. | |
37 bool CompensateForWrapAround(uint32_t new_timestamp, | |
38 uint32_t old_timestamp, | |
39 int64_t* compensated_timestamp) { | |
40 int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp); | |
41 if (wraps < 0) { | |
42 // Reordering, don't use this packet. | |
43 return false; | |
44 } | |
45 *compensated_timestamp = new_timestamp + (wraps << 32); | |
46 return true; | |
47 } | |
48 } // namespace | |
49 | |
50 // Class holding RTP and NTP timestamp from a RTCP SR report. | |
51 RtcpMeasurement::RtcpMeasurement() : ntp_time(0, 0), rtp_timestamp(0) {} | |
52 | |
53 RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, | |
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; | |
72 } | |
73 return false; | |
74 } | |
75 | |
76 bool RtcpMeasurements::IsValid(const RtcpMeasurement& other) const { | |
77 if (!other.ntp_time.Valid()) | |
78 return false; | |
79 | |
80 int64_t ntp_ms_new = other.ntp_time.ToMs(); | |
81 for (const auto& it : list) { | |
82 if (ntp_ms_new <= it.ntp_time.ToMs()) { | |
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() != kNumRtcpReportsToUse) | |
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 = list.front().ntp_time.ToMs(); | |
109 int64_t ntp_ms_old = list.back().ntp_time.ToMs(); | |
110 | |
111 if (!CalculateFrequency(ntp_ms_new, timestamp_new, ntp_ms_old, timestamp_old, | |
112 ¶ms.frequency_khz)) { | |
113 return; | |
114 } | |
115 params.offset_ms = timestamp_new - params.frequency_khz * ntp_ms_new; | |
116 params.calculated = true; | |
117 } | |
118 | |
119 // Updates list holding NTP and RTP timestamp pairs. | |
120 bool UpdateRtcpList(uint32_t ntp_secs, | |
121 uint32_t ntp_frac, | |
122 uint32_t rtp_timestamp, | |
123 RtcpMeasurements* rtcp_measurements, | |
124 bool* new_rtcp_sr) { | |
125 *new_rtcp_sr = false; | |
126 | |
127 RtcpMeasurement measurement(ntp_secs, ntp_frac, rtp_timestamp); | |
128 if (rtcp_measurements->Contains(measurement)) { | |
129 // RTCP SR report already added. | |
130 return true; | |
131 } | |
132 | |
133 if (!rtcp_measurements->IsValid(measurement)) { | |
134 // Old report or invalid parameters. | |
135 return false; | |
136 } | |
137 | |
138 // Insert new RTCP SR report. | |
139 if (rtcp_measurements->list.size() == kNumRtcpReportsToUse) | |
140 rtcp_measurements->list.pop_back(); | |
141 | |
142 rtcp_measurements->list.push_front(measurement); | |
143 *new_rtcp_sr = true; | |
144 | |
145 // List updated, calculate new parameters. | |
146 rtcp_measurements->UpdateParameters(); | |
147 return true; | |
148 } | |
149 | |
150 // Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp | |
151 // pairs in |rtcp|. The converted timestamp is returned in | |
152 // |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP | |
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; | |
159 | |
160 uint32_t rtcp_timestamp_old = rtcp.list.back().rtp_timestamp; | |
161 int64_t rtp_timestamp_unwrapped; | |
162 if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old, | |
163 &rtp_timestamp_unwrapped)) { | |
164 return false; | |
165 } | |
166 | |
167 double rtp_timestamp_ms = | |
168 (static_cast<double>(rtp_timestamp_unwrapped) - rtcp.params.offset_ms) / | |
169 rtcp.params.frequency_khz + | |
170 0.5f; | |
171 if (rtp_timestamp_ms < 0) { | |
172 return false; | |
173 } | |
174 *rtp_timestamp_in_ms = rtp_timestamp_ms; | |
175 return true; | |
176 } | |
177 | |
178 int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) { | |
179 if (new_timestamp < old_timestamp) { | |
180 // 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 | |
182 // cast to a int32_t, it should be positive. | |
183 if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) { | |
184 // Forward wrap around. | |
185 return 1; | |
186 } | |
187 } 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 | |
189 // around. Since it is cast to a int32_t, it should be positive. | |
190 return -1; | |
191 } | |
192 return 0; | |
193 } | |
194 | |
195 } // namespace webrtc | |
OLD | NEW |