summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/video_coding/timing/jitter_estimator.h
blob: 89dc64934b69dcc9092d08b7e1f945f1b3396bca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
 *  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_JITTER_ESTIMATOR_H_
#define MODULES_VIDEO_CODING_TIMING_JITTER_ESTIMATOR_H_

#include <algorithm>
#include <memory>
#include <queue>

#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "api/field_trials_view.h"
#include "api/units/data_size.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "modules/video_coding/timing/frame_delay_variation_kalman_filter.h"
#include "modules/video_coding/timing/rtt_filter.h"
#include "rtc_base/experiments/struct_parameters_parser.h"
#include "rtc_base/numerics/moving_percentile_filter.h"
#include "rtc_base/rolling_accumulator.h"

namespace webrtc {

class Clock;

class JitterEstimator {
 public:
  // Configuration struct for statically overriding some constants and
  // behaviour, configurable through field trials.
  struct Config {
    static constexpr char kFieldTrialsKey[] = "WebRTC-JitterEstimatorConfig";

    // Parses a field trial string and validates the values.
    static Config ParseAndValidate(absl::string_view field_trial);

    std::unique_ptr<StructParametersParser> Parser() {
      // clang-format off
      return StructParametersParser::Create(
          "avg_frame_size_median", &avg_frame_size_median,
          "max_frame_size_percentile", &max_frame_size_percentile,
          "frame_size_window", &frame_size_window,
          "num_stddev_delay_clamp", &num_stddev_delay_clamp,
          "num_stddev_delay_outlier", &num_stddev_delay_outlier,
          "num_stddev_size_outlier", &num_stddev_size_outlier,
          "congestion_rejection_factor", &congestion_rejection_factor,
          "estimate_noise_when_congested", &estimate_noise_when_congested);
      // clang-format on
    }

    bool MaxFrameSizePercentileEnabled() const {
      return max_frame_size_percentile.has_value();
    }

    // If true, the "avg" frame size is calculated as the median over a window
    // of recent frame sizes.
    bool avg_frame_size_median = false;

    // If set, the "max" frame size is calculated as this percentile over a
    // window of recent frame sizes.
    absl::optional<double> max_frame_size_percentile = absl::nullopt;

    // The length of the percentile filters' window, in number of frames.
    absl::optional<int> frame_size_window = absl::nullopt;

    // The incoming frame delay variation samples are clamped to be at most
    // this number of standard deviations away from zero.
    //
    // Increasing this value clamps fewer samples.
    absl::optional<double> num_stddev_delay_clamp = absl::nullopt;

    // A (relative) frame delay variation sample is an outlier if its absolute
    // deviation from the Kalman filter model falls outside this number of
    // sample standard deviations.
    //
    // Increasing this value rejects fewer samples.
    absl::optional<double> num_stddev_delay_outlier = absl::nullopt;

    // An (absolute) frame size sample is an outlier if its positive deviation
    // from the estimated average frame size falls outside this number of sample
    // standard deviations.
    //
    // Increasing this value rejects fewer samples.
    absl::optional<double> num_stddev_size_outlier = absl::nullopt;

    // A (relative) frame size variation sample is deemed "congested", and is
    // thus rejected, if its value is less than this factor times the estimated
    // max frame size.
    //
    // Decreasing this value rejects fewer samples.
    absl::optional<double> congestion_rejection_factor = absl::nullopt;

    // If true, the noise estimate will be updated for congestion rejected
    // frames. This is currently enabled by default, but that may not be optimal
    // since congested frames typically are not spread around the line with
    // Gaussian noise. (This is the whole reason for the congestion rejection!)
    bool estimate_noise_when_congested = true;
  };

  JitterEstimator(Clock* clock, const FieldTrialsView& field_trials);
  JitterEstimator(const JitterEstimator&) = delete;
  JitterEstimator& operator=(const JitterEstimator&) = delete;
  ~JitterEstimator();

  // Resets the estimate to the initial state.
  void Reset();

