blob: bf9f726c4255e9efaf87c729a47034e62191ac62 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 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
Karl Wiberg76b7f512018-03-22 15:29:03 +010011#include "rtc_base/time/timestamp_extrapolator.h"
wu@webrtc.orged4cb562014-05-06 04:50:49 +000012
13#include <algorithm>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
15namespace webrtc {
16
wu@webrtc.org66773a02014-05-07 17:09:44 +000017TimestampExtrapolator::TimestampExtrapolator(int64_t start_ms)
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000018 : _rwLock(RWLockWrapper::CreateRWLock()),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000019 _startMs(0),
20 _firstTimestamp(0),
21 _wrapArounds(0),
22 _prevUnwrappedTimestamp(-1),
23 _prevWrapTimestamp(-1),
24 _lambda(1),
25 _firstAfterReset(true),
26 _packetCount(0),
27 _startUpFilterDelayInPackets(2),
28 _detectorAccumulatorPos(0),
29 _detectorAccumulatorNeg(0),
30 _alarmThreshold(60e3),
31 _accDrift(6600), // in timestamp ticks, i.e. 15 ms
32 _accMaxError(7000),
andrew@webrtc.orgcc476aa2014-10-31 16:01:25 +000033 _pP11(1e10) {
Karl Wiberg79eb1d92017-11-08 12:26:07 +010034 Reset(start_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
Karl Wiberg79eb1d92017-11-08 12:26:07 +010037TimestampExtrapolator::~TimestampExtrapolator() {
38 delete _rwLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000039}
40
Karl Wiberg79eb1d92017-11-08 12:26:07 +010041void TimestampExtrapolator::Reset(int64_t start_ms) {
42 WriteLockScoped wl(*_rwLock);
43 _startMs = start_ms;
44 _prevMs = _startMs;
45 _firstTimestamp = 0;
46 _w[0] = 90.0;
47 _w[1] = 0;
48 _pP[0][0] = 1;
49 _pP[1][1] = _pP11;
50 _pP[0][1] = _pP[1][0] = 0;
51 _firstAfterReset = true;
52 _prevUnwrappedTimestamp = -1;
53 _prevWrapTimestamp = -1;
54 _wrapArounds = 0;
55 _packetCount = 0;
56 _detectorAccumulatorPos = 0;
57 _detectorAccumulatorNeg = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000058}
59
Karl Wiberg79eb1d92017-11-08 12:26:07 +010060void TimestampExtrapolator::Update(int64_t tMs, uint32_t ts90khz) {
61 _rwLock->AcquireLockExclusive();
62 if (tMs - _prevMs > 10e3) {
63 // Ten seconds without a complete frame.
64 // Reset the extrapolator
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000065 _rwLock->ReleaseLockExclusive();
Karl Wiberg79eb1d92017-11-08 12:26:07 +010066 Reset(tMs);
67 _rwLock->AcquireLockExclusive();
68 } else {
69 _prevMs = tMs;
70 }
71
72 // Remove offset to prevent badly scaled matrices
73 tMs -= _startMs;
74
75 CheckForWrapArounds(ts90khz);
76
77 int64_t unwrapped_ts90khz =
78 static_cast<int64_t>(ts90khz) +
79 _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
80
81 if (_firstAfterReset) {
82 // Make an initial guess of the offset,
83 // should be almost correct since tMs - _startMs
84 // should about zero at this time.
85 _w[1] = -_w[0] * tMs;
86 _firstTimestamp = unwrapped_ts90khz;
87 _firstAfterReset = false;
88 }
89
90 double residual = (static_cast<double>(unwrapped_ts90khz) - _firstTimestamp) -
91 static_cast<double>(tMs) * _w[0] - _w[1];
92 if (DelayChangeDetection(residual) &&
93 _packetCount >= _startUpFilterDelayInPackets) {
94 // A sudden change of average network delay has been detected.
95 // Force the filter to adjust its offset parameter by changing
96 // the offset uncertainty. Don't do this during startup.
97 _pP[1][1] = _pP11;
98 }
99
100 if (_prevUnwrappedTimestamp >= 0 &&
101 unwrapped_ts90khz < _prevUnwrappedTimestamp) {
102 // Drop reordered frames.
103 _rwLock->ReleaseLockExclusive();
104 return;
105 }
106
107 // T = [t(k) 1]';
108 // that = T'*w;
109 // K = P*T/(lambda + T'*P*T);
110 double K[2];
111 K[0] = _pP[0][0] * tMs + _pP[0][1];
112 K[1] = _pP[1][0] * tMs + _pP[1][1];
113 double TPT = _lambda + tMs * K[0] + K[1];
114 K[0] /= TPT;
115 K[1] /= TPT;
116 // w = w + K*(ts(k) - that);
117 _w[0] = _w[0] + K[0] * residual;
118 _w[1] = _w[1] + K[1] * residual;
119 // P = 1/lambda*(P - K*T'*P);
120 double p00 =
121 1 / _lambda * (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
122 double p01 =
123 1 / _lambda * (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
124 _pP[1][0] =
125 1 / _lambda * (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
126 _pP[1][1] =
127 1 / _lambda * (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
128 _pP[0][0] = p00;
129 _pP[0][1] = p01;
130 _prevUnwrappedTimestamp = unwrapped_ts90khz;
131 if (_packetCount < _startUpFilterDelayInPackets) {
132 _packetCount++;
133 }
134 _rwLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +0000135}
136
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100137int64_t TimestampExtrapolator::ExtrapolateLocalTime(uint32_t timestamp90khz) {
138 ReadLockScoped rl(*_rwLock);
139 int64_t localTimeMs = 0;
140 CheckForWrapArounds(timestamp90khz);
141 double unwrapped_ts90khz =
142 static_cast<double>(timestamp90khz) +
143 _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
144 if (_packetCount == 0) {
145 localTimeMs = -1;
146 } else if (_packetCount < _startUpFilterDelayInPackets) {
147 localTimeMs =
148 _prevMs +
149 static_cast<int64_t>(
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000150 static_cast<double>(unwrapped_ts90khz - _prevUnwrappedTimestamp) /
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100151 90.0 +
152 0.5);
153 } else {
154 if (_w[0] < 1e-3) {
155 localTimeMs = _startMs;
156 } else {
157 double timestampDiff =
158 unwrapped_ts90khz - static_cast<double>(_firstTimestamp);
159 localTimeMs = static_cast<int64_t>(static_cast<double>(_startMs) +
160 (timestampDiff - _w[1]) / _w[0] + 0.5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 }
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100162 }
163 return localTimeMs;
niklase@google.com470e71d2011-07-07 08:21:25 +0000164}
165
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100166// Investigates if the timestamp clock has overflowed since the last timestamp
167// and keeps track of the number of wrap arounds since reset.
168void TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz) {
169 if (_prevWrapTimestamp == -1) {
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000170 _prevWrapTimestamp = ts90khz;
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100171 return;
172 }
173 if (ts90khz < _prevWrapTimestamp) {
174 // This difference will probably be less than -2^31 if we have had a wrap
175 // around (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is
176 // casted to a Word32, it should be positive.
177 if (static_cast<int32_t>(ts90khz - _prevWrapTimestamp) > 0) {
178 // Forward wrap around
179 _wrapArounds++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 }
Karl Wiberg76b7f512018-03-22 15:29:03 +0100181 } else {
182 // This difference will probably be less than -2^31 if we have had a
183 // backward wrap around. Since it is casted to a Word32, it should be
184 // positive.
185 if (static_cast<int32_t>(_prevWrapTimestamp - ts90khz) > 0) {
186 // Backward wrap around
187 _wrapArounds--;
188 }
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100189 }
190 _prevWrapTimestamp = ts90khz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000191}
192
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100193bool TimestampExtrapolator::DelayChangeDetection(double error) {
194 // CUSUM detection of sudden delay changes
195 error = (error > 0) ? std::min(error, _accMaxError)
196 : std::max(error, -_accMaxError);
197 _detectorAccumulatorPos =
Karl Wiberg76b7f512018-03-22 15:29:03 +0100198 std::max(_detectorAccumulatorPos + error - _accDrift, double{0});
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100199 _detectorAccumulatorNeg =
Karl Wiberg76b7f512018-03-22 15:29:03 +0100200 std::min(_detectorAccumulatorNeg + error + _accDrift, double{0});
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100201 if (_detectorAccumulatorPos > _alarmThreshold ||
202 _detectorAccumulatorNeg < -_alarmThreshold) {
203 // Alarm
204 _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
205 return true;
206 }
207 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208}
Karl Wiberg79eb1d92017-11-08 12:26:07 +0100209
210} // namespace webrtc