/* * 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. */ #ifndef MODULES_VIDEO_CODING_TIMING_TIMESTAMP_EXTRAPOLATOR_H_ #define MODULES_VIDEO_CODING_TIMING_TIMESTAMP_EXTRAPOLATOR_H_ #include #include #include #include "absl/strings/string_view.h" #include "api/field_trials_view.h" #include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/numerics/sequence_number_unwrapper.h" namespace webrtc { // The `TimestampExtrapolator` is an adaptive filter that estimates the // local clock time of incoming RTP timestamps. It's main purpose is to handle // clock drift and clock offset, not to model network behaviour. // // The mechanisms applied for this are: // * Recursive least-squares filter for estimating clock skew and clock offset. // * Hard reset on wall clock timeout. // * Hard reset on large incoming RTP timestamp jumps. // * Hard outlier rejection based on the difference between the predicted and // the actual wall clock time for an RTP timestamp. // * Soft outlier attenuation based on the integrated (CUSUM style) difference // between predicted and actual wall clock time for an RTP timestamp. // // Not all of the mechanisms are enabled by default. Use the field trial string // to experiment with different settings. // // Not thread safe. class TimestampExtrapolator { public: // Configuration struct for overriding some constants and behaviour, // configurable through field trials. struct Config { inline static constexpr absl::string_view kFieldTrialsKey = "WebRTC-TimestampExtrapolatorConfig"; // Factory function that parses the field trials and returns a `Config` // with validated values. static Config ParseAndValidate(const FieldTrialsView& field_trials); std::unique_ptr Parser() { // clang-format off return StructParametersParser::Create( "hard_reset_timeout", &hard_reset_timeout, "hard_reset_rtp_timestamp_jump_threshold", &hard_reset_rtp_timestamp_jump_threshold, "outlier_rejection_startup_delay", &outlier_rejection_startup_delay, "outlier_rejection_max_consecutive", &outlier_rejection_max_consecutive, "outlier_rejection_forgetting_factor", &outlier_rejection_forgetting_factor, "outlier_rejection_stddev", &outlier_rejection_stddev, "alarm_threshold", &alarm_threshold, "acc_drift", &acc_drift, "acc_max_error", &acc_max_error, "reset_full_cov_on_alarm", &reset_full_cov_on_alarm); // clang-format on } bool OutlierRejectionEnabled() const { return outlier_rejection_stddev.has_value(); } // -- Hard reset behaviour -- // If a frame has not been received within this timeout, do a full reset. TimeDelta hard_reset_timeout = TimeDelta::Seconds(10); // A jump in the RTP timestamp of this magnitude, not accounted for by the // passage of time, is considered a source clock replacement and will // trigger a filter reset. 900000 ticks = 10 seconds. // (Only enabled if hard outlier rejection is enabled.) int hard_reset_rtp_timestamp_jump_threshold = 900'000; // -- Hard outlier rejection -- // Number of frames to wait before starting to update the residual // statistics. 300 frames = 10 seconds@30fps. int outlier_rejection_startup_delay = 300; // Number of consecutive frames that are allowed to be treated as outliers. // If more frames than these are outliers, hard outlier rejection stops // and soft outlier attentuation starts. // 150 frames = 5 seconds@30fps. int outlier_rejection_max_consecutive = 150; // Smoothing factor for the residual statistics. // Half-life is log(0.5)/log(0.999) ~= 693 frames ~= 23 seconds@30fps. double outlier_rejection_forgetting_factor = 0.999; // If set, will reject outliers based on this number of standard deviations // of the filtered residuals. // Setting this field to non-nullopt enables hard outlier rejection. std::optional outlier_rejection_stddev = 2.0; // -- Soft outlier attenuation -- // Alarm on sudden delay change if the (filtered; see below) accumulated // residuals are larger than this number of RTP ticks. After the // startup period, an alarm will result in a full or partial reset of the // uncertainty covariance (see `reset_full_cov_on_alarm` below). int alarm_threshold = 60000; // 666 ms <=> 20 frames@30fps. // Acceptable level of per-frame drift in the detector (in RTP ticks). int acc_drift = 6600; // 73 ms <=> 2.2 frames@30fps. // Max limit on residuals in the detector (in RTP ticks). // TODO(brandtr): Increase from this unreasonably low value. int acc_max_error = 7000; // 77 ms <=> 2.3 frames@30fps. // If true, reset the entire uncertainty covariance matrix on alarms. // If false, only reset the offset variance term. // TODO(brandtr): Flip so that the frequency term won't get hit tpp badly // when a large delay spike happens. bool reset_full_cov_on_alarm = false; }; TimestampExtrapolator(Timestamp start, const FieldTrialsView& field_trials); ~TimestampExtrapolator(); // Update the filter with a new incoming local timestamp/RTP timestamp pair. void Update(Timestamp now, uint32_t ts90khz); // Return the expected local timestamp for an RTP timestamp. std::optional ExtrapolateLocalTime(uint32_t timestamp90khz) const; void Reset(Timestamp start); Config GetConfigForTest() const { return config_; } private: void SoftReset(); bool OutlierDetection(double residual); bool DelayChangeDetection(double residual); const Config config_; double w_[2]; double p_[2][2]; Timestamp start_; Timestamp prev_; std::optional first_unwrapped_timestamp_; RtpTimestampUnwrapper unwrapper_; std::optional prev_unwrapped_timestamp_; int packet_count_; // Running residual statistics for the hard outlier rejection. double residual_mean_; double residual_variance_; int outliers_consecutive_count_; // Integrated residual statistics for the soft outlier attenuation. double detector_accumulator_pos_; double detector_accumulator_neg_; }; } // namespace webrtc #endif // MODULES_VIDEO_CODING_TIMING_TIMESTAMP_EXTRAPOLATOR_H_