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