211 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 | |
|  *
 | |
|  *  Use of this source code is governed by a BSD-style license
 | |
|  *  that can be found in the LICENSE file in the root of the source
 | |
|  *  tree. An additional intellectual property rights grant can be found
 | |
|  *  in the file PATENTS.  All contributing project authors may
 | |
|  *  be found in the AUTHORS file in the root of the source tree.
 | |
|  */
 | |
| 
 | |
| #include "rtc_base/time/timestamp_extrapolator.h"
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| namespace webrtc {
 | |
| 
 | |
| TimestampExtrapolator::TimestampExtrapolator(int64_t start_ms)
 | |
|     : _rwLock(RWLockWrapper::CreateRWLock()),
 | |
|       _startMs(0),
 | |
|       _firstTimestamp(0),
 | |
|       _wrapArounds(0),
 | |
|       _prevUnwrappedTimestamp(-1),
 | |
|       _prevWrapTimestamp(-1),
 | |
|       _lambda(1),
 | |
|       _firstAfterReset(true),
 | |
|       _packetCount(0),
 | |
|       _startUpFilterDelayInPackets(2),
 | |
|       _detectorAccumulatorPos(0),
 | |
|       _detectorAccumulatorNeg(0),
 | |
|       _alarmThreshold(60e3),
 | |
|       _accDrift(6600),  // in timestamp ticks, i.e. 15 ms
 | |
|       _accMaxError(7000),
 | |
|       _pP11(1e10) {
 | |
|   Reset(start_ms);
 | |
| }
 | |
| 
 | |
| TimestampExtrapolator::~TimestampExtrapolator() {
 | |
|   delete _rwLock;
 | |
| }
 | |
| 
 | |
| void TimestampExtrapolator::Reset(int64_t start_ms) {
 | |
|   WriteLockScoped wl(*_rwLock);
 | |
|   _startMs = start_ms;
 | |
|   _prevMs = _startMs;
 | |
|   _firstTimestamp = 0;
 | |
|   _w[0] = 90.0;
 | |
|   _w[1] = 0;
 | |
|   _pP[0][0] = 1;
 | |
|   _pP[1][1] = _pP11;
 | |
|   _pP[0][1] = _pP[1][0] = 0;
 | |
|   _firstAfterReset = true;
 | |
|   _prevUnwrappedTimestamp = -1;
 | |
|   _prevWrapTimestamp = -1;
 | |
|   _wrapArounds = 0;
 | |
|   _packetCount = 0;
 | |
|   _detectorAccumulatorPos = 0;
 | |
|   _detectorAccumulatorNeg = 0;
 | |
| }
 | |
| 
 | |
| void TimestampExtrapolator::Update(int64_t tMs, uint32_t ts90khz) {
 | |
|   _rwLock->AcquireLockExclusive();
 | |
|   if (tMs - _prevMs > 10e3) {
 | |
|     // Ten seconds without a complete frame.
 | |
|     // Reset the extrapolator
 | |
|     _rwLock->ReleaseLockExclusive();
 | |
|     Reset(tMs);
 | |
|     _rwLock->AcquireLockExclusive();
 | |
|   } else {
 | |
|     _prevMs = tMs;
 | |
|   }
 | |
| 
 | |
|   // Remove offset to prevent badly scaled matrices
 | |
|   tMs -= _startMs;
 | |
| 
 | |
|   CheckForWrapArounds(ts90khz);
 | |
| 
 | |
|   int64_t unwrapped_ts90khz =
 | |
|       static_cast<int64_t>(ts90khz) +
 | |
|       _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
 | |
| 
 | |
|   if (_firstAfterReset) {
 | |
|     // Make an initial guess of the offset,
 | |
|     // should be almost correct since tMs - _startMs
 | |
|     // should about zero at this time.
 | |
|     _w[1] = -_w[0] * tMs;
 | |
|     _firstTimestamp = unwrapped_ts90khz;
 | |
|     _firstAfterReset = false;
 | |
|   }
 | |
| 
 | |
|   double residual = (static_cast<double>(unwrapped_ts90khz) - _firstTimestamp) -
 | |
|                     static_cast<double>(tMs) * _w[0] - _w[1];
 | |
|   if (DelayChangeDetection(residual) &&
 | |
|       _packetCount >= _startUpFilterDelayInPackets) {
 | |
|     // A sudden change of average network delay has been detected.
 | |
|     // Force the filter to adjust its offset parameter by changing
 | |
|     // the offset uncertainty. Don't do this during startup.
 | |
|     _pP[1][1] = _pP11;
 | |
|   }
 | |
| 
 | |
|   if (_prevUnwrappedTimestamp >= 0 &&
 | |
|       unwrapped_ts90khz < _prevUnwrappedTimestamp) {
 | |
|     // Drop reordered frames.
 | |
|     _rwLock->ReleaseLockExclusive();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // T = [t(k) 1]';
 | |
|   // that = T'*w;
 | |
|   // K = P*T/(lambda + T'*P*T);
 | |
|   double K[2];
 | |
|   K[0] = _pP[0][0] * tMs + _pP[0][1];
 | |
|   K[1] = _pP[1][0] * tMs + _pP[1][1];
 | |
|   double TPT = _lambda + tMs * K[0] + K[1];
 | |
|   K[0] /= TPT;
 | |
|   K[1] /= TPT;
 | |
|   // w = w + K*(ts(k) - that);
 | |
|   _w[0] = _w[0] + K[0] * residual;
 | |
|   _w[1] = _w[1] + K[1] * residual;
 | |
|   // P = 1/lambda*(P - K*T'*P);
 | |
|   double p00 =
 | |
|       1 / _lambda * (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
 | |
|   double p01 =
 | |
|       1 / _lambda * (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
 | |
|   _pP[1][0] =
 | |
|       1 / _lambda * (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
 | |
|   _pP[1][1] =
 | |
|       1 / _lambda * (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
 | |
|   _pP[0][0] = p00;
 | |
|   _pP[0][1] = p01;
 | |
|   _prevUnwrappedTimestamp = unwrapped_ts90khz;
 | |
|   if (_packetCount < _startUpFilterDelayInPackets) {
 | |
|     _packetCount++;
 | |
|   }
 | |
|   _rwLock->ReleaseLockExclusive();
 | |
| }
 | |
| 
 | |
| int64_t TimestampExtrapolator::ExtrapolateLocalTime(uint32_t timestamp90khz) {
 | |
|   ReadLockScoped rl(*_rwLock);
 | |
|   int64_t localTimeMs = 0;
 | |
|   CheckForWrapArounds(timestamp90khz);
 | |
|   double unwrapped_ts90khz =
 | |
|       static_cast<double>(timestamp90khz) +
 | |
|       _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
 | |
|   if (_packetCount == 0) {
 | |
|     localTimeMs = -1;
 | |
|   } else if (_packetCount < _startUpFilterDelayInPackets) {
 | |
|     localTimeMs =
 | |
|         _prevMs +
 | |
|         static_cast<int64_t>(
 | |
|             static_cast<double>(unwrapped_ts90khz - _prevUnwrappedTimestamp) /
 | |
|                 90.0 +
 | |
|             0.5);
 | |
|   } else {
 | |
|     if (_w[0] < 1e-3) {
 | |
|       localTimeMs = _startMs;
 | |
|     } else {
 | |
|       double timestampDiff =
 | |
|           unwrapped_ts90khz - static_cast<double>(_firstTimestamp);
 | |
|       localTimeMs = static_cast<int64_t>(static_cast<double>(_startMs) +
 | |
|                                          (timestampDiff - _w[1]) / _w[0] + 0.5);
 | |
|     }
 | |
|   }
 | |
|   return localTimeMs;
 | |
| }
 | |
| 
 | |
| // Investigates if the timestamp clock has overflowed since the last timestamp
 | |
| // and keeps track of the number of wrap arounds since reset.
 | |
| void TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz) {
 | |
|   if (_prevWrapTimestamp == -1) {
 | |
|     _prevWrapTimestamp = ts90khz;
 | |
|     return;
 | |
|   }
 | |
|   if (ts90khz < _prevWrapTimestamp) {
 | |
|     // This difference will probably be less than -2^31 if we have had a wrap
 | |
|     // around (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is
 | |
|     // casted to a Word32, it should be positive.
 | |
|     if (static_cast<int32_t>(ts90khz - _prevWrapTimestamp) > 0) {
 | |
|       // Forward wrap around
 | |
|       _wrapArounds++;
 | |
|     }
 | |
|   } else {
 | |
|     // This difference will probably be less than -2^31 if we have had a
 | |
|     // backward wrap around. Since it is casted to a Word32, it should be
 | |
|     // positive.
 | |
|     if (static_cast<int32_t>(_prevWrapTimestamp - ts90khz) > 0) {
 | |
|       // Backward wrap around
 | |
|       _wrapArounds--;
 | |
|     }
 | |
|   }
 | |
|   _prevWrapTimestamp = ts90khz;
 | |
| }
 | |
| 
 | |
| bool TimestampExtrapolator::DelayChangeDetection(double error) {
 | |
|   // CUSUM detection of sudden delay changes
 | |
|   error = (error > 0) ? std::min(error, _accMaxError)
 | |
|                       : std::max(error, -_accMaxError);
 | |
|   _detectorAccumulatorPos =
 | |
|       std::max(_detectorAccumulatorPos + error - _accDrift, double{0});
 | |
|   _detectorAccumulatorNeg =
 | |
|       std::min(_detectorAccumulatorNeg + error + _accDrift, double{0});
 | |
|   if (_detectorAccumulatorPos > _alarmThreshold ||
 | |
|       _detectorAccumulatorNeg < -_alarmThreshold) {
 | |
|     // Alarm
 | |
|     _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
 | |
|     return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| }  // namespace webrtc
 |