resampler_unittest.cc (5823B)
1 /* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "common_audio/resampler/include/resampler.h" 12 13 #include <array> 14 #include <cstddef> 15 #include <cstdint> 16 #include <cstring> 17 18 #include "rtc_base/strings/string_builder.h" 19 #include "test/gtest.h" 20 21 // TODO(andrew): this is a work-in-progress. Many more tests are needed. 22 23 namespace webrtc { 24 namespace { 25 26 // Rates we must support. 27 constexpr int kMaxRate = 96000; 28 constexpr int kRates[] = {8000, 16000, 32000, 44000, 48000, kMaxRate}; 29 constexpr size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); 30 constexpr int kMaxChannels = 2; 31 constexpr size_t kDataSize = static_cast<size_t>(kMaxChannels * kMaxRate / 100); 32 33 // TODO(andrew): should we be supporting these combinations? 34 bool ValidRates(int in_rate, int out_rate) { 35 // Not the most compact notation, for clarity. 36 if ((in_rate == 44000 && (out_rate == 48000 || out_rate == 96000)) || 37 (out_rate == 44000 && (in_rate == 48000 || in_rate == 96000))) { 38 return false; 39 } 40 41 return true; 42 } 43 44 class ResamplerTest : public ::testing::Test { 45 protected: 46 ResamplerTest(); 47 void SetUp() override; 48 void TearDown() override; 49 50 void ResetIfNeededAndPush(int in_rate, int out_rate, int num_channels); 51 52 Resampler rs_; 53 int16_t data_in_[kDataSize]; 54 int16_t data_out_[kDataSize]; 55 }; 56 57 ResamplerTest::ResamplerTest() {} 58 59 void ResamplerTest::SetUp() { 60 // Initialize input data with anything. The tests are content independent. 61 memset(data_in_, 1, sizeof(data_in_)); 62 } 63 64 void ResamplerTest::TearDown() {} 65 66 void ResamplerTest::ResetIfNeededAndPush(int in_rate, 67 int out_rate, 68 int num_channels) { 69 StringBuilder ss; 70 ss << "Input rate: " << in_rate << ", output rate: " << out_rate 71 << ", channel count: " << num_channels; 72 SCOPED_TRACE(ss.str()); 73 74 if (ValidRates(in_rate, out_rate)) { 75 size_t in_length = static_cast<size_t>(in_rate / 100); 76 size_t out_length = 0; 77 EXPECT_EQ(0, rs_.ResetIfNeeded(in_rate, out_rate, num_channels)); 78 EXPECT_EQ(0, 79 rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); 80 EXPECT_EQ(static_cast<size_t>(out_rate / 100), out_length); 81 } else { 82 EXPECT_EQ(-1, rs_.ResetIfNeeded(in_rate, out_rate, num_channels)); 83 } 84 } 85 86 TEST_F(ResamplerTest, Reset) { 87 const int kNumChannels[] = {1, 2}; 88 const size_t kNumChannelsSize = std::size(kNumChannels); 89 90 // The only failure mode for the constructor is if Reset() fails. For the 91 // time being then (until an Init function is added), we rely on Reset() 92 // to test the constructor. 93 94 // Check that all required combinations are supported. 95 for (size_t i = 0; i < kRatesSize; ++i) { 96 for (size_t j = 0; j < kRatesSize; ++j) { 97 for (size_t k = 0; k < kNumChannelsSize; ++k) { 98 StringBuilder ss; 99 ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j] 100 << ", channels: " << kNumChannels[k]; 101 SCOPED_TRACE(ss.str()); 102 if (ValidRates(kRates[i], kRates[j])) 103 EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); 104 else 105 EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); 106 } 107 } 108 } 109 } 110 111 // TODO(tlegrand): Replace code inside the two tests below with a function 112 // with number of channels and ResamplerType as input. 113 TEST_F(ResamplerTest, Mono) { 114 const int kChannels = 1; 115 for (size_t i = 0; i < kRatesSize; ++i) { 116 for (size_t j = 0; j < kRatesSize; ++j) { 117 StringBuilder ss; 118 ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j]; 119 SCOPED_TRACE(ss.str()); 120 121 if (ValidRates(kRates[i], kRates[j])) { 122 size_t in_length = static_cast<size_t>(kRates[i] / 100); 123 size_t out_length = 0; 124 EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); 125 EXPECT_EQ( 126 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); 127 EXPECT_EQ(static_cast<size_t>(kRates[j] / 100), out_length); 128 } else { 129 EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); 130 } 131 } 132 } 133 } 134 135 TEST_F(ResamplerTest, Stereo) { 136 const int kChannels = 2; 137 for (size_t i = 0; i < kRatesSize; ++i) { 138 for (size_t j = 0; j < kRatesSize; ++j) { 139 StringBuilder ss; 140 ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j]; 141 SCOPED_TRACE(ss.str()); 142 143 if (ValidRates(kRates[i], kRates[j])) { 144 size_t in_length = static_cast<size_t>(kChannels * kRates[i] / 100); 145 size_t out_length = 0; 146 EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); 147 EXPECT_EQ( 148 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); 149 EXPECT_EQ(static_cast<size_t>(kChannels * kRates[j] / 100), out_length); 150 } else { 151 EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); 152 } 153 } 154 } 155 } 156 157 // Try multiple resets between a few supported and unsupported rates. 158 TEST_F(ResamplerTest, MultipleResets) { 159 constexpr size_t kNumChanges = 5; 160 constexpr std::array<int, kNumChanges> kInRates = { 161 {8000, 44000, 44000, 32000, 32000}}; 162 constexpr std::array<int, kNumChanges> kOutRates = { 163 {16000, 48000, 48000, 16000, 16000}}; 164 constexpr std::array<int, kNumChanges> kNumChannels = {{2, 2, 2, 2, 1}}; 165 for (size_t i = 0; i < kNumChanges; ++i) { 166 ResetIfNeededAndPush(kInRates[i], kOutRates[i], kNumChannels[i]); 167 } 168 } 169 170 } // namespace 171 } // namespace webrtc