1 /* 2 * Copyright (c) 2012 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 11 #include "webrtc/modules/audio_coding/main/test/TestVADDTX.h" 12 13 #include <iostream> 14 15 #include "webrtc/common_types.h" 16 #include "webrtc/engine_configurations.h" 17 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" 18 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h" 19 #include "webrtc/modules/audio_coding/main/test/utility.h" 20 #include "webrtc/system_wrappers/interface/trace.h" 21 #include "webrtc/test/testsupport/fileutils.h" 22 23 namespace webrtc { 24 25 TestVADDTX::TestVADDTX() 26 : _acmA(AudioCodingModule::Create(0)), 27 _acmB(AudioCodingModule::Create(1)), 28 _channelA2B(NULL) {} 29 30 TestVADDTX::~TestVADDTX() { 31 if (_channelA2B != NULL) { 32 delete _channelA2B; 33 _channelA2B = NULL; 34 } 35 } 36 37 void TestVADDTX::Perform() { 38 const std::string file_name = webrtc::test::ResourcePath( 39 "audio_coding/testfile32kHz", "pcm"); 40 _inFileA.Open(file_name, 32000, "rb"); 41 42 EXPECT_EQ(0, _acmA->InitializeReceiver()); 43 EXPECT_EQ(0, _acmB->InitializeReceiver()); 44 45 uint8_t numEncoders = _acmA->NumberOfCodecs(); 46 CodecInst myCodecParam; 47 for (uint8_t n = 0; n < numEncoders; n++) { 48 EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam)); 49 if (!strcmp(myCodecParam.plname, "opus")) { 50 // Register Opus as mono. 51 myCodecParam.channels = 1; 52 } 53 EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam)); 54 } 55 56 // Create and connect the channel 57 _channelA2B = new Channel; 58 _acmA->RegisterTransportCallback(_channelA2B); 59 _channelA2B->RegisterReceiverACM(_acmB.get()); 60 61 _acmA->RegisterVADCallback(&_monitor); 62 63 int16_t testCntr = 1; 64 65 #ifdef WEBRTC_CODEC_ISAC 66 // Open outputfile 67 OpenOutFile(testCntr++); 68 69 // Register iSAC WB as send codec 70 char nameISAC[] = "ISAC"; 71 RegisterSendCodec('A', nameISAC, 16000); 72 73 // Run the five test cased 74 runTestCases(); 75 76 // Close file 77 _outFileB.Close(); 78 79 // Open outputfile 80 OpenOutFile(testCntr++); 81 82 // Register iSAC SWB as send codec 83 RegisterSendCodec('A', nameISAC, 32000); 84 85 // Run the five test cased 86 runTestCases(); 87 88 // Close file 89 _outFileB.Close(); 90 #endif 91 #ifdef WEBRTC_CODEC_ILBC 92 // Open outputfile 93 OpenOutFile(testCntr++); 94 95 // Register iLBC as send codec 96 char nameILBC[] = "ilbc"; 97 RegisterSendCodec('A', nameILBC); 98 99 // Run the five test cased 100 runTestCases(); 101 102 // Close file 103 _outFileB.Close(); 104 105 #endif 106 #ifdef WEBRTC_CODEC_OPUS 107 // Open outputfile 108 OpenOutFile(testCntr++); 109 110 // Register Opus as send codec 111 char nameOPUS[] = "opus"; 112 RegisterSendCodec('A', nameOPUS); 113 114 // Run the five test cased 115 runTestCases(); 116 117 // Close file 118 _outFileB.Close(); 119 120 #endif 121 } 122 123 void TestVADDTX::runTestCases() { 124 // #1 DTX = OFF, VAD = ON, VADNormal 125 SetVAD(false, true, VADNormal); 126 Run(); 127 VerifyTest(); 128 129 // #2 DTX = OFF, VAD = ON, VADAggr 130 SetVAD(false, true, VADAggr); 131 Run(); 132 VerifyTest(); 133 134 // #3 DTX = ON, VAD = ON, VADLowBitrate 135 SetVAD(true, true, VADLowBitrate); 136 Run(); 137 VerifyTest(); 138 139 // #4 DTX = ON, VAD = ON, VADVeryAggr 140 SetVAD(true, true, VADVeryAggr); 141 Run(); 142 VerifyTest(); 143 144 // #5 DTX = ON, VAD = OFF, VADNormal 145 SetVAD(true, false, VADNormal); 146 Run(); 147 VerifyTest(); 148 } 149 150 void TestVADDTX::runTestInternalDTX(int expected_result) { 151 // #6 DTX = ON, VAD = ON, VADNormal 152 SetVAD(true, true, VADNormal); 153 EXPECT_EQ(expected_result, _acmA->ReplaceInternalDTXWithWebRtc(true)); 154 if (expected_result == 0) { 155 Run(); 156 VerifyTest(); 157 } 158 } 159 160 void TestVADDTX::SetVAD(bool statusDTX, bool statusVAD, int16_t vadMode) { 161 bool dtxEnabled, vadEnabled; 162 ACMVADMode vadModeSet; 163 164 EXPECT_EQ(0, _acmA->SetVAD(statusDTX, statusVAD, (ACMVADMode) vadMode)); 165 EXPECT_EQ(0, _acmA->VAD(&dtxEnabled, &vadEnabled, &vadModeSet)); 166 167 // Requested VAD/DTX settings 168 _setStruct.statusDTX = statusDTX; 169 _setStruct.statusVAD = statusVAD; 170 _setStruct.vadMode = (ACMVADMode) vadMode; 171 172 // VAD settings after setting VAD in ACM 173 _getStruct.statusDTX = dtxEnabled; 174 _getStruct.statusVAD = vadEnabled; 175 _getStruct.vadMode = vadModeSet; 176 } 177 178 VADDTXstruct TestVADDTX::GetVAD() { 179 VADDTXstruct retStruct; 180 bool dtxEnabled, vadEnabled; 181 ACMVADMode vadModeSet; 182 183 EXPECT_EQ(0, _acmA->VAD(&dtxEnabled, &vadEnabled, &vadModeSet)); 184 185 retStruct.statusDTX = dtxEnabled; 186 retStruct.statusVAD = vadEnabled; 187 retStruct.vadMode = vadModeSet; 188 return retStruct; 189 } 190 191 int16_t TestVADDTX::RegisterSendCodec(char side, char* codecName, 192 int32_t samplingFreqHz, 193 int32_t rateKbps) { 194 std::cout << std::flush; 195 AudioCodingModule* myACM; 196 switch (side) { 197 case 'A': { 198 myACM = _acmA.get(); 199 break; 200 } 201 case 'B': { 202 myACM = _acmB.get(); 203 break; 204 } 205 default: 206 return -1; 207 } 208 209 if (myACM == NULL) { 210 return -1; 211 } 212 213 CodecInst myCodecParam; 214 for (int16_t codecCntr = 0; codecCntr < myACM->NumberOfCodecs(); 215 codecCntr++) { 216 EXPECT_EQ(0, myACM->Codec((uint8_t) codecCntr, &myCodecParam)); 217 if (!STR_CASE_CMP(myCodecParam.plname, codecName)) { 218 if ((samplingFreqHz == -1) || (myCodecParam.plfreq == samplingFreqHz)) { 219 if ((rateKbps == -1) || (myCodecParam.rate == rateKbps)) { 220 break; 221 } 222 } 223 } 224 } 225 226 // We only allow VAD/DTX when sending mono. 227 myCodecParam.channels = 1; 228 EXPECT_EQ(0, myACM->RegisterSendCodec(myCodecParam)); 229 230 // initialization was succesful 231 return 0; 232 } 233 234 void TestVADDTX::Run() { 235 AudioFrame audioFrame; 236 237 uint16_t SamplesIn10MsecA = _inFileA.PayloadLength10Ms(); 238 uint32_t timestampA = 1; 239 int32_t outFreqHzB = _outFileB.SamplingFrequency(); 240 241 while (!_inFileA.EndOfFile()) { 242 _inFileA.Read10MsData(audioFrame); 243 audioFrame.timestamp_ = timestampA; 244 timestampA += SamplesIn10MsecA; 245 EXPECT_EQ(0, _acmA->Add10MsData(audioFrame)); 246 EXPECT_GT(_acmA->Process(), -1); 247 EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame)); 248 _outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_); 249 } 250 #ifdef PRINT_STAT 251 _monitor.PrintStatistics(); 252 #endif 253 _inFileA.Rewind(); 254 _monitor.GetStatistics(_statCounter); 255 _monitor.ResetStatistics(); 256 } 257 258 void TestVADDTX::OpenOutFile(int16_t test_number) { 259 std::string file_name; 260 std::stringstream file_stream; 261 file_stream << webrtc::test::OutputPath(); 262 file_stream << "testVADDTX_outFile_"; 263 file_stream << test_number << ".pcm"; 264 file_name = file_stream.str(); 265 _outFileB.Open(file_name, 16000, "wb"); 266 } 267 268 int16_t TestVADDTX::VerifyTest() { 269 // Verify empty frame result 270 uint8_t statusEF = 0; 271 uint8_t vadPattern = 0; 272 uint8_t emptyFramePattern[6]; 273 CodecInst myCodecParam; 274 _acmA->SendCodec(&myCodecParam); 275 bool dtxInUse = true; 276 bool isReplaced = false; 277 if ((STR_CASE_CMP(myCodecParam.plname, "G729") == 0) 278 || (STR_CASE_CMP(myCodecParam.plname, "G723") == 0) 279 || (STR_CASE_CMP(myCodecParam.plname, "AMR") == 0) 280 || (STR_CASE_CMP(myCodecParam.plname, "AMR-wb") == 0) 281 || (STR_CASE_CMP(myCodecParam.plname, "speex") == 0)) { 282 _acmA->IsInternalDTXReplacedWithWebRtc(&isReplaced); 283 if (!isReplaced) { 284 dtxInUse = false; 285 } 286 } else if (STR_CASE_CMP(myCodecParam.plname, "opus") == 0) { 287 if (_getStruct.statusDTX != false) { 288 // DTX status doesn't match expected. 289 vadPattern |= 4; 290 } else if (_getStruct.statusVAD != false) { 291 // Mismatch in VAD setting. 292 vadPattern |= 2; 293 } else { 294 _setStruct.statusDTX = false; 295 _setStruct.statusVAD = false; 296 } 297 } 298 299 // Check for error in VAD/DTX settings 300 if (_getStruct.statusDTX != _setStruct.statusDTX) { 301 // DTX status doesn't match expected 302 vadPattern |= 4; 303 } 304 if (_getStruct.statusDTX) { 305 if ((!_getStruct.statusVAD && dtxInUse) 306 || (!dtxInUse && (_getStruct.statusVAD != _setStruct.statusVAD))) { 307 // Missmatch in VAD setting 308 vadPattern |= 2; 309 } 310 } else { 311 if (_getStruct.statusVAD != _setStruct.statusVAD) { 312 // VAD status doesn't match expected 313 vadPattern |= 2; 314 } 315 } 316 if (_getStruct.vadMode != _setStruct.vadMode) { 317 // VAD Mode doesn't match expected 318 vadPattern |= 1; 319 } 320 321 // Set expected empty frame pattern 322 int ii; 323 for (ii = 0; ii < 6; ii++) { 324 emptyFramePattern[ii] = 0; 325 } 326 // 0 - "kNoEncoding", not important to check. 327 // Codecs with packetsize != 80 samples will get this output. 328 // 1 - "kActiveNormalEncoded", expect to receive some frames with this label . 329 // 2 - "kPassiveNormalEncoded". 330 // 3 - "kPassiveDTXNB". 331 // 4 - "kPassiveDTXWB". 332 // 5 - "kPassiveDTXSWB". 333 emptyFramePattern[0] = 1; 334 emptyFramePattern[1] = 1; 335 emptyFramePattern[2] = (((!_getStruct.statusDTX && _getStruct.statusVAD) 336 || (!dtxInUse && _getStruct.statusDTX))); 337 emptyFramePattern[3] = ((_getStruct.statusDTX && dtxInUse 338 && (_acmA->SendFrequency() == 8000))); 339 emptyFramePattern[4] = ((_getStruct.statusDTX && dtxInUse 340 && (_acmA->SendFrequency() == 16000))); 341 emptyFramePattern[5] = ((_getStruct.statusDTX && dtxInUse 342 && (_acmA->SendFrequency() == 32000))); 343 344 // Check pattern 1-5 (skip 0) 345 for (int ii = 1; ii < 6; ii++) { 346 if (emptyFramePattern[ii]) { 347 statusEF |= (_statCounter[ii] == 0); 348 } else { 349 statusEF |= (_statCounter[ii] > 0); 350 } 351 } 352 EXPECT_EQ(0, statusEF); 353 EXPECT_EQ(0, vadPattern); 354 355 return 0; 356 } 357 358 ActivityMonitor::ActivityMonitor() { 359 _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = 360 _counter[5] = 0; 361 } 362 363 ActivityMonitor::~ActivityMonitor() { 364 } 365 366 int32_t ActivityMonitor::InFrameType(int16_t frameType) { 367 _counter[frameType]++; 368 return 0; 369 } 370 371 void ActivityMonitor::PrintStatistics() { 372 printf("\n"); 373 printf("kActiveNormalEncoded kPassiveNormalEncoded kPassiveDTXWB "); 374 printf("kPassiveDTXNB kPassiveDTXSWB kFrameEmpty\n"); 375 printf("%19u", _counter[1]); 376 printf("%22u", _counter[2]); 377 printf("%14u", _counter[3]); 378 printf("%14u", _counter[4]); 379 printf("%14u", _counter[5]); 380 printf("%11u", _counter[0]); 381 printf("\n\n"); 382 } 383 384 void ActivityMonitor::ResetStatistics() { 385 _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = 386 _counter[5] = 0; 387 } 388 389 void ActivityMonitor::GetStatistics(uint32_t* getCounter) { 390 for (int ii = 0; ii < 6; ii++) { 391 getCounter[ii] = _counter[ii]; 392 } 393 } 394 395 } // namespace webrtc 396