mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

These tests often fail in 'ExtrapolateLocalTime' because the result gives a negative Timestamp. Here is the stack from https://chromium-swarm.appspot.com/task?id=6173230e67897b10: PC: @ 0x7f03afdb8e87 (unknown) raise ... @ 0x55f4a360ba71 352 webrtc::Timestamp::operator+() @ 0x55f4a47ecaf3 160 webrtc::TimestampExtrapolator::ExtrapolateLocalTime() Low-Coverage-Reason: coverage isn't that low. Change-Id: If3e7cbf31d6c4800727b24352ed2c6edc425fc73 Bug: webrtc:15022 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/300600 Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Commit-Queue: Jeremy Leconte <jleconte@google.com> Cr-Commit-Position: refs/heads/main@{#39853}
173 lines
5.4 KiB
C++
173 lines
5.4 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 "modules/video_coding/timing/timestamp_extrapolator.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "absl/types/optional.h"
|
|
#include "rtc_base/numerics/sequence_number_unwrapper.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
constexpr double kLambda = 1;
|
|
constexpr uint32_t kStartUpFilterDelayInPackets = 2;
|
|
constexpr double kAlarmThreshold = 60e3;
|
|
// in timestamp ticks, i.e. 15 ms
|
|
constexpr double kAccDrift = 6600;
|
|
constexpr double kAccMaxError = 7000;
|
|
constexpr double kP11 = 1e10;
|
|
|
|
} // namespace
|
|
|
|
TimestampExtrapolator::TimestampExtrapolator(Timestamp start)
|
|
: start_(Timestamp::Zero()),
|
|
prev_(Timestamp::Zero()),
|
|
packet_count_(0),
|
|
detector_accumulator_pos_(0),
|
|
detector_accumulator_neg_(0) {
|
|
Reset(start);
|
|
}
|
|
|
|
void TimestampExtrapolator::Reset(Timestamp start) {
|
|
start_ = start;
|
|
prev_ = start_;
|
|
first_unwrapped_timestamp_ = absl::nullopt;
|
|
w_[0] = 90.0;
|
|
w_[1] = 0;
|
|
p_[0][0] = 1;
|
|
p_[1][1] = kP11;
|
|
p_[0][1] = p_[1][0] = 0;
|
|
unwrapper_ = RtpTimestampUnwrapper();
|
|
packet_count_ = 0;
|
|
detector_accumulator_pos_ = 0;
|
|
detector_accumulator_neg_ = 0;
|
|
}
|
|
|
|
void TimestampExtrapolator::Update(Timestamp now, uint32_t ts90khz) {
|
|
if (now - prev_ > TimeDelta::Seconds(10)) {
|
|
// Ten seconds without a complete frame.
|
|
// Reset the extrapolator
|
|
Reset(now);
|
|
} else {
|
|
prev_ = now;
|
|
}
|
|
|
|
// Remove offset to prevent badly scaled matrices
|
|
const TimeDelta offset = now - start_;
|
|
double t_ms = offset.ms();
|
|
|
|
int64_t unwrapped_ts90khz = unwrapper_.Unwrap(ts90khz);
|
|
|
|
if (!first_unwrapped_timestamp_) {
|
|
// Make an initial guess of the offset,
|
|
// should be almost correct since t_ms - start
|
|
// should about zero at this time.
|
|
w_[1] = -w_[0] * t_ms;
|
|
first_unwrapped_timestamp_ = unwrapped_ts90khz;
|
|
}
|
|
|
|
double residual =
|
|
(static_cast<double>(unwrapped_ts90khz) - *first_unwrapped_timestamp_) -
|
|
t_ms * w_[0] - w_[1];
|
|
if (DelayChangeDetection(residual) &&
|
|
packet_count_ >= kStartUpFilterDelayInPackets) {
|
|
// 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.
|
|
p_[1][1] = kP11;
|
|
}
|
|
|
|
if (prev_unwrapped_timestamp_ &&
|
|
unwrapped_ts90khz < prev_unwrapped_timestamp_) {
|
|
// Drop reordered frames.
|
|
return;
|
|
}
|
|
|
|
// T = [t(k) 1]';
|
|
// that = T'*w;
|
|
// K = P*T/(lambda + T'*P*T);
|
|
double K[2];
|
|
K[0] = p_[0][0] * t_ms + p_[0][1];
|
|
K[1] = p_[1][0] * t_ms + p_[1][1];
|
|
double TPT = kLambda + t_ms * 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 / kLambda * (p_[0][0] - (K[0] * t_ms * p_[0][0] + K[0] * p_[1][0]));
|
|
double p01 =
|
|
1 / kLambda * (p_[0][1] - (K[0] * t_ms * p_[0][1] + K[0] * p_[1][1]));
|
|
p_[1][0] =
|
|
1 / kLambda * (p_[1][0] - (K[1] * t_ms * p_[0][0] + K[1] * p_[1][0]));
|
|
p_[1][1] =
|
|
1 / kLambda * (p_[1][1] - (K[1] * t_ms * p_[0][1] + K[1] * p_[1][1]));
|
|
p_[0][0] = p00;
|
|
p_[0][1] = p01;
|
|
prev_unwrapped_timestamp_ = unwrapped_ts90khz;
|
|
if (packet_count_ < kStartUpFilterDelayInPackets) {
|
|
packet_count_++;
|
|
}
|
|
}
|
|
|
|
absl::optional<Timestamp> TimestampExtrapolator::ExtrapolateLocalTime(
|
|
uint32_t timestamp90khz) const {
|
|
int64_t unwrapped_ts90khz = unwrapper_.PeekUnwrap(timestamp90khz);
|
|
|
|
if (!first_unwrapped_timestamp_) {
|
|
return absl::nullopt;
|
|
} else if (packet_count_ < kStartUpFilterDelayInPackets) {
|
|
constexpr double kRtpTicksPerMs = 90;
|
|
TimeDelta diff = TimeDelta::Millis(
|
|
(unwrapped_ts90khz - *prev_unwrapped_timestamp_) / kRtpTicksPerMs);
|
|
if (prev_.us() + diff.us() < 0) {
|
|
// Prevent the construction of a negative Timestamp.
|
|
// This scenario can occur when the RTP timestamp wraps around.
|
|
return absl::nullopt;
|
|
}
|
|
return prev_ + diff;
|
|
} else if (w_[0] < 1e-3) {
|
|
return start_;
|
|
} else {
|
|
double timestampDiff = unwrapped_ts90khz - *first_unwrapped_timestamp_;
|
|
TimeDelta diff = TimeDelta::Millis(
|
|
static_cast<int64_t>((timestampDiff - w_[1]) / w_[0] + 0.5));
|
|
if (start_.us() + diff.us() < 0) {
|
|
// Prevent the construction of a negative Timestamp.
|
|
// This scenario can occur when the RTP timestamp wraps around.
|
|
return absl::nullopt;
|
|
}
|
|
return start_ + diff;
|
|
}
|
|
}
|
|
|
|
bool TimestampExtrapolator::DelayChangeDetection(double error) {
|
|
// CUSUM detection of sudden delay changes
|
|
error = (error > 0) ? std::min(error, kAccMaxError)
|
|
: std::max(error, -kAccMaxError);
|
|
detector_accumulator_pos_ =
|
|
std::max(detector_accumulator_pos_ + error - kAccDrift, double{0});
|
|
detector_accumulator_neg_ =
|
|
std::min(detector_accumulator_neg_ + error + kAccDrift, double{0});
|
|
if (detector_accumulator_pos_ > kAlarmThreshold ||
|
|
detector_accumulator_neg_ < -kAlarmThreshold) {
|
|
// Alarm
|
|
detector_accumulator_pos_ = detector_accumulator_neg_ = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // namespace webrtc
|