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