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