  // Updates the jitter estimate with the new data.
  //
  // Input:
  //          - frame_delay      : Delay-delta calculated by UTILDelayEstimate.
  //          - frame_size       : Frame size of the current frame.
  void UpdateEstimate(TimeDelta frame_delay, DataSize frame_size);

  // Returns the current jitter estimate and adds an RTT dependent term in cases
  // of retransmission.
  //  Input:
  //          - rtt_multiplier   : RTT param multiplier (when applicable).
  //          - rtt_mult_add_cap : Multiplier cap from the RTTMultExperiment.
  //
  // Return value              : Jitter estimate.
  TimeDelta GetJitterEstimate(double rtt_multiplier,
                              absl::optional<TimeDelta> rtt_mult_add_cap);

  // Updates the nack counter.
  void FrameNacked();

  // Updates the RTT filter.
  //
  // Input:
  //          - rtt          : Round trip time.
  void UpdateRtt(TimeDelta rtt);

  // Returns the configuration. Only to be used by unit tests.
  Config GetConfigForTest() const;

 private:
  // Updates the random jitter estimate, i.e. the variance of the time
  // deviations from the line given by the Kalman filter.
  //
  // Input:
  //          - d_dT              : The deviation from the kalman estimate.
  void EstimateRandomJitter(double d_dT);

  double NoiseThreshold() const;

  // Calculates the current jitter estimate.
  //
  // Return value                 : The current jitter estimate.
  TimeDelta CalculateEstimate();

  // Post process the calculated estimate.
  void PostProcessEstimate();

  // Returns the estimated incoming frame rate.
  Frequency GetFrameRate() const;

  // Configuration that may override some internals.
  const Config config_;

  // Filters the {frame_delay_delta, frame_size_delta} measurements through
  // a linear Kalman filter.
  FrameDelayVariationKalmanFilter kalman_filter_;

  // TODO(bugs.webrtc.org/14381): Update `avg_frame_size_bytes_` to DataSize
  // when api/units have sufficient precision.
  double avg_frame_size_bytes_;   // Average frame size
  double var_frame_size_bytes2_;  // Frame size variance. Unit is bytes^2.
  // Largest frame size received (descending with a factor kPsi).
  // Used by default.
  // TODO(bugs.webrtc.org/14381): Update `max_frame_size_bytes_` to DataSize
  // when api/units have sufficient precision.
  double max_frame_size_bytes_;
  // Percentile frame sized received (over a window). Only used if configured.
  MovingMedianFilter<int64_t> avg_frame_size_median_bytes_;
  MovingPercentileFilter<int64_t> max_frame_size_bytes_percentile_;
  // TODO(bugs.webrtc.org/14381): Update `startup_frame_size_sum_bytes_` to
  // DataSize when api/units have sufficient precision.
  double startup_frame_size_sum_bytes_;
  size_t startup_frame_size_count_;

  absl::optional<Timestamp> last_update_time_;
  // The previously returned jitter estimate
  absl::optional<TimeDelta> prev_estimate_;
  // Frame size of the previous frame
  absl::optional<DataSize> prev_frame_size_;
  // Average of the random jitter. Unit is milliseconds.
  double avg_noise_ms_;
  // Variance of the time-deviation from the line. Unit is milliseconds^2.
  double var_noise_ms2_;
  size_t alpha_count_;
  // The filtered sum of jitter estimates
  TimeDelta filter_jitter_estimate_ = TimeDelta::Zero();

  size_t startup_count_;
  // Time when the latest nack was seen
  Timestamp latest_nack_ = Timestamp::Zero();
  // Keeps track of the number of nacks received, but never goes above
  // kNackLimit.
  size_t nack_count_;
  RttFilter rtt_filter_;

  // Tracks frame rates in microseconds.
  rtc::RollingAccumulator<uint64_t> fps_counter_;
  Clock* clock_;
};

}  // namespace webrtc

#endif  // MODULES_VIDEO_CODING_TIMING_JITTER_ESTIMATOR_H_