tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DriftController.h (7110B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef DOM_MEDIA_DRIFTCONTROL_DRIFTCONTROLLER_H_
      7 #define DOM_MEDIA_DRIFTCONTROL_DRIFTCONTROLLER_H_
      8 
      9 #include <cstdint>
     10 
     11 #include "MediaSegment.h"
     12 #include "TimeUnits.h"
     13 #include "mozilla/RollingMean.h"
     14 
     15 namespace mozilla {
     16 
     17 /**
     18 * DriftController calculates the divergence of the source clock from its
     19 * nominal (provided) rate compared to that of the target clock, which drives
     20 * the calculations.
     21 *
     22 * The DriftController looks at how the current buffering level differs from the
     23 * desired buffering level and sets a corrected source rate. A resampler should
     24 * be configured to resample from the corrected source rate to the nominal
     25 * target rate. It assumes that the resampler is initially configured to
     26 * resample from the nominal source rate to the nominal target rate.
     27 *
     28 * The pref `media.clock drift.buffering` can be used to configure the minimum
     29 * initial desired internal buffering. Right now it is at 50ms. A larger desired
     30 * buffering level will be used if deemed necessary based on input device
     31 * latency, reported or observed. It will also be increased as a response to an
     32 * underrun, since that indicates the buffer was too small.
     33 */
     34 class DriftController final {
     35 public:
     36  /**
     37   * Provide the nominal source and the target sample rate.
     38   */
     39  DriftController(uint32_t aSourceRate, uint32_t aTargetRate,
     40                  media::TimeUnit aDesiredBuffering);
     41 
     42  /**
     43   * Set the buffering level that the controller should target.
     44   */
     45  void SetDesiredBuffering(media::TimeUnit aDesiredBuffering);
     46 
     47  /**
     48   * Reset internal state in a way that is suitable for handling an underrun.
     49   */
     50  void ResetAfterUnderrun();
     51 
     52  /**
     53   * Returns the drift-corrected source rate.
     54   */
     55  uint32_t GetCorrectedSourceRate() const;
     56 
     57  /**
     58   * The number of times mCorrectedSourceRate has been changed to adjust to
     59   * drift.
     60   */
     61  uint32_t NumCorrectionChanges() const { return mNumCorrectionChanges; }
     62 
     63  /**
     64   * The amount of time that the difference between the buffering level and
     65   * the desired value has been both less than 20% of the desired level and
     66   * less than 10ms of buffered frames.
     67   */
     68  media::TimeUnit DurationNearDesired() const { return mDurationNearDesired; }
     69 
     70  /**
     71   * The amount of time that has passed since the last time SetDesiredBuffering
     72   * was called.
     73   */
     74  media::TimeUnit DurationSinceDesiredBufferingChange() const {
     75    return mTotalTargetClock - mLastDesiredBufferingChangeTime;
     76  }
     77 
     78  /**
     79   * A rolling window average measurement of source latency by looking at the
     80   * duration of the source buffer.
     81   */
     82  media::TimeUnit MeasuredSourceLatency() const {
     83    return mMeasuredSourceLatency.mean();
     84  }
     85 
     86  /**
     87   * Update the available source frames, target frames, and the current
     88   * buffer, in every iteration. If the conditions are met a new correction is
     89   * calculated. A new correction is calculated every mAdjustmentInterval. In
     90   * addition to that, the correction is clamped so that the output sample rate
     91   * changes by at most 0.1% of its nominal rate each correction.
     92   */
     93  void UpdateClock(media::TimeUnit aSourceDuration,
     94                   media::TimeUnit aTargetDuration, uint32_t aBufferedFrames,
     95                   uint32_t aBufferSize);
     96 
     97 private:
     98  int64_t NearThreshold() const;
     99  // Adjust mCorrectedSourceRate for the current values of mDriftEstimate and
    100  // mAvgBufferedFramesEst - mDesiredBuffering.ToTicksAtRate(mSourceRate).
    101  //
    102  // mCorrectedSourceRate is not changed if it is not expected to cause an
    103  // overshoot during the next mAdjustmentInterval and is expected to bring
    104  // mAvgBufferedFramesEst to the desired level within 30s or is within
    105  // 1 frame/sec of a rate which would converge within 30s.
    106  //
    107  // Otherwise, mCorrectedSourceRate is set so as to aim to have
    108  // mAvgBufferedFramesEst converge to the desired value in 15s.
    109  // If the buffering level is higher than desired, then mCorrectedSourceRate
    110  // must be higher than expected from mDriftEstimate to consume input
    111  // data faster.
    112  //
    113  // Changes to mCorrectedSourceRate are capped at mSourceRate/1000 to avoid
    114  // rapid changes.
    115  void CalculateCorrection(uint32_t aBufferedFrames, uint32_t aBufferSize);
    116 
    117 public:
    118  const uint8_t mPlotId;
    119  const uint32_t mSourceRate;
    120  const uint32_t mTargetRate;
    121  const media::TimeUnit mAdjustmentInterval = media::TimeUnit::FromSeconds(1);
    122 
    123 private:
    124  media::TimeUnit mDesiredBuffering;
    125  float mCorrectedSourceRate;
    126  media::TimeUnit mDurationNearDesired;
    127  uint32_t mNumCorrectionChanges = 0;
    128  // Moving averages of input and output durations, used in a ratio to
    129  // estimate clock drift. Each average is calculated using packet durations
    130  // from the same time intervals (between output requests), with the same
    131  // weights, to support their use as a ratio.  Durations from many packets
    132  // are essentially summed (with consistent denominators) to provide
    133  // longish-term measures of clock advance.  These are independent of any
    134  // corrections in resampling ratio.
    135  double mInputDurationAvg = 0.0;
    136  double mOutputDurationAvg = 0.0;
    137  // Moving average of mInputDurationAvg/mOutputDurationAvg to smooth
    138  // out short-term deviations from an estimated longish-term drift rate.
    139  // Greater than 1 means the input clock has advanced faster than the output
    140  // clock.  This is the output of a second low pass filter stage.
    141  double mDriftEstimate = 1.0;
    142  // Output of the first low pass filter stage for mDriftEstimate
    143  double mStage1Drift = 1.0;
    144  // Estimate of the average buffering level after each output request, in
    145  // input frames (and fractions thereof), smoothed to reduce the effect of
    146  // short term variations.  This is adjusted for estimated clock drift and for
    147  // corrections in the resampling ratio.  This is the output of a second low
    148  // pass filter stage.
    149  double mAvgBufferedFramesEst = 0.0;
    150  // Output of the first low pass filter stage for mAvgBufferedFramesEst
    151  double mStage1Buffered = 0.0;
    152  // Whether handling an underrun, including waiting for the first input sample.
    153  bool mIsHandlingUnderrun = true;
    154  // An estimate of the source's latency, i.e. callback buffer size, in frames.
    155  // Like mInputDurationAvg, this measures the duration arriving between each
    156  // output request, but mMeasuredSourceLatency does not include zero
    157  // duration measurements.
    158  RollingMean<media::TimeUnit, media::TimeUnit> mMeasuredSourceLatency;
    159  // An estimate of the target's latency, i.e. callback buffer size, in frames.
    160  RollingMean<media::TimeUnit, media::TimeUnit> mMeasuredTargetLatency;
    161 
    162  media::TimeUnit mTargetClock;
    163  media::TimeUnit mTotalTargetClock;
    164  media::TimeUnit mTargetClockAfterLastSourcePacket;
    165  media::TimeUnit mLastDesiredBufferingChangeTime;
    166 };
    167 
    168 }  // namespace mozilla
    169 #endif  // DOM_MEDIA_DRIFTCONTROL_DRIFTCONTROLLER_H_