Home | History | Annotate | Download | only in filters
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // The format of these tests are to enqueue a known amount of data and then
      6 // request the exact amount we expect in order to dequeue the known amount of
      7 // data.  This ensures that for any rate we are consuming input data at the
      8 // correct rate.  We always pass in a very large destination buffer with the
      9 // expectation that FillBuffer() will fill as much as it can but no more.
     10 
     11 #include <algorithm>  // For std::min().
     12 #include <cmath>
     13 #include <vector>
     14 
     15 #include "base/bind.h"
     16 #include "base/callback.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "media/base/audio_buffer.h"
     19 #include "media/base/audio_bus.h"
     20 #include "media/base/buffers.h"
     21 #include "media/base/channel_layout.h"
     22 #include "media/base/test_helpers.h"
     23 #include "media/filters/audio_renderer_algorithm.h"
     24 #include "media/filters/wsola_internals.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 namespace media {
     28 
     29 const int kFrameSize = 250;
     30 const int kSamplesPerSecond = 3000;
     31 const int kOutputDurationInSec = 10;
     32 
     33 static void FillWithSquarePulseTrain(
     34     int half_pulse_width, int offset, int num_samples, float* data) {
     35   ASSERT_GE(offset, 0);
     36   ASSERT_LE(offset, num_samples);
     37 
     38   // Fill backward from |offset| - 1 toward zero, starting with -1, alternating
     39   // between -1 and 1 every |pulse_width| samples.
     40   float pulse = -1.0f;
     41   for (int n = offset - 1, k = 0; n >= 0; --n, ++k) {
     42     if (k >= half_pulse_width) {
     43       pulse = -pulse;
     44       k = 0;
     45     }
     46     data[n] = pulse;
     47   }
     48 
     49   // Fill forward from |offset| towards the end, starting with 1, alternating
     50   // between 1 and -1 every |pulse_width| samples.
     51   pulse = 1.0f;
     52   for (int n = offset, k = 0; n < num_samples; ++n, ++k) {
     53     if (k >= half_pulse_width) {
     54       pulse = -pulse;
     55       k = 0;
     56     }
     57     data[n] = pulse;
     58   }
     59 }
     60 
     61 static void FillWithSquarePulseTrain(
     62     int half_pulse_width, int offset, int channel, AudioBus* audio_bus) {
     63   FillWithSquarePulseTrain(half_pulse_width, offset, audio_bus->frames(),
     64                            audio_bus->channel(channel));
     65 }
     66 
     67 class AudioRendererAlgorithmTest : public testing::Test {
     68  public:
     69   AudioRendererAlgorithmTest()
     70       : frames_enqueued_(0),
     71         channels_(0),
     72         channel_layout_(CHANNEL_LAYOUT_NONE),
     73         sample_format_(kUnknownSampleFormat),
     74         samples_per_second_(0),
     75         bytes_per_sample_(0) {
     76   }
     77 
     78   virtual ~AudioRendererAlgorithmTest() {}
     79 
     80   void Initialize() {
     81     Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 3000);
     82   }
     83 
     84   void Initialize(ChannelLayout channel_layout,
     85                   SampleFormat sample_format,
     86                   int samples_per_second) {
     87     channels_ = ChannelLayoutToChannelCount(channel_layout);
     88     samples_per_second_ = samples_per_second;
     89     channel_layout_ = channel_layout;
     90     sample_format_ = sample_format;
     91     bytes_per_sample_ = SampleFormatToBytesPerChannel(sample_format);
     92     AudioParameters params(media::AudioParameters::AUDIO_PCM_LINEAR,
     93                            channel_layout,
     94                            samples_per_second,
     95                            bytes_per_sample_ * 8,
     96                            samples_per_second / 100);
     97     algorithm_.Initialize(params);
     98     FillAlgorithmQueue();
     99   }
    100 
    101   void FillAlgorithmQueue() {
    102     // The value of the data is meaningless; we just want non-zero data to
    103     // differentiate it from muted data.
    104     scoped_refptr<AudioBuffer> buffer;
    105     while (!algorithm_.IsQueueFull()) {
    106       switch (sample_format_) {
    107         case kSampleFormatU8:
    108           buffer = MakeAudioBuffer<uint8>(
    109               sample_format_,
    110               channel_layout_,
    111               ChannelLayoutToChannelCount(channel_layout_),
    112               samples_per_second_,
    113               1,
    114               1,
    115               kFrameSize,
    116               kNoTimestamp());
    117           break;
    118         case kSampleFormatS16:
    119           buffer = MakeAudioBuffer<int16>(
    120               sample_format_,
    121               channel_layout_,
    122               ChannelLayoutToChannelCount(channel_layout_),
    123               samples_per_second_,
    124               1,
    125               1,
    126               kFrameSize,
    127               kNoTimestamp());
    128           break;
    129         case kSampleFormatS32:
    130           buffer = MakeAudioBuffer<int32>(
    131               sample_format_,
    132               channel_layout_,
    133               ChannelLayoutToChannelCount(channel_layout_),
    134               samples_per_second_,
    135               1,
    136               1,
    137               kFrameSize,
    138               kNoTimestamp());
    139           break;
    140         default:
    141           NOTREACHED() << "Unrecognized format " << sample_format_;
    142       }
    143       algorithm_.EnqueueBuffer(buffer);
    144       frames_enqueued_ += kFrameSize;
    145     }
    146   }
    147 
    148   bool AudioDataIsMuted(AudioBus* audio_data, int frames_written) {
    149     for (int ch = 0; ch < channels_; ++ch) {
    150       for (int i = 0; i < frames_written; ++i) {
    151         if (audio_data->channel(ch)[i] != 0.0f)
    152           return false;
    153       }
    154     }
    155     return true;
    156   }
    157 
    158   int ComputeConsumedFrames(int initial_frames_enqueued,
    159                             int initial_frames_buffered) {
    160     int frame_delta = frames_enqueued_ - initial_frames_enqueued;
    161     int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered;
    162     int consumed = frame_delta - buffered_delta;
    163     CHECK_GE(consumed, 0);
    164     return consumed;
    165   }
    166 
    167   void TestPlaybackRate(double playback_rate) {
    168     const int kDefaultBufferSize = algorithm_.samples_per_second() / 100;
    169     const int kDefaultFramesRequested = kOutputDurationInSec *
    170         algorithm_.samples_per_second();
    171 
    172     TestPlaybackRate(
    173         playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
    174   }
    175 
    176   void TestPlaybackRate(double playback_rate,
    177                         int buffer_size_in_frames,
    178                         int total_frames_requested) {
    179     int initial_frames_enqueued = frames_enqueued_;
    180     int initial_frames_buffered = algorithm_.frames_buffered();
    181 
    182     scoped_ptr<AudioBus> bus =
    183         AudioBus::Create(channels_, buffer_size_in_frames);
    184     if (playback_rate == 0.0) {
    185       int frames_written = algorithm_.FillBuffer(
    186           bus.get(), buffer_size_in_frames, playback_rate);
    187       EXPECT_EQ(0, frames_written);
    188       return;
    189     }
    190 
    191     bool expect_muted = (playback_rate < 0.5 || playback_rate > 4);
    192 
    193     int frames_remaining = total_frames_requested;
    194     bool first_fill_buffer = true;
    195     while (frames_remaining > 0) {
    196       int frames_requested = std::min(buffer_size_in_frames, frames_remaining);
    197       int frames_written =
    198           algorithm_.FillBuffer(bus.get(), frames_requested, playback_rate);
    199       ASSERT_GT(frames_written, 0) << "Requested: " << frames_requested
    200                                    << ", playing at " << playback_rate;
    201 
    202       // Do not check data if it is first pull out and only one frame written.
    203       // The very first frame out of WSOLA is always zero because of
    204       // overlap-and-add window, which is zero for the first sample. Therefore,
    205       // if at very first buffer-fill only one frame is written, that is zero
    206       // which might cause exception in CheckFakeData().
    207       if (!first_fill_buffer || frames_written > 1)
    208         ASSERT_EQ(expect_muted, AudioDataIsMuted(bus.get(), frames_written));
    209       first_fill_buffer = false;
    210       frames_remaining -= frames_written;
    211 
    212       FillAlgorithmQueue();
    213     }
    214 
    215     int frames_consumed =
    216         ComputeConsumedFrames(initial_frames_enqueued, initial_frames_buffered);
    217 
    218     // If playing back at normal speed, we should always get back the same
    219     // number of bytes requested.
    220     if (playback_rate == 1.0) {
    221       EXPECT_EQ(total_frames_requested, frames_consumed);
    222       return;
    223     }
    224 
    225     // Otherwise, allow |kMaxAcceptableDelta| difference between the target and
    226     // actual playback rate.
    227     // When |kSamplesPerSecond| and |total_frames_requested| are reasonably
    228     // large, one can expect less than a 1% difference in most cases. In our
    229     // current implementation, sped up playback is less accurate than slowed
    230     // down playback, and for playback_rate > 1, playback rate generally gets
    231     // less and less accurate the farther it drifts from 1 (though this is
    232     // nonlinear).
    233     double actual_playback_rate =
    234         1.0 * frames_consumed / total_frames_requested;
    235     EXPECT_NEAR(playback_rate, actual_playback_rate, playback_rate / 100.0);
    236   }
    237 
    238   void WsolaTest(float playback_rate) {
    239     const int kSampleRateHz = 48000;
    240     const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
    241     const int kBytesPerSample = 2;
    242     const int kNumFrames = kSampleRateHz / 100;  // 10 milliseconds.
    243 
    244     channels_ = ChannelLayoutToChannelCount(kChannelLayout);
    245     AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
    246                            kSampleRateHz, kBytesPerSample * 8, kNumFrames);
    247     algorithm_.Initialize(params);
    248 
    249     // A pulse is 6 milliseconds (even number of samples).
    250     const int kPulseWidthSamples = 6 * kSampleRateHz / 1000;
    251     const int kHalfPulseWidthSamples = kPulseWidthSamples / 2;
    252 
    253     // For the ease of implementation get 1 frame every call to FillBuffer().
    254     scoped_ptr<AudioBus> output = AudioBus::Create(channels_, 1);
    255 
    256     // Input buffer to inject pulses.
    257     scoped_refptr<AudioBuffer> input =
    258         AudioBuffer::CreateBuffer(kSampleFormatPlanarF32,
    259                                   kChannelLayout,
    260                                   channels_,
    261                                   kSampleRateHz,
    262                                   kPulseWidthSamples);
    263 
    264     const std::vector<uint8*>& channel_data = input->channel_data();
    265 
    266     // Fill |input| channels.
    267     FillWithSquarePulseTrain(kHalfPulseWidthSamples, 0, kPulseWidthSamples,
    268                              reinterpret_cast<float*>(channel_data[0]));
    269     FillWithSquarePulseTrain(kHalfPulseWidthSamples, kHalfPulseWidthSamples,
    270                              kPulseWidthSamples,
    271                              reinterpret_cast<float*>(channel_data[1]));
    272 
    273     // A buffer for the output until a complete pulse is created. Then
    274     // reference pulse is compared with this buffer.
    275     scoped_ptr<AudioBus> pulse_buffer = AudioBus::Create(
    276         channels_, kPulseWidthSamples);
    277 
    278     const float kTolerance = 0.000001f;
    279     // Equivalent of 4 seconds.
    280     const int kNumRequestedPulses = kSampleRateHz * 4 / kPulseWidthSamples;
    281     for (int n = 0; n < kNumRequestedPulses; ++n) {
    282       int num_buffered_frames = 0;
    283       while (num_buffered_frames < kPulseWidthSamples) {
    284         int num_samples = algorithm_.FillBuffer(output.get(), 1, playback_rate);
    285         ASSERT_LE(num_samples, 1);
    286         if (num_samples > 0) {
    287           output->CopyPartialFramesTo(0, num_samples, num_buffered_frames,
    288                                       pulse_buffer.get());
    289           num_buffered_frames++;
    290         } else {
    291           algorithm_.EnqueueBuffer(input);
    292         }
    293       }
    294 
    295       // Pulses in the first half of WSOLA AOL frame are not constructed
    296       // perfectly. Do not check them.
    297       if (n > 3) {
    298          for (int m = 0; m < channels_; ++m) {
    299           const float* pulse_ch = pulse_buffer->channel(m);
    300 
    301           // Because of overlap-and-add we might have round off error.
    302           for (int k = 0; k < kPulseWidthSamples; ++k) {
    303             ASSERT_NEAR(reinterpret_cast<float*>(channel_data[m])[k],
    304                         pulse_ch[k], kTolerance) << " loop " << n
    305                                 << " channel/sample " << m << "/" << k;
    306           }
    307         }
    308       }
    309 
    310       // Zero out the buffer to be sure the next comparison is relevant.
    311       pulse_buffer->Zero();
    312     }
    313   }
    314 
    315  protected:
    316   AudioRendererAlgorithm algorithm_;
    317   int frames_enqueued_;
    318   int channels_;
    319   ChannelLayout channel_layout_;
    320   SampleFormat sample_format_;
    321   int samples_per_second_;
    322   int bytes_per_sample_;
    323 };
    324 
    325 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NormalRate) {
    326   Initialize();
    327   TestPlaybackRate(1.0);
    328 }
    329 
    330 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NearlyNormalFasterRate) {
    331   Initialize();
    332   TestPlaybackRate(1.0001);
    333 }
    334 
    335 TEST_F(AudioRendererAlgorithmTest, FillBuffer_NearlyNormalSlowerRate) {
    336   Initialize();
    337   TestPlaybackRate(0.9999);
    338 }
    339 
    340 TEST_F(AudioRendererAlgorithmTest, FillBuffer_OneAndAQuarterRate) {
    341   Initialize();
    342   TestPlaybackRate(1.25);
    343 }
    344 
    345 TEST_F(AudioRendererAlgorithmTest, FillBuffer_OneAndAHalfRate) {
    346   Initialize();
    347   TestPlaybackRate(1.5);
    348 }
    349 
    350 TEST_F(AudioRendererAlgorithmTest, FillBuffer_DoubleRate) {
    351   Initialize();
    352   TestPlaybackRate(2.0);
    353 }
    354 
    355 TEST_F(AudioRendererAlgorithmTest, FillBuffer_EightTimesRate) {
    356   Initialize();
    357   TestPlaybackRate(8.0);
    358 }
    359 
    360 TEST_F(AudioRendererAlgorithmTest, FillBuffer_ThreeQuartersRate) {
    361   Initialize();
    362   TestPlaybackRate(0.75);
    363 }
    364 
    365 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HalfRate) {
    366   Initialize();
    367   TestPlaybackRate(0.5);
    368 }
    369 
    370 TEST_F(AudioRendererAlgorithmTest, FillBuffer_QuarterRate) {
    371   Initialize();
    372   TestPlaybackRate(0.25);
    373 }
    374 
    375 TEST_F(AudioRendererAlgorithmTest, FillBuffer_Pause) {
    376   Initialize();
    377   TestPlaybackRate(0.0);
    378 }
    379 
    380 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SlowDown) {
    381   Initialize();
    382   TestPlaybackRate(4.5);
    383   TestPlaybackRate(3.0);
    384   TestPlaybackRate(2.0);
    385   TestPlaybackRate(1.0);
    386   TestPlaybackRate(0.5);
    387   TestPlaybackRate(0.25);
    388 }
    389 
    390 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SpeedUp) {
    391   Initialize();
    392   TestPlaybackRate(0.25);
    393   TestPlaybackRate(0.5);
    394   TestPlaybackRate(1.0);
    395   TestPlaybackRate(2.0);
    396   TestPlaybackRate(3.0);
    397   TestPlaybackRate(4.5);
    398 }
    399 
    400 TEST_F(AudioRendererAlgorithmTest, FillBuffer_JumpAroundSpeeds) {
    401   Initialize();
    402   TestPlaybackRate(2.1);
    403   TestPlaybackRate(0.9);
    404   TestPlaybackRate(0.6);
    405   TestPlaybackRate(1.4);
    406   TestPlaybackRate(0.3);
    407 }
    408 
    409 TEST_F(AudioRendererAlgorithmTest, FillBuffer_SmallBufferSize) {
    410   Initialize();
    411   static const int kBufferSizeInFrames = 1;
    412   static const int kFramesRequested = kOutputDurationInSec * kSamplesPerSecond;
    413   TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
    414   TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
    415   TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
    416 }
    417 
    418 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LargeBufferSize) {
    419   Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS16, 44100);
    420   TestPlaybackRate(1.0);
    421   TestPlaybackRate(0.5);
    422   TestPlaybackRate(1.5);
    423 }
    424 
    425 TEST_F(AudioRendererAlgorithmTest, FillBuffer_LowerQualityAudio) {
    426   Initialize(CHANNEL_LAYOUT_MONO, kSampleFormatU8, kSamplesPerSecond);
    427   TestPlaybackRate(1.0);
    428   TestPlaybackRate(0.5);
    429   TestPlaybackRate(1.5);
    430 }
    431 
    432 TEST_F(AudioRendererAlgorithmTest, FillBuffer_HigherQualityAudio) {
    433   Initialize(CHANNEL_LAYOUT_STEREO, kSampleFormatS32, kSamplesPerSecond);
    434   TestPlaybackRate(1.0);
    435   TestPlaybackRate(0.5);
    436   TestPlaybackRate(1.5);
    437 }
    438 
    439 TEST_F(AudioRendererAlgorithmTest, DotProduct) {
    440   const int kChannels = 3;
    441   const int kFrames = 20;
    442   const int kHalfPulseWidth = 2;
    443 
    444   scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
    445   scoped_ptr<AudioBus> b = AudioBus::Create(kChannels, kFrames);
    446 
    447   scoped_ptr<float[]> dot_prod(new float[kChannels]);
    448 
    449   FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, a.get());
    450   FillWithSquarePulseTrain(kHalfPulseWidth, 1, 1, a.get());
    451   FillWithSquarePulseTrain(kHalfPulseWidth, 2, 2, a.get());
    452 
    453   FillWithSquarePulseTrain(kHalfPulseWidth, 0, 0, b.get());
    454   FillWithSquarePulseTrain(kHalfPulseWidth, 0, 1, b.get());
    455   FillWithSquarePulseTrain(kHalfPulseWidth, 0, 2, b.get());
    456 
    457   internal::MultiChannelDotProduct(a.get(), 0, b.get(), 0, kFrames,
    458                                    dot_prod.get());
    459 
    460   EXPECT_FLOAT_EQ(kFrames, dot_prod[0]);
    461   EXPECT_FLOAT_EQ(0, dot_prod[1]);
    462   EXPECT_FLOAT_EQ(-kFrames, dot_prod[2]);
    463 
    464   internal::MultiChannelDotProduct(a.get(), 4, b.get(), 8, kFrames / 2,
    465                                    dot_prod.get());
    466 
    467   EXPECT_FLOAT_EQ(kFrames / 2, dot_prod[0]);
    468   EXPECT_FLOAT_EQ(0, dot_prod[1]);
    469   EXPECT_FLOAT_EQ(-kFrames / 2, dot_prod[2]);
    470 }
    471 
    472 TEST_F(AudioRendererAlgorithmTest, MovingBlockEnergy) {
    473   const int kChannels = 2;
    474   const int kFrames = 20;
    475   const int kFramesPerBlock = 3;
    476   const int kNumBlocks = kFrames - (kFramesPerBlock - 1);
    477   scoped_ptr<AudioBus> a = AudioBus::Create(kChannels, kFrames);
    478   scoped_ptr<float[]> energies(new float[kChannels * kNumBlocks]);
    479   float* ch_left = a->channel(0);
    480   float* ch_right = a->channel(1);
    481 
    482   // Fill up both channels.
    483   for (int n = 0; n < kFrames; ++n) {
    484     ch_left[n] = n;
    485     ch_right[n] = kFrames - 1 - n;
    486   }
    487 
    488   internal::MultiChannelMovingBlockEnergies(a.get(), kFramesPerBlock,
    489                                             energies.get());
    490 
    491   // Check if the energy of candidate blocks of each channel computed correctly.
    492   for (int n = 0; n < kNumBlocks; ++n) {
    493     float expected_energy = 0;
    494     for (int k = 0; k < kFramesPerBlock; ++k)
    495       expected_energy += ch_left[n + k] * ch_left[n + k];
    496 
    497     // Left (first) channel.
    498     EXPECT_FLOAT_EQ(expected_energy, energies[2 * n]);
    499 
    500     expected_energy = 0;
    501     for (int k = 0; k < kFramesPerBlock; ++k)
    502       expected_energy += ch_right[n + k] * ch_right[n + k];
    503 
    504     // Second (right) channel.
    505     EXPECT_FLOAT_EQ(expected_energy, energies[2 * n + 1]);
    506   }
    507 }
    508 
    509 TEST_F(AudioRendererAlgorithmTest, FullAndDecimatedSearch) {
    510   const int kFramesInSearchRegion = 12;
    511   const int kChannels = 2;
    512   float ch_0[] = {
    513       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f };
    514   float ch_1[] = {
    515       0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 1.0f, 0.1f, 0.0f, 0.0f };
    516   ASSERT_EQ(sizeof(ch_0), sizeof(ch_1));
    517   ASSERT_EQ(static_cast<size_t>(kFramesInSearchRegion),
    518             sizeof(ch_0) / sizeof(*ch_0));
    519   scoped_ptr<AudioBus> search_region = AudioBus::Create(kChannels,
    520                                                         kFramesInSearchRegion);
    521   float* ch = search_region->channel(0);
    522   memcpy(ch, ch_0, sizeof(float) * kFramesInSearchRegion);
    523   ch = search_region->channel(1);
    524   memcpy(ch, ch_1, sizeof(float) * kFramesInSearchRegion);
    525 
    526   const int kFramePerBlock = 4;
    527   float target_0[] = { 1.0f, 1.0f, 1.0f, 0.0f };
    528   float target_1[] = { 0.0f, 1.0f, 0.1f, 1.0f };
    529   ASSERT_EQ(sizeof(target_0), sizeof(target_1));
    530   ASSERT_EQ(static_cast<size_t>(kFramePerBlock),
    531             sizeof(target_0) / sizeof(*target_0));
    532 
    533   scoped_ptr<AudioBus> target = AudioBus::Create(kChannels,
    534                                                  kFramePerBlock);
    535   ch = target->channel(0);
    536   memcpy(ch, target_0, sizeof(float) * kFramePerBlock);
    537   ch = target->channel(1);
    538   memcpy(ch, target_1, sizeof(float) * kFramePerBlock);
    539 
    540   scoped_ptr<float[]> energy_target(new float[kChannels]);
    541 
    542   internal::MultiChannelDotProduct(target.get(), 0, target.get(), 0,
    543                                    kFramePerBlock, energy_target.get());
    544 
    545   ASSERT_EQ(3.f, energy_target[0]);
    546   ASSERT_EQ(2.01f, energy_target[1]);
    547 
    548   const int kNumCandidBlocks = kFramesInSearchRegion - (kFramePerBlock - 1);
    549   scoped_ptr<float[]> energy_candid_blocks(new float[kNumCandidBlocks *
    550                                                      kChannels]);
    551 
    552   internal::MultiChannelMovingBlockEnergies(
    553       search_region.get(), kFramePerBlock, energy_candid_blocks.get());
    554 
    555   // Check the energy of the candidate blocks of the first channel.
    556   ASSERT_FLOAT_EQ(0, energy_candid_blocks[0]);
    557   ASSERT_FLOAT_EQ(0, energy_candid_blocks[2]);
    558   ASSERT_FLOAT_EQ(1, energy_candid_blocks[4]);
    559   ASSERT_FLOAT_EQ(2, energy_candid_blocks[6]);
    560   ASSERT_FLOAT_EQ(3, energy_candid_blocks[8]);
    561   ASSERT_FLOAT_EQ(3, energy_candid_blocks[10]);
    562   ASSERT_FLOAT_EQ(2, energy_candid_blocks[12]);
    563   ASSERT_FLOAT_EQ(1, energy_candid_blocks[14]);
    564   ASSERT_FLOAT_EQ(0, energy_candid_blocks[16]);
    565 
    566   // Check the energy of the candidate blocks of the second channel.
    567   ASSERT_FLOAT_EQ(0, energy_candid_blocks[1]);
    568   ASSERT_FLOAT_EQ(0, energy_candid_blocks[3]);
    569   ASSERT_FLOAT_EQ(0, energy_candid_blocks[5]);
    570   ASSERT_FLOAT_EQ(0, energy_candid_blocks[7]);
    571   ASSERT_FLOAT_EQ(0.01f, energy_candid_blocks[9]);
    572   ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[11]);
    573   ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[13]);
    574   ASSERT_FLOAT_EQ(1.02f, energy_candid_blocks[15]);
    575   ASSERT_FLOAT_EQ(1.01f, energy_candid_blocks[17]);
    576 
    577   // An interval which is of no effect.
    578   internal::Interval exclude_interval = std::make_pair(-100, -10);
    579   EXPECT_EQ(5, internal::FullSearch(
    580       0, kNumCandidBlocks - 1, exclude_interval, target.get(),
    581       search_region.get(), energy_target.get(), energy_candid_blocks.get()));
    582 
    583   // Exclude the the best match.
    584   exclude_interval = std::make_pair(2, 5);
    585   EXPECT_EQ(7, internal::FullSearch(
    586       0, kNumCandidBlocks - 1, exclude_interval, target.get(),
    587       search_region.get(), energy_target.get(), energy_candid_blocks.get()));
    588 
    589   // An interval which is of no effect.
    590   exclude_interval = std::make_pair(-100, -10);
    591   EXPECT_EQ(4, internal::DecimatedSearch(
    592       4, exclude_interval, target.get(), search_region.get(),
    593       energy_target.get(), energy_candid_blocks.get()));
    594 
    595   EXPECT_EQ(5, internal::OptimalIndex(search_region.get(), target.get(),
    596                                       exclude_interval));
    597 }
    598 
    599 TEST_F(AudioRendererAlgorithmTest, QuadraticInterpolation) {
    600   // Arbitrary coefficients.
    601   const float kA = 0.7f;
    602   const float kB = 1.2f;
    603   const float kC = 0.8f;
    604 
    605   float y_values[3];
    606   y_values[0] = kA - kB + kC;
    607   y_values[1] = kC;
    608   y_values[2] = kA + kB + kC;
    609 
    610   float extremum;
    611   float extremum_value;
    612 
    613   internal::QuadraticInterpolation(y_values, &extremum, &extremum_value);
    614 
    615   float x_star = -kB / (2.f * kA);
    616   float y_star = kA * x_star * x_star + kB * x_star + kC;
    617 
    618   EXPECT_FLOAT_EQ(x_star, extremum);
    619   EXPECT_FLOAT_EQ(y_star, extremum_value);
    620 }
    621 
    622 TEST_F(AudioRendererAlgorithmTest, QuadraticInterpolation_Colinear) {
    623   float y_values[3];
    624   y_values[0] = 1.0;
    625   y_values[1] = 1.0;
    626   y_values[2] = 1.0;
    627 
    628   float extremum;
    629   float extremum_value;
    630 
    631   internal::QuadraticInterpolation(y_values, &extremum, &extremum_value);
    632 
    633   EXPECT_FLOAT_EQ(extremum, 0.0);
    634   EXPECT_FLOAT_EQ(extremum_value, 1.0);
    635 }
    636 
    637 TEST_F(AudioRendererAlgorithmTest, WsolaSlowdown) {
    638   WsolaTest(0.6f);
    639 }
    640 
    641 TEST_F(AudioRendererAlgorithmTest, WsolaSpeedup) {
    642   WsolaTest(1.6f);
    643 }
    644 
    645 }  // namespace media
    646