• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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