blob: b9243ca80c2a75d0b5df5f17134e2cb6c33a7379 [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
Henrik Kjellander98f53512015-10-28 18:17:40 +010011#include "webrtc/system_wrappers/include/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) {
wu@webrtc.orged4cb562014-05-06 04:50:49 +000034 Reset(start_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
wu@webrtc.org66773a02014-05-07 17:09:44 +000037TimestampExtrapolator::~TimestampExtrapolator()
niklase@google.com470e71d2011-07-07 08:21:25 +000038{
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000039 delete _rwLock;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
wu@webrtc.org66773a02014-05-07 17:09:44 +000042void TimestampExtrapolator::Reset(int64_t start_ms)
niklase@google.com470e71d2011-07-07 08:21:25 +000043{
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000044 WriteLockScoped wl(*_rwLock);
wu@webrtc.orged4cb562014-05-06 04:50:49 +000045 _startMs = start_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +000046 _prevMs = _startMs;
47 _firstTimestamp = 0;
48 _w[0] = 90.0;
49 _w[1] = 0;
andrew@webrtc.orgcc476aa2014-10-31 16:01:25 +000050 _pP[0][0] = 1;
51 _pP[1][1] = _pP11;
52 _pP[0][1] = _pP[1][0] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000053 _firstAfterReset = true;
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000054 _prevUnwrappedTimestamp = -1;
55 _prevWrapTimestamp = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000056 _wrapArounds = 0;
57 _packetCount = 0;
58 _detectorAccumulatorPos = 0;
59 _detectorAccumulatorNeg = 0;
60}
61
62void
wu@webrtc.org66773a02014-05-07 17:09:44 +000063TimestampExtrapolator::Update(int64_t tMs, uint32_t ts90khz)
niklase@google.com470e71d2011-07-07 08:21:25 +000064{
65
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000066 _rwLock->AcquireLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +000067 if (tMs - _prevMs > 10e3)
68 {
69 // Ten seconds without a complete frame.
70 // Reset the extrapolator
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000071 _rwLock->ReleaseLockExclusive();
wu@webrtc.orged4cb562014-05-06 04:50:49 +000072 Reset(tMs);
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +000073 _rwLock->AcquireLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +000074 }
75 else
76 {
77 _prevMs = tMs;
78 }
79
80 // Remove offset to prevent badly scaled matrices
81 tMs -= _startMs;
82
niklase@google.com470e71d2011-07-07 08:21:25 +000083 CheckForWrapArounds(ts90khz);
niklase@google.com470e71d2011-07-07 08:21:25 +000084
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000085 int64_t unwrapped_ts90khz = static_cast<int64_t>(ts90khz) +
86 _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
87
niklase@google.com470e71d2011-07-07 08:21:25 +000088 if (_firstAfterReset)
89 {
90 // Make an initial guess of the offset,
91 // should be almost correct since tMs - _startMs
92 // should about zero at this time.
93 _w[1] = -_w[0] * tMs;
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000094 _firstTimestamp = unwrapped_ts90khz;
niklase@google.com470e71d2011-07-07 08:21:25 +000095 _firstAfterReset = false;
96 }
97
stefan@webrtc.org9f557c12013-05-17 12:55:07 +000098 double residual =
99 (static_cast<double>(unwrapped_ts90khz) - _firstTimestamp) -
100 static_cast<double>(tMs) * _w[0] - _w[1];
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000101 if (DelayChangeDetection(residual) &&
niklase@google.com470e71d2011-07-07 08:21:25 +0000102 _packetCount >= _startUpFilterDelayInPackets)
103 {
104 // A sudden change of average network delay has been detected.
105 // Force the filter to adjust its offset parameter by changing
106 // the offset uncertainty. Don't do this during startup.
andrew@webrtc.orgcc476aa2014-10-31 16:01:25 +0000107 _pP[1][1] = _pP11;
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 }
qiangchen067121a2017-04-19 09:57:37 -0700109
110 if (_prevUnwrappedTimestamp >= 0 &&
111 unwrapped_ts90khz < _prevUnwrappedTimestamp)
112 {
113 // Drop reordered frames.
114 _rwLock->ReleaseLockExclusive();
115 return;
116 }
117
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 //T = [t(k) 1]';
119 //that = T'*w;
120 //K = P*T/(lambda + T'*P*T);
121 double K[2];
andrew@webrtc.orgcc476aa2014-10-31 16:01:25 +0000122 K[0] = _pP[0][0] * tMs + _pP[0][1];
123 K[1] = _pP[1][0] * tMs + _pP[1][1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000124 double TPT = _lambda + tMs * K[0] + K[1];
125 K[0] /= TPT;
126 K[1] /= TPT;
127 //w = w + K*(ts(k) - that);
128 _w[0] = _w[0] + K[0] * residual;
129 _w[1] = _w[1] + K[1] * residual;
130 //P = 1/lambda*(P - K*T'*P);
andrew@webrtc.orgcc476aa2014-10-31 16:01:25 +0000131 double p00 = 1 / _lambda *
132 (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
133 double p01 = 1 / _lambda *
134 (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
135 _pP[1][0] = 1 / _lambda *
136 (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
137 _pP[1][1] = 1 / _lambda *
138 (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
139 _pP[0][0] = p00;
140 _pP[0][1] = p01;
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000141 _prevUnwrappedTimestamp = unwrapped_ts90khz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 if (_packetCount < _startUpFilterDelayInPackets)
143 {
144 _packetCount++;
145 }
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +0000146 _rwLock->ReleaseLockExclusive();
niklase@google.com470e71d2011-07-07 08:21:25 +0000147}
148
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000149int64_t
wu@webrtc.org66773a02014-05-07 17:09:44 +0000150TimestampExtrapolator::ExtrapolateLocalTime(uint32_t timestamp90khz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000151{
stefan@webrtc.org7889a9b2011-12-12 08:18:24 +0000152 ReadLockScoped rl(*_rwLock);
pbos@webrtc.org7b859cc2013-04-02 15:54:38 +0000153 int64_t localTimeMs = 0;
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000154 CheckForWrapArounds(timestamp90khz);
155 double unwrapped_ts90khz = static_cast<double>(timestamp90khz) +
156 _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 if (_packetCount == 0)
158 {
159 localTimeMs = -1;
160 }
161 else if (_packetCount < _startUpFilterDelayInPackets)
162 {
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000163 localTimeMs = _prevMs + static_cast<int64_t>(
164 static_cast<double>(unwrapped_ts90khz - _prevUnwrappedTimestamp) /
165 90.0 + 0.5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 }
167 else
168 {
169 if (_w[0] < 1e-3)
170 {
171 localTimeMs = _startMs;
172 }
173 else
174 {
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000175 double timestampDiff = unwrapped_ts90khz -
176 static_cast<double>(_firstTimestamp);
177 localTimeMs = static_cast<int64_t>(
178 static_cast<double>(_startMs) + (timestampDiff - _w[1]) /
179 _w[0] + 0.5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 }
181 }
182 return localTimeMs;
183}
184
185// Investigates if the timestamp clock has overflowed since the last timestamp and
186// keeps track of the number of wrap arounds since reset.
187void
wu@webrtc.org66773a02014-05-07 17:09:44 +0000188TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000189{
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000190 if (_prevWrapTimestamp == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 {
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000192 _prevWrapTimestamp = ts90khz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 return;
194 }
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000195 if (ts90khz < _prevWrapTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 {
197 // This difference will probably be less than -2^31 if we have had a wrap around
198 // (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is casted to a Word32,
199 // it should be positive.
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000200 if (static_cast<int32_t>(ts90khz - _prevWrapTimestamp) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 {
202 // Forward wrap around
203 _wrapArounds++;
204 }
205 }
206 // This difference will probably be less than -2^31 if we have had a backward wrap around.
207 // Since it is casted to a Word32, it should be positive.
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000208 else if (static_cast<int32_t>(_prevWrapTimestamp - ts90khz) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 {
210 // Backward wrap around
211 _wrapArounds--;
212 }
stefan@webrtc.org9f557c12013-05-17 12:55:07 +0000213 _prevWrapTimestamp = ts90khz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214}
215
216bool
wu@webrtc.org66773a02014-05-07 17:09:44 +0000217TimestampExtrapolator::DelayChangeDetection(double error)
niklase@google.com470e71d2011-07-07 08:21:25 +0000218{
219 // CUSUM detection of sudden delay changes
wu@webrtc.orged4cb562014-05-06 04:50:49 +0000220 error = (error > 0) ? std::min(error, _accMaxError) :
221 std::max(error, -_accMaxError);
222 _detectorAccumulatorPos =
223 std::max(_detectorAccumulatorPos + error - _accDrift, (double)0);
224 _detectorAccumulatorNeg =
225 std::min(_detectorAccumulatorNeg + error + _accDrift, (double)0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 if (_detectorAccumulatorPos > _alarmThreshold || _detectorAccumulatorNeg < -_alarmThreshold)
227 {
228 // Alarm
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
230 return true;
231 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000232 return false;
233}
234
235}