Home | History | Annotate | Download | only in base
      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 #include <cmath>
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "media/base/audio_bus.h"
     12 #include "media/base/multi_channel_resampler.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 namespace media {
     16 
     17 // Just test a basic resampling case.  The SincResampler unit test will take
     18 // care of accuracy testing; we just need to check that multichannel works as
     19 // expected within some tolerance.
     20 static const float kScaleFactor = 192000.0f / 44100.0f;
     21 
     22 // Simulate large and small sample requests used by the different audio paths.
     23 static const int kHighLatencySize = 8192;
     24 // Low latency buffers show a larger error than high latency ones.  Which makes
     25 // sense since each error represents a larger portion of the total request.
     26 static const int kLowLatencySize = 128;
     27 
     28 // Test fill value.
     29 static const float kFillValue = 0.1f;
     30 
     31 // Chosen arbitrarily based on what each resampler reported during testing.
     32 static const double kLowLatencyMaxRMSError = 0.0036;
     33 static const double kLowLatencyMaxError = 0.04;
     34 static const double kHighLatencyMaxRMSError = 0.0036;
     35 static const double kHighLatencyMaxError = 0.04;
     36 
     37 class MultiChannelResamplerTest
     38     : public testing::TestWithParam<int> {
     39  public:
     40   MultiChannelResamplerTest()
     41       : last_frame_delay_(-1) {
     42   }
     43   virtual ~MultiChannelResamplerTest() {}
     44 
     45   void InitializeAudioData(int channels, int frames) {
     46     frames_ = frames;
     47     audio_bus_ = AudioBus::Create(channels, frames);
     48   }
     49 
     50   // MultiChannelResampler::MultiChannelAudioSourceProvider implementation, just
     51   // fills the provided audio_data with |kFillValue|.
     52   virtual void ProvideInput(int frame_delay, AudioBus* audio_bus) {
     53     EXPECT_GE(frame_delay, last_frame_delay_);
     54     last_frame_delay_ = frame_delay;
     55 
     56     float fill_value = fill_junk_values_ ? (1 / kFillValue) : kFillValue;
     57     EXPECT_EQ(audio_bus->channels(), audio_bus_->channels());
     58     for (int i = 0; i < audio_bus->channels(); ++i)
     59       for (int j = 0; j < audio_bus->frames(); ++j)
     60         audio_bus->channel(i)[j] = fill_value;
     61   }
     62 
     63   void MultiChannelTest(int channels, int frames, double expected_max_rms_error,
     64                         double expected_max_error) {
     65     InitializeAudioData(channels, frames);
     66     MultiChannelResampler resampler(
     67         channels, kScaleFactor, SincResampler::kDefaultRequestSize, base::Bind(
     68             &MultiChannelResamplerTest::ProvideInput, base::Unretained(this)));
     69 
     70     // First prime the resampler with some junk data, so we can verify Flush().
     71     fill_junk_values_ = true;
     72     resampler.Resample(1, audio_bus_.get());
     73     resampler.Flush();
     74     fill_junk_values_ = false;
     75 
     76     // The last frame delay should be strictly less than the total frame count.
     77     EXPECT_LT(last_frame_delay_, audio_bus_->frames());
     78     last_frame_delay_ = -1;
     79 
     80     // If Flush() didn't work, the rest of the tests will fail.
     81     resampler.Resample(frames, audio_bus_.get());
     82     TestValues(expected_max_rms_error, expected_max_error);
     83   }
     84 
     85   void HighLatencyTest(int channels) {
     86     MultiChannelTest(channels, kHighLatencySize, kHighLatencyMaxRMSError,
     87                      kHighLatencyMaxError);
     88   }
     89 
     90   void LowLatencyTest(int channels) {
     91     MultiChannelTest(channels, kLowLatencySize, kLowLatencyMaxRMSError,
     92                      kLowLatencyMaxError);
     93   }
     94 
     95   void TestValues(double expected_max_rms_error, double expected_max_error ) {
     96     // Calculate Root-Mean-Square-Error for the resampling.
     97     double max_error = 0.0;
     98     double sum_of_squares = 0.0;
     99     for (int i = 0; i < audio_bus_->channels(); ++i) {
    100       for (int j = 0; j < frames_; ++j) {
    101         // Ensure all values are accounted for.
    102         ASSERT_NE(audio_bus_->channel(i)[j], 0);
    103 
    104         double error = fabs(audio_bus_->channel(i)[j] - kFillValue);
    105         max_error = std::max(max_error, error);
    106         sum_of_squares += error * error;
    107       }
    108     }
    109 
    110     double rms_error = sqrt(
    111         sum_of_squares / (frames_ * audio_bus_->channels()));
    112 
    113     EXPECT_LE(rms_error, expected_max_rms_error);
    114     EXPECT_LE(max_error, expected_max_error);
    115   }
    116 
    117  protected:
    118   int frames_;
    119   bool fill_junk_values_;
    120   scoped_ptr<AudioBus> audio_bus_;
    121   int last_frame_delay_;
    122 
    123   DISALLOW_COPY_AND_ASSIGN(MultiChannelResamplerTest);
    124 };
    125 
    126 TEST_P(MultiChannelResamplerTest, HighLatency) {
    127   HighLatencyTest(GetParam());
    128 }
    129 
    130 TEST_P(MultiChannelResamplerTest, LowLatency) {
    131   LowLatencyTest(GetParam());
    132 }
    133 
    134 // Test common channel layouts: mono, stereo, 5.1, 7.1.
    135 INSTANTIATE_TEST_CASE_P(
    136     MultiChannelResamplerTest, MultiChannelResamplerTest,
    137     testing::Values(1, 2, 6, 8));
    138 
    139 }  // namespace media
    140