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