15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/audio_bus.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/multi_channel_resampler.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Just test a basic resampling case. The SincResampler unit test will take 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// care of accuracy testing; we just need to check that multichannel works as 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expected within some tolerance. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kScaleFactor = 192000.0f / 44100.0f; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Simulate large and small sample requests used by the different audio paths. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kHighLatencySize = 8192; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Low latency buffers show a larger error than high latency ones. Which makes 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sense since each error represents a larger portion of the total request. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kLowLatencySize = 128; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test fill value. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kFillValue = 0.1f; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Chosen arbitrarily based on what each resampler reported during testing. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kLowLatencyMaxRMSError = 0.0036; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kLowLatencyMaxError = 0.04; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kHighLatencyMaxRMSError = 0.0036; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kHighLatencyMaxError = 0.04; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultiChannelResamplerTest 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : public testing::TestWithParam<int> { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MultiChannelResamplerTest() 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : last_frame_delay_(-1) { 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~MultiChannelResamplerTest() {} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void InitializeAudioData(int channels, int frames) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_ = frames; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_bus_ = AudioBus::Create(channels, frames); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MultiChannelResampler::MultiChannelAudioSourceProvider implementation, just 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fills the provided audio_data with |kFillValue|. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void ProvideInput(int frame_delay, AudioBus* audio_bus) { 53b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) EXPECT_GE(frame_delay, last_frame_delay_); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_frame_delay_ = frame_delay; 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float fill_value = fill_junk_values_ ? (1 / kFillValue) : kFillValue; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_EQ(audio_bus->channels(), audio_bus_->channels()); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < audio_bus->channels(); ++i) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = 0; j < audio_bus->frames(); ++j) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_bus->channel(i)[j] = fill_value; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void MultiChannelTest(int channels, int frames, double expected_max_rms_error, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double expected_max_error) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InitializeAudioData(channels, frames); 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) MultiChannelResampler resampler( 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) channels, kScaleFactor, SincResampler::kDefaultRequestSize, base::Bind( 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) &MultiChannelResamplerTest::ProvideInput, base::Unretained(this))); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // First prime the resampler with some junk data, so we can verify Flush(). 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fill_junk_values_ = true; 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) resampler.Resample(1, audio_bus_.get()); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resampler.Flush(); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fill_junk_values_ = false; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The last frame delay should be strictly less than the total frame count. 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_LT(last_frame_delay_, audio_bus_->frames()); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_frame_delay_ = -1; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If Flush() didn't work, the rest of the tests will fail. 81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) resampler.Resample(frames, audio_bus_.get()); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TestValues(expected_max_rms_error, expected_max_error); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void HighLatencyTest(int channels) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiChannelTest(channels, kHighLatencySize, kHighLatencyMaxRMSError, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kHighLatencyMaxError); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void LowLatencyTest(int channels) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiChannelTest(channels, kLowLatencySize, kLowLatencyMaxRMSError, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kLowLatencyMaxError); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void TestValues(double expected_max_rms_error, double expected_max_error ) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Calculate Root-Mean-Square-Error for the resampling. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double max_error = 0.0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double sum_of_squares = 0.0; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < audio_bus_->channels(); ++i) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int j = 0; j < frames_; ++j) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure all values are accounted for. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT_NE(audio_bus_->channel(i)[j], 0); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double error = fabs(audio_bus_->channel(i)[j] - kFillValue); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_error = std::max(max_error, error); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum_of_squares += error * error; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double rms_error = sqrt( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sum_of_squares / (frames_ * audio_bus_->channels())); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_LE(rms_error, expected_max_rms_error); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EXPECT_LE(max_error, expected_max_error); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected: 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int frames_; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool fill_junk_values_; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<AudioBus> audio_bus_; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int last_frame_delay_; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MultiChannelResamplerTest); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_P(MultiChannelResamplerTest, HighLatency) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HighLatencyTest(GetParam()); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_P(MultiChannelResamplerTest, LowLatency) { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LowLatencyTest(GetParam()); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test common channel layouts: mono, stereo, 5.1, 7.1. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)INSTANTIATE_TEST_CASE_P( 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MultiChannelResamplerTest, MultiChannelResamplerTest, 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) testing::Values(1, 2, 6, 8)); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 140