blob: a65ceefa106504c6d23f831286af277b9c592c84 [file] [log] [blame]
* Copyright (c) 2022 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 "api/units/data_size.h"
#include "api/units/time_delta.h"
namespace webrtc {
// This class uses a linear Kalman filter (see
// to estimate the frame delay
// variation (i.e., the difference in transmission time between a frame and the
// prior frame) for a frame, given its size variation in bytes (i.e., the
// difference in size between a frame and the prior frame). The idea is that,
// given a fixed link bandwidth, a larger frame (in bytes) would take
// proportionally longer to arrive than a correspondingly smaller frame. Using
// the variations of frame delay and frame size, the underlying bandwidth and
// queuing delay variation of the network link can be estimated.
// The filter takes as input the frame delay variation, the difference between
// the actual inter-frame arrival time and the expected inter-frame arrival time
// (based on RTP timestamp), and frame size variation, the inter-frame size
// delta for a single frame. The frame delay variation is seen as the
// measurement and the frame size variation is used in the observation model.
// The hidden state of the filter is the link bandwidth and queuing delay
// buildup. The estimated state can be used to get the expected frame delay
// variation for a frame, given its frame size variation. This information can
// then be used to estimate the frame delay variation coming from network
// jitter.
// Mathematical details:
// * The state (`x` in Wikipedia notation) is a 2x1 vector comprising the
// reciprocal of link bandwidth [1 / bytes per ms] and the
// link queuing delay buildup [ms].
// * The state transition matrix (`F`) is the 2x2 identity matrix, meaning that
// link bandwidth and link queuing delay buildup are modeled as independent.
// * The measurement (`z`) is the (scalar) frame delay variation [ms].
// * The observation matrix (`H`) is a 1x2 vector set as
// `{frame_size_variation [bytes], 1.0}`.
// * The state estimate covariance (`P`) is a symmetric 2x2 matrix.
// * The process noise covariance (`Q`) is a constant 2x2 diagonal matrix
// [(1 / bytes per ms)^2, ms^2].
// * The observation noise covariance (`r`) is a scalar [ms^2] that is
// determined externally to this class.
class FrameDelayVariationKalmanFilter {
~FrameDelayVariationKalmanFilter() = default;
// Predicts and updates the filter, given a new pair of frame delay variation
// and frame size variation.
// Inputs:
// `frame_delay_variation_ms`:
// Frame delay variation as calculated by the `InterFrameDelay` estimator.
// `frame_size_variation_bytes`:
// Frame size variation, i.e., the current frame size minus the previous
// frame size (in bytes). Note that this quantity may be negative.
// `max_frame_size_bytes`:
// Filtered largest frame size received since the last reset.
// `var_noise`:
// Variance of the estimated random jitter.
// TODO( For now use doubles as input parameters as
// units defined in api/units have insufficient underlying precision for
// jitter estimation.
void PredictAndUpdate(double frame_delay_variation_ms,
double frame_size_variation_bytes,
double max_frame_size_bytes,
double var_noise);
// Given a frame size variation, returns the estimated frame delay variation
// explained by the link bandwidth alone.
double GetFrameDelayVariationEstimateSizeBased(
double frame_size_variation_bytes) const;
// Given a frame size variation, returns the estimated frame delay variation
// explained by both link bandwidth and link queuing delay buildup.
double GetFrameDelayVariationEstimateTotal(
double frame_size_variation_bytes) const;
// State estimate (bandwidth [1 / bytes per ms], queue buildup [ms]).
double estimate_[2];
double estimate_cov_[2][2]; // Estimate covariance.
// Process noise covariance. This is a diagonal matrix, so we only store the
// diagonal entries.
double process_noise_cov_diag_[2];
} // namespace webrtc