Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / filters / audio_renderer_algorithm_unittest.cc
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   ~AudioRendererAlgorithmTest() override {}
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