blob: 8290749f132390e0de9ad409030daf79957b9c33 [file] [log] [blame]
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +00001/*
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
Henrik Kjellander98f53512015-10-28 18:17:40 +010011#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +000012
asaperssonde9e5ff2016-11-02 07:14:03 -070013#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010014#include "webrtc/system_wrappers/include/clock.h"
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +000015
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +000016namespace webrtc {
asaperssonde9e5ff2016-11-02 07:14:03 -070017namespace {
18// Calculates the RTP timestamp frequency from two pairs of NTP/RTP timestamps.
19bool CalculateFrequency(int64_t rtcp_ntp_ms1,
20 uint32_t rtp_timestamp1,
21 int64_t rtcp_ntp_ms2,
22 uint32_t rtp_timestamp2,
23 double* frequency_khz) {
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +000024 if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) {
25 return false;
26 }
27 *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
28 static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2);
29 return true;
30}
31
32// Detects if there has been a wraparound between |old_timestamp| and
33// |new_timestamp|, and compensates by adding 2^32 if that is the case.
34bool CompensateForWrapAround(uint32_t new_timestamp,
35 uint32_t old_timestamp,
36 int64_t* compensated_timestamp) {
wu@webrtc.org66773a02014-05-07 17:09:44 +000037 int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +000038 if (wraps < 0) {
39 // Reordering, don't use this packet.
40 return false;
41 }
42 *compensated_timestamp = new_timestamp + (wraps << 32);
43 return true;
44}
asaperssonde9e5ff2016-11-02 07:14:03 -070045} // namespace
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +000046
asaperssonde9e5ff2016-11-02 07:14:03 -070047// Class holding RTP and NTP timestamp from a RTCP SR report.
48RtcpMeasurement::RtcpMeasurement()
49 : ntp_secs(0), ntp_frac(0), rtp_timestamp(0) {}
50
51RtcpMeasurement::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
56bool 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.
64RtcpMeasurements::RtcpMeasurements() {}
65RtcpMeasurements::~RtcpMeasurements() {}
66
67bool 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
75bool 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 &timestamp_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
99void 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, &timestamp_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 &params.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.
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000122bool UpdateRtcpList(uint32_t ntp_secs,
123 uint32_t ntp_frac,
124 uint32_t rtp_timestamp,
asaperssonde9e5ff2016-11-02 07:14:03 -0700125 RtcpMeasurements* rtcp_measurements,
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000126 bool* new_rtcp_sr) {
127 *new_rtcp_sr = false;
asaperssonde9e5ff2016-11-02 07:14:03 -0700128
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.
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000137 return false;
138 }
139
asaperssonde9e5ff2016-11-02 07:14:03 -0700140 // Two RTCP SR reports are needed to map between RTP and NTP.
141 // More than two will not improve the mapping.
142 if (rtcp_measurements->list.size() == 2)
143 rtcp_measurements->list.pop_back();
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000144
asaperssonde9e5ff2016-11-02 07:14:03 -0700145 rtcp_measurements->list.push_front(measurement);
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000146 *new_rtcp_sr = true;
asaperssonde9e5ff2016-11-02 07:14:03 -0700147
148 // List updated, calculate new parameters.
149 rtcp_measurements->UpdateParameters();
wu@webrtc.orgcd701192014-04-24 22:10:24 +0000150 return true;
151}
152
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000153// Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp
154// pairs in |rtcp|. The converted timestamp is returned in
155// |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP
156// timestamps and returns false if it can't do the conversion due to reordering.
157bool RtpToNtpMs(int64_t rtp_timestamp,
asaperssonde9e5ff2016-11-02 07:14:03 -0700158 const RtcpMeasurements& rtcp,
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000159 int64_t* rtp_timestamp_in_ms) {
asaperssonde9e5ff2016-11-02 07:14:03 -0700160 if (!rtcp.params.calculated || rtcp.list.empty())
asaperssonf8cdd182016-03-15 01:00:47 -0700161 return false;
162
asaperssonde9e5ff2016-11-02 07:14:03 -0700163 uint32_t rtcp_timestamp_old = rtcp.list.back().rtp_timestamp;
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000164 int64_t rtp_timestamp_unwrapped;
165 if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old,
166 &rtp_timestamp_unwrapped)) {
167 return false;
168 }
asaperssonde9e5ff2016-11-02 07:14:03 -0700169
170 double rtp_timestamp_ms =
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) {
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000175 return false;
176 }
asaperssonde9e5ff2016-11-02 07:14:03 -0700177 *rtp_timestamp_in_ms = rtp_timestamp_ms;
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000178 return true;
179}
180
181int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
182 if (new_timestamp < old_timestamp) {
183 // This difference should be less than -2^31 if we have had a wrap around
184 // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
185 // cast to a int32_t, it should be positive.
186 if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
187 // Forward wrap around.
188 return 1;
189 }
190 } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
191 // This difference should be less than -2^31 if we have had a backward wrap
192 // around. Since it is cast to a int32_t, it should be positive.
193 return -1;
194 }
195 return 0;
196}
wu@webrtc.org66773a02014-05-07 17:09:44 +0000197
stefan@webrtc.org64d9dec2012-09-26 16:47:40 +0000198} // namespace webrtc