tor-browser

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

TestDriftController.cpp (15576B)


      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 #include "DriftController.h"
      7 #include "gtest/gtest.h"
      8 
      9 using namespace mozilla;
     10 using TimeUnit = media::TimeUnit;
     11 
     12 // Advance the output by the specified duration, using a calculated input
     13 // packet duration that provides the specified buffering level.
     14 void AdvanceByOutputDuration(TimeUnit* aCurrentBuffered,
     15                             DriftController* aController,
     16                             TimeUnit aOutputDuration,
     17                             uint32_t aNextBufferedInputFrames) {
     18  uint32_t nominalSourceRate = aController->mSourceRate;
     19  uint32_t nominalTargetRate = aController->mTargetRate;
     20  uint32_t correctedRate = aController->GetCorrectedSourceRate();
     21  // Use a denominator to exactly track (1/nominalTargetRate)ths of
     22  // durations in seconds of input frames buffered in the resampler.
     23  *aCurrentBuffered = aCurrentBuffered->ToBase(
     24      static_cast<int64_t>(nominalSourceRate) * nominalTargetRate);
     25  // Buffered input frames to feed the output are removed first, so that the
     26  // number of input frames required can be calculated.  aCurrentBuffered may
     27  // temporarily become negative.
     28  *aCurrentBuffered -= aOutputDuration.ToBase(*aCurrentBuffered) *
     29                       correctedRate / nominalSourceRate;
     30  // Determine the input duration (aligned to input frames) that would provide
     31  // the specified buffering level when rounded down to the nearest input
     32  // frame.
     33  int64_t currentBufferedInputFrames =
     34      aCurrentBuffered->ToBase<TimeUnit::FloorPolicy>(nominalSourceRate)
     35          .ToTicksAtRate(nominalSourceRate);
     36  TimeUnit inputDuration(
     37      CheckedInt64(aNextBufferedInputFrames) - currentBufferedInputFrames,
     38      nominalSourceRate);
     39  EXPECT_GE(inputDuration.ToTicksAtRate(nominalSourceRate), 0);
     40  *aCurrentBuffered += inputDuration;
     41  // The buffer size is not used in the controller logic.
     42  uint32_t bufferSize = 0;
     43  aController->UpdateClock(inputDuration, aOutputDuration,
     44                           aNextBufferedInputFrames, bufferSize);
     45 }
     46 
     47 TEST(TestDriftController, Basic)
     48 {
     49  constexpr uint32_t buffered = 5 * 480;
     50  constexpr uint32_t bufferedLow = 3 * 480;
     51  constexpr uint32_t bufferedHigh = 7 * 480;
     52 
     53  TimeUnit currentBuffered(buffered, 48000);
     54  DriftController c(48000, 48000, currentBuffered);
     55  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000U);
     56 
     57  // The adjustment interval is 1s.
     58  const auto oneSec = media::TimeUnit(48000, 48000);
     59  uint32_t stepsPerSec = 50;
     60  media::TimeUnit stepDuration = oneSec / stepsPerSec;
     61 
     62  for (uint32_t i = 0; i < stepsPerSec; ++i) {
     63    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
     64  }
     65  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
     66 
     67  for (uint32_t i = 0; i < stepsPerSec; ++i) {
     68    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedLow);
     69  }
     70  EXPECT_EQ(c.GetCorrectedSourceRate(), 47957u);
     71 
     72  for (uint32_t i = 0; i < stepsPerSec; ++i) {
     73    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
     74  }
     75  EXPECT_EQ(c.GetCorrectedSourceRate(), 47957u);
     76 
     77  for (uint32_t i = 0; i < stepsPerSec; ++i) {
     78    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
     79  }
     80  EXPECT_EQ(c.GetCorrectedSourceRate(), 48005u);
     81 }
     82 
     83 TEST(TestDriftController, BasicResampler)
     84 {
     85  // This test is equivalent to Basic, but for the output sample rate, so
     86  // input buffer frame counts should be equal to those in Basic.
     87  constexpr uint32_t buffered = 5 * 480;
     88  constexpr uint32_t bufferedLow = 3 * 480;
     89  constexpr uint32_t bufferedHigh = 7 * 480;
     90 
     91  TimeUnit currentBuffered(buffered, 48000);
     92  DriftController c(48000, 24000, currentBuffered);
     93 
     94  // The adjustment interval is 1s.
     95  const auto oneSec = media::TimeUnit(48000, 48000);
     96  uint32_t stepsPerSec = 50;
     97  media::TimeUnit stepDuration = oneSec / stepsPerSec;
     98 
     99  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    100    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    101  }
    102  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    103 
    104  // low
    105  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    106    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedLow);
    107  }
    108  EXPECT_EQ(c.GetCorrectedSourceRate(), 47957u);
    109 
    110  // high
    111  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    112    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    113  }
    114  EXPECT_EQ(c.GetCorrectedSourceRate(), 47957u);
    115 
    116  // high
    117  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    118    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    119  }
    120  EXPECT_EQ(c.GetCorrectedSourceRate(), 48005u);
    121 }
    122 
    123 TEST(TestDriftController, BufferedInput)
    124 {
    125  constexpr uint32_t buffered = 5 * 480;
    126  constexpr uint32_t bufferedLow = 3 * 480;
    127  constexpr uint32_t bufferedHigh = 7 * 480;
    128 
    129  TimeUnit currentBuffered(buffered, 48000);
    130  DriftController c(48000, 48000, currentBuffered);
    131  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    132 
    133  // The adjustment interval is 1s.
    134  const auto oneSec = media::TimeUnit(48000, 48000);
    135  uint32_t stepsPerSec = 20;
    136  media::TimeUnit stepDuration = oneSec / stepsPerSec;
    137 
    138  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    139    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    140  }
    141  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    142 
    143  // 0 buffered when updating correction
    144  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    145    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, 0);
    146  }
    147  EXPECT_EQ(c.GetCorrectedSourceRate(), 47990u);
    148 
    149  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    150    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedLow);
    151  }
    152  EXPECT_EQ(c.GetCorrectedSourceRate(), 47971u);
    153 
    154  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    155    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    156  }
    157  EXPECT_EQ(c.GetCorrectedSourceRate(), 47960u);
    158 
    159  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    160    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    161  }
    162  // Hysteresis keeps the corrected rate the same.
    163  EXPECT_EQ(c.GetCorrectedSourceRate(), 47960u);
    164 }
    165 
    166 TEST(TestDriftController, BufferedInputWithResampling)
    167 {
    168  // This test is equivalent to BufferedInput, but for the output sample rate,
    169  // so input buffer frame counts should be equal to those in BufferedInput.
    170  constexpr uint32_t buffered = 5 * 480;
    171  constexpr uint32_t bufferedLow = 3 * 480;
    172  constexpr uint32_t bufferedHigh = 7 * 480;
    173 
    174  TimeUnit currentBuffered(buffered, 48000);
    175  DriftController c(48000, 24000, currentBuffered);
    176  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    177 
    178  // The adjustment interval is 1s.
    179  const auto oneSec = media::TimeUnit(24000, 24000);
    180  uint32_t stepsPerSec = 20;
    181  media::TimeUnit stepDuration = oneSec / stepsPerSec;
    182 
    183  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    184    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    185  }
    186  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    187 
    188  // 0 buffered when updating correction
    189  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    190    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, 0);
    191  }
    192  EXPECT_EQ(c.GetCorrectedSourceRate(), 47990u);
    193 
    194  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    195    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedLow);
    196  }
    197  EXPECT_EQ(c.GetCorrectedSourceRate(), 47971u);
    198 
    199  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    200    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    201  }
    202  EXPECT_EQ(c.GetCorrectedSourceRate(), 47960u);
    203 
    204  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    205    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    206  }
    207  // Hysteresis keeps the corrected rate the same.
    208  EXPECT_EQ(c.GetCorrectedSourceRate(), 47960u);
    209 }
    210 
    211 TEST(TestDriftController, SmallError)
    212 {
    213  constexpr uint32_t buffered = 5 * 480;
    214  constexpr uint32_t bufferedLow = buffered - 48;
    215  constexpr uint32_t bufferedHigh = buffered + 48;
    216 
    217  TimeUnit currentBuffered(buffered, 48000);
    218  DriftController c(48000, 48000, currentBuffered);
    219  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    220 
    221  // The adjustment interval is 1s.
    222  const auto oneSec = media::TimeUnit(48000, 48000);
    223  uint32_t stepsPerSec = 25;
    224  media::TimeUnit stepDuration = oneSec / stepsPerSec;
    225 
    226  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    227    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, buffered);
    228  }
    229  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    230 
    231  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    232    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedLow);
    233  }
    234  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    235 
    236  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    237    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    238  }
    239  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    240  for (uint32_t i = 0; i < stepsPerSec; ++i) {
    241    AdvanceByOutputDuration(&currentBuffered, &c, stepDuration, bufferedHigh);
    242  }
    243  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000u);
    244 }
    245 
    246 TEST(TestDriftController, SmallBufferedFrames)
    247 {
    248  constexpr uint32_t bufferedLow = 3 * 480;
    249 
    250  DriftController c(48000, 48000, media::TimeUnit::FromSeconds(0.05));
    251  media::TimeUnit oneSec = media::TimeUnit::FromSeconds(1);
    252  uint32_t stepsPerSec = 40;
    253  media::TimeUnit stepDuration = oneSec / stepsPerSec;
    254 
    255  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000U);
    256  for (uint32_t i = 0; i < stepsPerSec - 1; ++i) {
    257    c.UpdateClock(stepDuration, stepDuration, bufferedLow, 0);
    258  }
    259  EXPECT_EQ(c.GetCorrectedSourceRate(), 48000U);
    260  c.UpdateClock(stepDuration, stepDuration, bufferedLow, 0);
    261  EXPECT_EQ(c.GetCorrectedSourceRate(), 47996U);
    262 }
    263 
    264 TEST(TestDriftController, VerySmallBufferedFrames)
    265 {
    266  uint32_t bufferedLow = 1;
    267  uint32_t nominalRate = 48000;
    268 
    269  DriftController c(nominalRate, nominalRate, media::TimeUnit::FromSeconds(1));
    270  EXPECT_EQ(c.GetCorrectedSourceRate(), nominalRate);
    271 
    272  TimeUnit currentBuffered(bufferedLow, 48000);
    273  media::TimeUnit hundredMillis = media::TimeUnit(100, 1000);
    274  uint32_t previousCorrected = nominalRate;
    275  // Perform enough steps (1500 seconds) that the corrected rate can
    276  // get to its lower bound, without underflowing zero.
    277  for (uint32_t i = 0; i < 15000; ++i) {
    278    // The input packet size is reduced each iteration by as much as possible
    279    // without completely draining the buffer.
    280    AdvanceByOutputDuration(&currentBuffered, &c, hundredMillis, bufferedLow);
    281    uint32_t correctedRate = c.GetCorrectedSourceRate();
    282    EXPECT_LE(correctedRate, previousCorrected) << "for i=" << i;
    283    EXPECT_GT(correctedRate, 0u) << "for i=" << i;
    284    previousCorrected = correctedRate;
    285  }
    286  // Check that the corrected rate has reached, does not go beyond, and does
    287  // not bounce off its lower bound.
    288  EXPECT_EQ(previousCorrected, 1u);
    289  for (uint32_t i = 15000; i < 15010; ++i) {
    290    AdvanceByOutputDuration(&currentBuffered, &c, hundredMillis, bufferedLow);
    291    EXPECT_EQ(c.GetCorrectedSourceRate(), 1u) << "for i=" << i;
    292  }
    293 }
    294 
    295 TEST(TestDriftController, SmallStepResponse)
    296 {
    297  // The DriftController is configured with nominal source rate a little less
    298  // than the actual rate.
    299  uint32_t nominalTargetRate = 48000;
    300  uint32_t nominalSourceRate = 48000;
    301  uint32_t actualSourceRate = 48000 * 1001 / 1000;  // +0.1% drift
    302 
    303  TimeUnit desiredBuffered = TimeUnit::FromSeconds(0.05);  // 50 ms
    304  DriftController c(nominalSourceRate, nominalTargetRate, desiredBuffered);
    305  EXPECT_EQ(c.GetCorrectedSourceRate(), nominalSourceRate);
    306 
    307  uint32_t stepsPerSec = 25;
    308  // Initial buffer level == desired.  Choose a base to exactly track
    309  // fractions of frames buffered in the resampler.
    310  TimeUnit buffered = desiredBuffered.ToBase(nominalSourceRate * stepsPerSec);
    311  media::TimeUnit inputStepDuration(actualSourceRate,
    312                                    stepsPerSec * nominalSourceRate);
    313  media::TimeUnit outputStepDuration(nominalTargetRate,
    314                                     stepsPerSec * nominalTargetRate);
    315 
    316  // Perform enough steps to observe convergence.
    317  uint32_t iterationCount = 200 /*seconds*/ * stepsPerSec;
    318  for (uint32_t i = 0; i < iterationCount; ++i) {
    319    uint32_t correctedRate = c.GetCorrectedSourceRate();
    320    buffered += TimeUnit(CheckedInt64(actualSourceRate) - correctedRate,
    321                         stepsPerSec * nominalSourceRate);
    322    // The buffer size is not used in the controller logic.
    323    c.UpdateClock(inputStepDuration, outputStepDuration,
    324                  buffered.ToTicksAtRate(nominalSourceRate), 0);
    325    if (outputStepDuration * i > TimeUnit::FromSeconds(50) &&
    326        /* Corrections are performed only once per second. */
    327        i % stepsPerSec == 0) {
    328      EXPECT_EQ(c.GetCorrectedSourceRate(), actualSourceRate) << "for i=" << i;
    329      EXPECT_NEAR(buffered.ToTicksAtRate(nominalSourceRate),
    330                  desiredBuffered.ToTicksAtRate(nominalSourceRate), 10)
    331          << "for i=" << i;
    332    }
    333  }
    334 }
    335 
    336 TEST(TestDriftController, LargeStepResponse)
    337 {
    338  // The DriftController is configured with nominal source rate much less than
    339  // the actual rate.  The large difference between nominal and actual
    340  // produces large PID terms and capping of the change in resampler input
    341  // rate to nominalRate/1000.  This does not correspond exactly to an
    342  // expected use case, but tests the stability of the response when changes
    343  // are capped.
    344  uint32_t nominalTargetRate = 48000;
    345  uint32_t nominalSourceRate = 48000 * 7 / 8;
    346  uint32_t actualSourceRate = 48000;
    347 
    348  TimeUnit desiredBuffered(actualSourceRate * 10, nominalSourceRate);
    349  DriftController c(nominalSourceRate, nominalTargetRate, desiredBuffered);
    350  EXPECT_EQ(c.GetCorrectedSourceRate(), nominalSourceRate);
    351 
    352  uint32_t stepsPerSec = 20;
    353  // Initial buffer level == desired.  Choose a base to exactly track
    354  // fractions of frames buffered in the resampler.
    355  TimeUnit buffered = desiredBuffered.ToBase(nominalSourceRate * stepsPerSec);
    356  media::TimeUnit inputStepDuration(actualSourceRate,
    357                                    stepsPerSec * nominalSourceRate);
    358  media::TimeUnit outputStepDuration(nominalTargetRate,
    359                                     stepsPerSec * nominalTargetRate);
    360 
    361  // Changes in the corrected rate are limited to nominalRate/1000 per second.
    362  // Perform enough steps to get from nominal to actual source rate and then
    363  // observe convergence.
    364  uint32_t iterationCount = 8 * stepsPerSec * 1000 *
    365                            (actualSourceRate - nominalSourceRate) /
    366                            nominalSourceRate;
    367  EXPECT_GT(outputStepDuration * (iterationCount - 1),
    368            TimeUnit::FromSeconds(1020));
    369  for (uint32_t i = 0; i < iterationCount; ++i) {
    370    uint32_t correctedRate = c.GetCorrectedSourceRate();
    371    buffered += TimeUnit(CheckedInt64(actualSourceRate) - correctedRate,
    372                         stepsPerSec * nominalSourceRate);
    373    // The buffer size is not used in the controller logic.
    374    c.UpdateClock(inputStepDuration, outputStepDuration,
    375                  buffered.ToTicksAtRate(nominalSourceRate), 0);
    376    if (outputStepDuration * i > TimeUnit::FromSeconds(1020) &&
    377        /* Corrections are performed only once per second. */
    378        i % stepsPerSec == 0) {
    379      EXPECT_EQ(c.GetCorrectedSourceRate(), actualSourceRate) << "for i=" << i;
    380      EXPECT_NEAR(buffered.ToTicksAtRate(nominalSourceRate),
    381                  desiredBuffered.ToTicksAtRate(nominalSourceRate), 10)
    382          << "for i=" << i;
    383    }
    384  }
    385 }