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_