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 #include <memory>
11 #include <string>
12
13 #include "modules/audio_coding/codecs/cng/webrtc_cng.h"
14 #include "test/gtest.h"
15 #include "test/testsupport/file_utils.h"
16
17 namespace webrtc {
18
19 enum {
20 kSidShortIntervalUpdate = 1,
21 kSidNormalIntervalUpdate = 100,
22 kSidLongIntervalUpdate = 10000
23 };
24
25 enum : size_t {
26 kCNGNumParamsLow = 0,
27 kCNGNumParamsNormal = 8,
28 kCNGNumParamsHigh = WEBRTC_CNG_MAX_LPC_ORDER,
29 kCNGNumParamsTooHigh = WEBRTC_CNG_MAX_LPC_ORDER + 1
30 };
31
32 enum { kNoSid, kForceSid };
33
34 class CngTest : public ::testing::Test {
35 protected:
36 virtual void SetUp();
37
38 void TestCngEncode(int sample_rate_hz, int quality);
39
40 int16_t speech_data_[640]; // Max size of CNG internal buffers.
41 };
42
43 class CngDeathTest : public CngTest {};
44
SetUp()45 void CngTest::SetUp() {
46 FILE* input_file;
47 const std::string file_name =
48 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
49 input_file = fopen(file_name.c_str(), "rb");
50 ASSERT_TRUE(input_file != NULL);
51 ASSERT_EQ(640, static_cast<int32_t>(
52 fread(speech_data_, sizeof(int16_t), 640, input_file)));
53 fclose(input_file);
54 input_file = NULL;
55 }
56
TestCngEncode(int sample_rate_hz,int quality)57 void CngTest::TestCngEncode(int sample_rate_hz, int quality) {
58 const size_t num_samples_10ms = rtc::CheckedDivExact(sample_rate_hz, 100);
59 rtc::Buffer sid_data;
60
61 ComfortNoiseEncoder cng_encoder(sample_rate_hz, kSidNormalIntervalUpdate,
62 quality);
63 EXPECT_EQ(0U, cng_encoder.Encode(rtc::ArrayView<const int16_t>(
64 speech_data_, num_samples_10ms),
65 kNoSid, &sid_data));
66 EXPECT_EQ(static_cast<size_t>(quality + 1),
67 cng_encoder.Encode(
68 rtc::ArrayView<const int16_t>(speech_data_, num_samples_10ms),
69 kForceSid, &sid_data));
70 }
71
72 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
73 // Create CNG encoder, init with faulty values, free CNG encoder.
TEST_F(CngDeathTest,CngInitFail)74 TEST_F(CngDeathTest, CngInitFail) {
75 // Call with too few parameters.
76 EXPECT_DEATH(
77 {
78 ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate, kCNGNumParamsLow);
79 },
80 "");
81 // Call with too many parameters.
82 EXPECT_DEATH(
83 {
84 ComfortNoiseEncoder(8000, kSidNormalIntervalUpdate,
85 kCNGNumParamsTooHigh);
86 },
87 "");
88 }
89
90 // Encode Cng with too long input vector.
TEST_F(CngDeathTest,CngEncodeTooLong)91 TEST_F(CngDeathTest, CngEncodeTooLong) {
92 rtc::Buffer sid_data;
93
94 // Create encoder.
95 ComfortNoiseEncoder cng_encoder(8000, kSidNormalIntervalUpdate,
96 kCNGNumParamsNormal);
97 // Run encoder with too much data.
98 EXPECT_DEATH(
99 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 641),
100 kNoSid, &sid_data),
101 "");
102 }
103 #endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
104
TEST_F(CngTest,CngEncode8000)105 TEST_F(CngTest, CngEncode8000) {
106 TestCngEncode(8000, kCNGNumParamsNormal);
107 }
108
TEST_F(CngTest,CngEncode16000)109 TEST_F(CngTest, CngEncode16000) {
110 TestCngEncode(16000, kCNGNumParamsNormal);
111 }
112
TEST_F(CngTest,CngEncode32000)113 TEST_F(CngTest, CngEncode32000) {
114 TestCngEncode(32000, kCNGNumParamsHigh);
115 }
116
TEST_F(CngTest,CngEncode48000)117 TEST_F(CngTest, CngEncode48000) {
118 TestCngEncode(48000, kCNGNumParamsNormal);
119 }
120
TEST_F(CngTest,CngEncode64000)121 TEST_F(CngTest, CngEncode64000) {
122 TestCngEncode(64000, kCNGNumParamsNormal);
123 }
124
125 // Update SID parameters, for both 9 and 16 parameters.
TEST_F(CngTest,CngUpdateSid)126 TEST_F(CngTest, CngUpdateSid) {
127 rtc::Buffer sid_data;
128
129 // Create and initialize encoder and decoder.
130 ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate,
131 kCNGNumParamsNormal);
132 ComfortNoiseDecoder cng_decoder;
133
134 // Run normal Encode and UpdateSid.
135 EXPECT_EQ(kCNGNumParamsNormal + 1,
136 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
137 kForceSid, &sid_data));
138 cng_decoder.UpdateSid(sid_data);
139
140 // Reinit with new length.
141 cng_encoder.Reset(16000, kSidNormalIntervalUpdate, kCNGNumParamsHigh);
142 cng_decoder.Reset();
143
144 // Expect 0 because of unstable parameters after switching length.
145 EXPECT_EQ(0U,
146 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
147 kForceSid, &sid_data));
148 EXPECT_EQ(
149 kCNGNumParamsHigh + 1,
150 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_ + 160, 160),
151 kForceSid, &sid_data));
152 cng_decoder.UpdateSid(
153 rtc::ArrayView<const uint8_t>(sid_data.data(), kCNGNumParamsNormal + 1));
154 }
155
156 // Update SID parameters, with wrong parameters or without calling decode.
TEST_F(CngTest,CngUpdateSidErroneous)157 TEST_F(CngTest, CngUpdateSidErroneous) {
158 rtc::Buffer sid_data;
159
160 // Encode.
161 ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate,
162 kCNGNumParamsNormal);
163 ComfortNoiseDecoder cng_decoder;
164 EXPECT_EQ(kCNGNumParamsNormal + 1,
165 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
166 kForceSid, &sid_data));
167
168 // First run with valid parameters, then with too many CNG parameters.
169 // The function will operate correctly by only reading the maximum number of
170 // parameters, skipping the extra.
171 EXPECT_EQ(kCNGNumParamsNormal + 1, sid_data.size());
172 cng_decoder.UpdateSid(sid_data);
173
174 // Make sure the input buffer is large enough. Since Encode() appends data, we
175 // need to set the size manually only afterwards, or the buffer will be bigger
176 // than anticipated.
177 sid_data.SetSize(kCNGNumParamsTooHigh + 1);
178 cng_decoder.UpdateSid(sid_data);
179 }
180
181 // Test to generate cng data, by forcing SID. Both normal and faulty condition.
TEST_F(CngTest,CngGenerate)182 TEST_F(CngTest, CngGenerate) {
183 rtc::Buffer sid_data;
184 int16_t out_data[640];
185
186 // Create and initialize encoder and decoder.
187 ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate,
188 kCNGNumParamsNormal);
189 ComfortNoiseDecoder cng_decoder;
190
191 // Normal Encode.
192 EXPECT_EQ(kCNGNumParamsNormal + 1,
193 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
194 kForceSid, &sid_data));
195
196 // Normal UpdateSid.
197 cng_decoder.UpdateSid(sid_data);
198
199 // Two normal Generate, one with new_period.
200 EXPECT_TRUE(cng_decoder.Generate(rtc::ArrayView<int16_t>(out_data, 640), 1));
201 EXPECT_TRUE(cng_decoder.Generate(rtc::ArrayView<int16_t>(out_data, 640), 0));
202
203 // Call Genereate with too much data.
204 EXPECT_FALSE(cng_decoder.Generate(rtc::ArrayView<int16_t>(out_data, 641), 0));
205 }
206
207 // Test automatic SID.
TEST_F(CngTest,CngAutoSid)208 TEST_F(CngTest, CngAutoSid) {
209 rtc::Buffer sid_data;
210
211 // Create and initialize encoder and decoder.
212 ComfortNoiseEncoder cng_encoder(16000, kSidNormalIntervalUpdate,
213 kCNGNumParamsNormal);
214 ComfortNoiseDecoder cng_decoder;
215
216 // Normal Encode, 100 msec, where no SID data should be generated.
217 for (int i = 0; i < 10; i++) {
218 EXPECT_EQ(
219 0U, cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
220 kNoSid, &sid_data));
221 }
222
223 // We have reached 100 msec, and SID data should be generated.
224 EXPECT_EQ(kCNGNumParamsNormal + 1,
225 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
226 kNoSid, &sid_data));
227 }
228
229 // Test automatic SID, with very short interval.
TEST_F(CngTest,CngAutoSidShort)230 TEST_F(CngTest, CngAutoSidShort) {
231 rtc::Buffer sid_data;
232
233 // Create and initialize encoder and decoder.
234 ComfortNoiseEncoder cng_encoder(16000, kSidShortIntervalUpdate,
235 kCNGNumParamsNormal);
236 ComfortNoiseDecoder cng_decoder;
237
238 // First call will never generate SID, unless forced to.
239 EXPECT_EQ(0U,
240 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
241 kNoSid, &sid_data));
242
243 // Normal Encode, 100 msec, SID data should be generated all the time.
244 for (int i = 0; i < 10; i++) {
245 EXPECT_EQ(
246 kCNGNumParamsNormal + 1,
247 cng_encoder.Encode(rtc::ArrayView<const int16_t>(speech_data_, 160),
248 kNoSid, &sid_data));
249 }
250 }
251
252 } // namespace webrtc
253