tor-browser

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

TestDynamicResampler.cpp (23173B)


      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 "DynamicResampler.h"
      7 #include "gtest/gtest.h"
      8 
      9 using namespace mozilla;
     10 
     11 TEST(TestDynamicResampler, SameRates_Float1)
     12 {
     13  const uint32_t in_frames = 100;
     14  const uint32_t out_frames = 100;
     15  uint32_t channels = 2;
     16  uint32_t in_rate = 44100;
     17  uint32_t out_rate = 44100;
     18 
     19  DynamicResampler dr(in_rate, out_rate);
     20  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
     21  EXPECT_EQ(dr.GetInRate(), in_rate);
     22  EXPECT_EQ(dr.GetChannels(), channels);
     23 
     24  // float in_ch1[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
     25  // float in_ch2[] = {.1, .2, .3, .4, .5, .6, .7, .8, .9, 1.0};
     26  float in_ch1[in_frames] = {};
     27  float in_ch2[in_frames] = {};
     28  AutoTArray<const float*, 2> in_buffer;
     29  in_buffer.AppendElements(channels);
     30  in_buffer[0] = in_ch1;
     31  in_buffer[1] = in_ch2;
     32 
     33  float out_ch1[out_frames] = {};
     34  float out_ch2[out_frames] = {};
     35 
     36  // Warm up with zeros
     37  dr.AppendInput(in_buffer, in_frames);
     38  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
     39  EXPECT_FALSE(hasUnderrun);
     40  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
     41  EXPECT_FALSE(hasUnderrun);
     42  for (uint32_t i = 0; i < out_frames; ++i) {
     43    EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
     44    EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
     45  }
     46 
     47  // Continue with non zero
     48  for (uint32_t i = 0; i < in_frames; ++i) {
     49    in_ch1[i] = in_ch2[i] = 0.01f * i;
     50  }
     51  dr.AppendInput(in_buffer, in_frames);
     52  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
     53  EXPECT_FALSE(hasUnderrun);
     54  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
     55  EXPECT_FALSE(hasUnderrun);
     56  for (uint32_t i = 0; i < out_frames; ++i) {
     57    EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
     58    EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
     59  }
     60 
     61  // No more frames in the input buffer
     62  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
     63  EXPECT_TRUE(hasUnderrun);
     64  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
     65  EXPECT_TRUE(hasUnderrun);
     66 }
     67 
     68 TEST(TestDynamicResampler, SameRates_Short1)
     69 {
     70  uint32_t in_frames = 2;
     71  uint32_t out_frames = 2;
     72  uint32_t channels = 2;
     73  uint32_t in_rate = 44100;
     74  uint32_t out_rate = 44100;
     75 
     76  DynamicResampler dr(in_rate, out_rate);
     77  dr.SetSampleFormat(AUDIO_FORMAT_S16);
     78  EXPECT_EQ(dr.GetInRate(), in_rate);
     79  EXPECT_EQ(dr.GetChannels(), channels);
     80 
     81  short in_ch1[] = {1, 2, 3};
     82  short in_ch2[] = {4, 5, 6};
     83  AutoTArray<const short*, 2> in_buffer;
     84  in_buffer.AppendElements(channels);
     85  in_buffer[0] = in_ch1;
     86  in_buffer[1] = in_ch2;
     87 
     88  short out_ch1[3] = {};
     89  short out_ch2[3] = {};
     90 
     91  dr.AppendInput(in_buffer, in_frames);
     92  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
     93  EXPECT_FALSE(hasUnderrun);
     94  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
     95  EXPECT_FALSE(hasUnderrun);
     96  for (uint32_t i = 0; i < out_frames; ++i) {
     97    EXPECT_EQ(in_ch1[i], out_ch1[i]);
     98    EXPECT_EQ(in_ch2[i], out_ch2[i]);
     99  }
    100 
    101  // No more frames in the input buffer
    102  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    103  EXPECT_TRUE(hasUnderrun);
    104  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    105  EXPECT_TRUE(hasUnderrun);
    106 }
    107 
    108 TEST(TestDynamicResampler, SameRates_Float2)
    109 {
    110  uint32_t in_frames = 3;
    111  uint32_t out_frames = 2;
    112  uint32_t channels = 2;
    113  uint32_t in_rate = 44100;
    114  uint32_t out_rate = 44100;
    115 
    116  DynamicResampler dr(in_rate, out_rate);
    117  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    118 
    119  float in_ch1[] = {0.1, 0.2, 0.3};
    120  float in_ch2[] = {0.4, 0.5, 0.6};
    121  AutoTArray<const float*, 2> in_buffer;
    122  in_buffer.AppendElements(channels);
    123  in_buffer[0] = in_ch1;
    124  in_buffer[1] = in_ch2;
    125 
    126  float out_ch1[3] = {};
    127  float out_ch2[3] = {};
    128 
    129  dr.AppendInput(in_buffer, in_frames);
    130  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    131  EXPECT_FALSE(hasUnderrun);
    132  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    133  EXPECT_FALSE(hasUnderrun);
    134  for (uint32_t i = 0; i < out_frames; ++i) {
    135    EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
    136    EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
    137  }
    138 
    139  out_frames = 1;
    140  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    141  EXPECT_FALSE(hasUnderrun);
    142  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    143  EXPECT_FALSE(hasUnderrun);
    144  for (uint32_t i = 0; i < out_frames; ++i) {
    145    EXPECT_FLOAT_EQ(in_ch1[i + 2], out_ch1[i]);
    146    EXPECT_FLOAT_EQ(in_ch2[i + 2], out_ch2[i]);
    147  }
    148 
    149  // No more frames, the input buffer has drained
    150  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    151  EXPECT_TRUE(hasUnderrun);
    152  dr.Resample(out_ch2, out_frames, 1);
    153  EXPECT_TRUE(hasUnderrun);
    154 }
    155 
    156 TEST(TestDynamicResampler, SameRates_Short2)
    157 {
    158  uint32_t in_frames = 3;
    159  uint32_t out_frames = 2;
    160  uint32_t channels = 2;
    161  uint32_t in_rate = 44100;
    162  uint32_t out_rate = 44100;
    163 
    164  DynamicResampler dr(in_rate, out_rate);
    165  dr.SetSampleFormat(AUDIO_FORMAT_S16);
    166 
    167  short in_ch1[] = {1, 2, 3};
    168  short in_ch2[] = {4, 5, 6};
    169  AutoTArray<const short*, 2> in_buffer;
    170  in_buffer.AppendElements(channels);
    171  in_buffer[0] = in_ch1;
    172  in_buffer[1] = in_ch2;
    173 
    174  short out_ch1[3] = {};
    175  short out_ch2[3] = {};
    176 
    177  dr.AppendInput(in_buffer, in_frames);
    178  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    179  EXPECT_FALSE(hasUnderrun);
    180  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    181  EXPECT_FALSE(hasUnderrun);
    182  for (uint32_t i = 0; i < out_frames; ++i) {
    183    EXPECT_EQ(in_ch1[i], out_ch1[i]);
    184    EXPECT_EQ(in_ch2[i], out_ch2[i]);
    185  }
    186 
    187  out_frames = 1;
    188  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    189  EXPECT_FALSE(hasUnderrun);
    190  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    191  EXPECT_FALSE(hasUnderrun);
    192  for (uint32_t i = 0; i < out_frames; ++i) {
    193    EXPECT_EQ(in_ch1[i + 2], out_ch1[i]);
    194    EXPECT_EQ(in_ch2[i + 2], out_ch2[i]);
    195  }
    196 
    197  // No more frames, the input buffer has drained
    198  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    199  EXPECT_TRUE(hasUnderrun);
    200  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    201  EXPECT_TRUE(hasUnderrun);
    202 }
    203 
    204 TEST(TestDynamicResampler, SameRates_Float3)
    205 {
    206  uint32_t in_frames = 2;
    207  uint32_t out_frames = 3;
    208  uint32_t channels = 2;
    209  uint32_t in_rate = 44100;
    210  uint32_t out_rate = 44100;
    211 
    212  DynamicResampler dr(in_rate, out_rate);
    213  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    214 
    215  float in_ch1[] = {0.1, 0.2, 0.3};
    216  float in_ch2[] = {0.4, 0.5, 0.6};
    217  AutoTArray<const float*, 2> in_buffer;
    218  in_buffer.AppendElements(channels);
    219  in_buffer[0] = in_ch1;
    220  in_buffer[1] = in_ch2;
    221 
    222  float out_ch1[3] = {};
    223  float out_ch2[3] = {};
    224 
    225  // Not enough frames in the input buffer
    226  dr.AppendInput(in_buffer, in_frames);
    227  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    228  EXPECT_TRUE(hasUnderrun);
    229  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    230  EXPECT_TRUE(hasUnderrun);
    231 
    232  // Add one frame
    233  in_buffer[0] = in_ch1 + 2;
    234  in_buffer[1] = in_ch2 + 2;
    235  dr.AppendInput(in_buffer, 1);
    236  out_frames = 1;
    237  hasUnderrun = dr.Resample(out_ch1 + 2, out_frames, 0);
    238  EXPECT_FALSE(hasUnderrun);
    239  hasUnderrun = dr.Resample(out_ch2 + 2, out_frames, 1);
    240  EXPECT_FALSE(hasUnderrun);
    241  for (uint32_t i = 0; i < 3; ++i) {
    242    EXPECT_FLOAT_EQ(in_ch1[i], out_ch1[i]);
    243    EXPECT_FLOAT_EQ(in_ch2[i], out_ch2[i]);
    244  }
    245 }
    246 
    247 TEST(TestDynamicResampler, SameRates_Short3)
    248 {
    249  uint32_t in_frames = 2;
    250  uint32_t out_frames = 3;
    251  uint32_t channels = 2;
    252  uint32_t in_rate = 44100;
    253  uint32_t out_rate = 44100;
    254 
    255  DynamicResampler dr(in_rate, out_rate);
    256  dr.SetSampleFormat(AUDIO_FORMAT_S16);
    257 
    258  short in_ch1[] = {1, 2, 3};
    259  short in_ch2[] = {4, 5, 6};
    260  AutoTArray<const short*, 2> in_buffer;
    261  in_buffer.AppendElements(channels);
    262  in_buffer[0] = in_ch1;
    263  in_buffer[1] = in_ch2;
    264 
    265  short out_ch1[3] = {};
    266  short out_ch2[3] = {};
    267 
    268  // Not enough frames in the input buffer
    269  dr.AppendInput(in_buffer, in_frames);
    270  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    271  EXPECT_TRUE(hasUnderrun);
    272  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    273  EXPECT_TRUE(hasUnderrun);
    274 
    275  // Add one frame
    276  in_buffer[0] = in_ch1 + 2;
    277  in_buffer[1] = in_ch2 + 2;
    278  dr.AppendInput(in_buffer, 1);
    279  out_frames = 1;
    280  hasUnderrun = dr.Resample(out_ch1 + 2, out_frames, 0);
    281  EXPECT_FALSE(hasUnderrun);
    282  hasUnderrun = dr.Resample(out_ch2 + 2, out_frames, 1);
    283  EXPECT_FALSE(hasUnderrun);
    284  for (uint32_t i = 0; i < 3; ++i) {
    285    EXPECT_EQ(in_ch1[i], out_ch1[i]);
    286    EXPECT_EQ(in_ch2[i], out_ch2[i]);
    287  }
    288 }
    289 
    290 TEST(TestDynamicResampler, UpdateOutRate_Float)
    291 {
    292  uint32_t in_frames = 10;
    293  uint32_t out_frames = 40;
    294  uint32_t channels = 2;
    295  uint32_t in_rate = 24000;
    296  uint32_t out_rate = 48000;
    297 
    298  uint32_t pre_buffer = 20;
    299 
    300  DynamicResampler dr(in_rate, out_rate);
    301  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    302  EXPECT_EQ(dr.GetInRate(), in_rate);
    303  EXPECT_EQ(dr.GetChannels(), channels);
    304 
    305  float in_ch1[10] = {};
    306  float in_ch2[10] = {};
    307  for (uint32_t i = 0; i < in_frames; ++i) {
    308    in_ch1[i] = in_ch2[i] = 0.01f * i;
    309  }
    310  AutoTArray<const float*, 2> in_buffer;
    311  in_buffer.AppendElements(channels);
    312  in_buffer[0] = in_ch1;
    313  in_buffer[1] = in_ch2;
    314 
    315  float out_ch1[40] = {};
    316  float out_ch2[40] = {};
    317 
    318  dr.AppendInputSilence(pre_buffer - in_frames);
    319  dr.AppendInput(in_buffer, in_frames);
    320  out_frames = 20u;
    321  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    322  EXPECT_FALSE(hasUnderrun);
    323  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    324  EXPECT_FALSE(hasUnderrun);
    325  for (uint32_t i = 0; i < out_frames; ++i) {
    326    // Half the input pre-buffer (10) is silence, and half the output (20).
    327    EXPECT_FLOAT_EQ(out_ch1[i], 0.0);
    328    EXPECT_FLOAT_EQ(out_ch2[i], 0.0);
    329  }
    330 
    331  // Update in rate
    332  in_rate = 26122;
    333  dr.UpdateResampler(in_rate, channels);
    334  EXPECT_EQ(dr.GetInRate(), in_rate);
    335  EXPECT_EQ(dr.GetChannels(), channels);
    336  out_frames = in_frames * out_rate / in_rate;
    337  EXPECT_EQ(out_frames, 18u);
    338  // Even if we provide no input if we have enough buffered input, we can create
    339  // output
    340  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    341  EXPECT_FALSE(hasUnderrun);
    342  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    343  EXPECT_FALSE(hasUnderrun);
    344 }
    345 
    346 TEST(TestDynamicResampler, UpdateOutRate_Short)
    347 {
    348  uint32_t in_frames = 10;
    349  uint32_t out_frames = 40;
    350  uint32_t channels = 2;
    351  uint32_t in_rate = 24000;
    352  uint32_t out_rate = 48000;
    353 
    354  uint32_t pre_buffer = 20;
    355 
    356  DynamicResampler dr(in_rate, out_rate);
    357  dr.SetSampleFormat(AUDIO_FORMAT_S16);
    358  EXPECT_EQ(dr.GetInRate(), in_rate);
    359  EXPECT_EQ(dr.GetChannels(), channels);
    360 
    361  short in_ch1[10] = {};
    362  short in_ch2[10] = {};
    363  for (uint32_t i = 0; i < in_frames; ++i) {
    364    in_ch1[i] = in_ch2[i] = i;
    365  }
    366  AutoTArray<const short*, 2> in_buffer;
    367  in_buffer.AppendElements(channels);
    368  in_buffer[0] = in_ch1;
    369  in_buffer[1] = in_ch2;
    370 
    371  short out_ch1[40] = {};
    372  short out_ch2[40] = {};
    373 
    374  dr.AppendInputSilence(pre_buffer - in_frames);
    375  dr.AppendInput(in_buffer, in_frames);
    376  out_frames = 20u;
    377  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    378  EXPECT_FALSE(hasUnderrun);
    379  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    380  EXPECT_FALSE(hasUnderrun);
    381  for (uint32_t i = 0; i < out_frames; ++i) {
    382    // Half the input pre-buffer (10) is silence, and half the output (20).
    383    EXPECT_EQ(out_ch1[i], 0.0);
    384    EXPECT_EQ(out_ch2[i], 0.0);
    385  }
    386 
    387  // Update in rate
    388  in_rate = 26122;
    389  dr.UpdateResampler(in_rate, channels);
    390  EXPECT_EQ(dr.GetInRate(), in_rate);
    391  EXPECT_EQ(dr.GetChannels(), channels);
    392  out_frames = in_frames * out_rate / in_rate;
    393  EXPECT_EQ(out_frames, 18u);
    394  // Even if we provide no input if we have enough buffered input, we can create
    395  // output
    396  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    397  EXPECT_FALSE(hasUnderrun);
    398  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    399  EXPECT_FALSE(hasUnderrun);
    400 }
    401 
    402 TEST(TestDynamicResampler, BigRangeInRates_Float)
    403 {
    404  uint32_t in_frames = 10;
    405  uint32_t out_frames = 10;
    406  uint32_t channels = 2;
    407  uint32_t in_rate = 44100;
    408  uint32_t out_rate = 44100;
    409 
    410  DynamicResampler dr(in_rate, out_rate);
    411  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    412 
    413  const uint32_t in_capacity = 40;
    414  float in_ch1[in_capacity] = {};
    415  float in_ch2[in_capacity] = {};
    416  for (uint32_t i = 0; i < in_capacity; ++i) {
    417    in_ch1[i] = in_ch2[i] = 0.01f * i;
    418  }
    419  AutoTArray<const float*, 2> in_buffer;
    420  in_buffer.AppendElements(channels);
    421  in_buffer[0] = in_ch1;
    422  in_buffer[1] = in_ch2;
    423 
    424  const uint32_t out_capacity = 1000;
    425  float out_ch1[out_capacity] = {};
    426  float out_ch2[out_capacity] = {};
    427 
    428  // Downsampling at a high enough ratio happens to have enough excess
    429  // in_frames from rounding in the out_frames calculation to cover the
    430  // skipped input latency when switching from zero-latency 44100->44100 to a
    431  // non-1:1 ratio.
    432  for (uint32_t rate = 100000; rate >= 10000; rate -= 2) {
    433    in_rate = rate;
    434    dr.UpdateResampler(in_rate, channels);
    435    EXPECT_EQ(dr.GetInRate(), in_rate);
    436    EXPECT_EQ(dr.GetChannels(), channels);
    437    in_frames = 20;  // more than we need
    438    out_frames = in_frames * out_rate / in_rate;
    439    for (uint32_t y = 0; y < 2; ++y) {
    440      dr.AppendInput(in_buffer, in_frames);
    441      bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    442      EXPECT_FALSE(hasUnderrun);
    443      hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    444      EXPECT_FALSE(hasUnderrun);
    445    }
    446  }
    447 }
    448 
    449 TEST(TestDynamicResampler, DownsamplingToCopying)
    450 {
    451  uint32_t channel_count = 1;
    452  // Start with downsampling
    453  uint32_t in_rate = 48001;
    454  uint32_t out_rate = 48000;
    455 
    456  DynamicResampler dr(in_rate, out_rate);
    457  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    458  dr.UpdateResampler(in_rate, channel_count);
    459 
    460  const uint32_t in_frame_count = 100;
    461  float in_frames[in_frame_count];
    462  float increment = 1.f / in_frame_count;
    463  for (uint32_t i = 0; i < in_frame_count; ++i) {
    464    in_frames[i] = static_cast<float>(i) * increment;
    465  }
    466  const float* in_channels[] = {in_frames};
    467  dr.AppendInput(in_channels, in_frame_count);
    468 
    469  const uint32_t block_size = 30;
    470  const uint32_t out_frame_count = 2 * block_size;
    471  float out_frames[out_frame_count];
    472  bool hasUnderrun = dr.Resample(out_frames, block_size, 0);
    473  EXPECT_FALSE(hasUnderrun);
    474  // Use out_rate for the input rate so that the DynamicResampler switches
    475  // from resampling to copying of frames.
    476  dr.UpdateResampler(out_rate, channel_count);
    477  hasUnderrun = dr.Resample(out_frames + block_size, block_size, 0);
    478  EXPECT_FALSE(hasUnderrun);
    479 
    480  // The abrupt change in slope from zero to increment is resampled to some
    481  // oscillations around the point of change.
    482  constexpr float tolerance = 0.1f;
    483  bool latencyHasPassed = false;
    484  EXPECT_NEAR(out_frames[0], 0.f, tolerance);
    485  for (uint32_t i = 1; i < out_frame_count; ++i) {
    486    if (!latencyHasPassed) {
    487      // Before the latency passes, samples may be approximately zero.
    488      EXPECT_GT(out_frames[i], -tolerance) << "for i=" << i;
    489      if (out_frames[i] > tolerance) {
    490        latencyHasPassed = true;
    491        EXPECT_LT(out_frames[i], increment + tolerance) << "for i=" << i;
    492      }
    493      continue;
    494    }
    495    EXPECT_NEAR(out_frames[i], out_frames[i - 1] + increment, tolerance);
    496  }
    497 }
    498 
    499 TEST(TestDynamicResampler, BigRangeInRates_Short)
    500 {
    501  uint32_t in_frames = 10;
    502  uint32_t out_frames = 10;
    503  uint32_t channels = 2;
    504  uint32_t in_rate = 44100;
    505  uint32_t out_rate = 44100;
    506 
    507  DynamicResampler dr(in_rate, out_rate);
    508  dr.SetSampleFormat(AUDIO_FORMAT_S16);
    509 
    510  const uint32_t in_capacity = 40;
    511  short in_ch1[in_capacity] = {};
    512  short in_ch2[in_capacity] = {};
    513  for (uint32_t i = 0; i < in_capacity; ++i) {
    514    in_ch1[i] = in_ch2[i] = i;
    515  }
    516  AutoTArray<const short*, 2> in_buffer;
    517  in_buffer.AppendElements(channels);
    518  in_buffer[0] = in_ch1;
    519  in_buffer[1] = in_ch2;
    520 
    521  const uint32_t out_capacity = 1000;
    522  short out_ch1[out_capacity] = {};
    523  short out_ch2[out_capacity] = {};
    524 
    525  for (uint32_t rate = 100000; rate >= 10000; rate -= 2) {
    526    in_rate = rate;
    527    dr.UpdateResampler(in_rate, channels);
    528    in_frames = 20;  // more than we need
    529    out_frames = in_frames * out_rate / in_rate;
    530    for (uint32_t y = 0; y < 2; ++y) {
    531      dr.AppendInput(in_buffer, in_frames);
    532      bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    533      EXPECT_FALSE(hasUnderrun);
    534      hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    535      EXPECT_FALSE(hasUnderrun);
    536    }
    537  }
    538 }
    539 
    540 TEST(TestDynamicResampler, UpdateChannels_Float)
    541 {
    542  uint32_t in_frames = 10;
    543  uint32_t out_frames = 10;
    544  uint32_t channels = 2;
    545  uint32_t in_rate = 44100;
    546  uint32_t out_rate = 48000;
    547 
    548  DynamicResampler dr(in_rate, out_rate);
    549  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    550 
    551  float in_ch1[10] = {};
    552  float in_ch2[10] = {};
    553  for (uint32_t i = 0; i < in_frames; ++i) {
    554    in_ch1[i] = in_ch2[i] = 0.01f * i;
    555  }
    556  AutoTArray<const float*, 2> in_buffer;
    557  in_buffer.AppendElements(channels);
    558  in_buffer[0] = in_ch1;
    559  in_buffer[1] = in_ch2;
    560 
    561  float out_ch1[10] = {};
    562  float out_ch2[10] = {};
    563 
    564  dr.AppendInput(in_buffer, in_frames);
    565  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    566  EXPECT_FALSE(hasUnderrun);
    567  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    568  EXPECT_FALSE(hasUnderrun);
    569 
    570  // Add 3rd channel
    571  dr.UpdateResampler(in_rate, 3);
    572  EXPECT_EQ(dr.GetInRate(), in_rate);
    573  EXPECT_EQ(dr.GetChannels(), 3u);
    574 
    575  float in_ch3[10] = {};
    576  for (uint32_t i = 0; i < in_frames; ++i) {
    577    in_ch3[i] = 0.01f * i;
    578  }
    579  in_buffer.AppendElement();
    580  in_buffer[2] = in_ch3;
    581  float out_ch3[10] = {};
    582 
    583  dr.AppendInput(in_buffer, in_frames);
    584 
    585  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    586  EXPECT_FALSE(hasUnderrun);
    587  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    588  EXPECT_FALSE(hasUnderrun);
    589  hasUnderrun = dr.Resample(out_ch3, out_frames, 2);
    590  EXPECT_FALSE(hasUnderrun);
    591 
    592  float in_ch4[10] = {};
    593  for (uint32_t i = 0; i < in_frames; ++i) {
    594    in_ch3[i] = 0.01f * i;
    595  }
    596  in_buffer.AppendElement();
    597  in_buffer[3] = in_ch4;
    598  float out_ch4[10] = {};
    599 
    600  dr.UpdateResampler(in_rate, 4);
    601  EXPECT_EQ(dr.GetInRate(), in_rate);
    602  EXPECT_EQ(dr.GetChannels(), 4u);
    603  dr.AppendInput(in_buffer, in_frames);
    604 
    605  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    606  EXPECT_FALSE(hasUnderrun);
    607  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    608  EXPECT_FALSE(hasUnderrun);
    609  hasUnderrun = dr.Resample(out_ch3, out_frames, 2);
    610  EXPECT_FALSE(hasUnderrun);
    611  hasUnderrun = dr.Resample(out_ch4, out_frames, 3);
    612  EXPECT_FALSE(hasUnderrun);
    613 }
    614 
    615 TEST(TestDynamicResampler, UpdateChannels_Short)
    616 {
    617  uint32_t in_frames = 10;
    618  uint32_t out_frames = 10;
    619  uint32_t channels = 2;
    620  uint32_t in_rate = 44100;
    621  uint32_t out_rate = 48000;
    622 
    623  DynamicResampler dr(in_rate, out_rate);
    624  dr.SetSampleFormat(AUDIO_FORMAT_S16);
    625 
    626  short in_ch1[10] = {};
    627  short in_ch2[10] = {};
    628  for (uint32_t i = 0; i < in_frames; ++i) {
    629    in_ch1[i] = in_ch2[i] = i;
    630  }
    631  AutoTArray<const short*, 2> in_buffer;
    632  in_buffer.AppendElements(channels);
    633  in_buffer[0] = in_ch1;
    634  in_buffer[1] = in_ch2;
    635 
    636  short out_ch1[10] = {};
    637  short out_ch2[10] = {};
    638 
    639  dr.AppendInput(in_buffer, in_frames);
    640  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    641  EXPECT_FALSE(hasUnderrun);
    642  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    643  EXPECT_FALSE(hasUnderrun);
    644 
    645  // Add 3rd channel
    646  dr.UpdateResampler(in_rate, 3);
    647  EXPECT_EQ(dr.GetInRate(), in_rate);
    648  EXPECT_EQ(dr.GetChannels(), 3u);
    649 
    650  short in_ch3[10] = {};
    651  for (uint32_t i = 0; i < in_frames; ++i) {
    652    in_ch3[i] = i;
    653  }
    654  in_buffer.AppendElement();
    655  in_buffer[2] = in_ch3;
    656  short out_ch3[10] = {};
    657 
    658  dr.AppendInput(in_buffer, in_frames);
    659 
    660  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    661  EXPECT_FALSE(hasUnderrun);
    662  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    663  EXPECT_FALSE(hasUnderrun);
    664  hasUnderrun = dr.Resample(out_ch3, out_frames, 2);
    665  EXPECT_FALSE(hasUnderrun);
    666 
    667  // Check update with AudioSegment
    668  short in_ch4[10] = {};
    669  for (uint32_t i = 0; i < in_frames; ++i) {
    670    in_ch3[i] = i;
    671  }
    672  in_buffer.AppendElement();
    673  in_buffer[3] = in_ch4;
    674  short out_ch4[10] = {};
    675 
    676  dr.UpdateResampler(in_rate, 4);
    677  EXPECT_EQ(dr.GetInRate(), in_rate);
    678  EXPECT_EQ(dr.GetChannels(), 4u);
    679  dr.AppendInput(in_buffer, in_frames);
    680 
    681  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    682  EXPECT_FALSE(hasUnderrun);
    683  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    684  EXPECT_FALSE(hasUnderrun);
    685  hasUnderrun = dr.Resample(out_ch3, out_frames, 2);
    686  EXPECT_FALSE(hasUnderrun);
    687  hasUnderrun = dr.Resample(out_ch4, out_frames, 3);
    688  EXPECT_FALSE(hasUnderrun);
    689 }
    690 
    691 TEST(TestDynamicResampler, Underrun)
    692 {
    693  const uint32_t in_frames = 100;
    694  const uint32_t out_frames = 200;
    695  uint32_t channels = 2;
    696  uint32_t in_rate = 48000;
    697  uint32_t out_rate = 48000;
    698 
    699  DynamicResampler dr(in_rate, out_rate);
    700  dr.SetSampleFormat(AUDIO_FORMAT_FLOAT32);
    701  EXPECT_EQ(dr.GetInRate(), in_rate);
    702  EXPECT_EQ(dr.GetChannels(), channels);
    703 
    704  float in_ch1[in_frames] = {};
    705  float in_ch2[in_frames] = {};
    706  AutoTArray<const float*, 2> in_buffer;
    707  in_buffer.AppendElements(channels);
    708  in_buffer[0] = in_ch1;
    709  in_buffer[1] = in_ch2;
    710 
    711  float out_ch1[out_frames] = {};
    712  float out_ch2[out_frames] = {};
    713 
    714  for (uint32_t i = 0; i < in_frames; ++i) {
    715    in_ch1[i] = 0.01f * i;
    716    in_ch2[i] = -0.01f * i;
    717  }
    718  dr.AppendInput(in_buffer, in_frames);
    719  bool hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    720  EXPECT_TRUE(hasUnderrun);
    721  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    722  EXPECT_TRUE(hasUnderrun);
    723  for (uint32_t i = 0; i < in_frames; ++i) {
    724    EXPECT_EQ(out_ch1[i], in_ch1[i]);
    725    EXPECT_EQ(out_ch2[i], in_ch2[i]);
    726  }
    727  for (uint32_t i = in_frames; i < out_frames; ++i) {
    728    EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i;
    729    EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i;
    730  }
    731 
    732  // No more frames in the input buffer
    733  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    734  EXPECT_TRUE(hasUnderrun);
    735  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    736  EXPECT_TRUE(hasUnderrun);
    737  for (uint32_t i = 0; i < out_frames; ++i) {
    738    EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i;
    739    EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i;
    740  }
    741 
    742  // Now try with resampling.
    743  dr.UpdateResampler(in_rate * 2, channels);
    744  dr.AppendInput(in_buffer, in_frames);
    745  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    746  EXPECT_TRUE(hasUnderrun);
    747  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    748  EXPECT_TRUE(hasUnderrun);
    749  // There is some buffering in the resampler, which is why the below is not
    750  // exact.
    751  for (uint32_t i = 0; i < 50; ++i) {
    752    EXPECT_GT(out_ch1[i], 0.0f) << "for i=" << i;
    753    EXPECT_LT(out_ch2[i], 0.0f) << "for i=" << i;
    754  }
    755  for (uint32_t i = 50; i < 54; ++i) {
    756    EXPECT_NE(out_ch1[i], 0.0f) << "for i=" << i;
    757    EXPECT_NE(out_ch2[i], 0.0f) << "for i=" << i;
    758  }
    759  for (uint32_t i = 54; i < out_frames; ++i) {
    760    EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i;
    761    EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i;
    762  }
    763 
    764  // No more frames in the input buffer
    765  hasUnderrun = dr.Resample(out_ch1, out_frames, 0);
    766  EXPECT_TRUE(hasUnderrun);
    767  hasUnderrun = dr.Resample(out_ch2, out_frames, 1);
    768  EXPECT_TRUE(hasUnderrun);
    769  for (uint32_t i = 0; i < out_frames; ++i) {
    770    EXPECT_EQ(out_ch1[i], 0.0f) << "for i=" << i;
    771    EXPECT_EQ(out_ch2[i], 0.0f) << "for i=" << i;
    772  }
    773 }