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/test/TestRedFec.h" 12 13 #include <assert.h> 14 15 #include "webrtc/common.h" 16 #include "webrtc/common_types.h" 17 #include "webrtc/engine_configurations.h" 18 #include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h" 19 #include "webrtc/modules/audio_coding/test/utility.h" 20 #include "webrtc/system_wrappers/include/trace.h" 21 #include "webrtc/test/testsupport/fileutils.h" 22 23 #ifdef SUPPORT_RED_WB 24 #undef SUPPORT_RED_WB 25 #endif 26 27 #ifdef SUPPORT_RED_SWB 28 #undef SUPPORT_RED_SWB 29 #endif 30 31 #ifdef SUPPORT_RED_FB 32 #undef SUPPORT_RED_FB 33 #endif 34 35 namespace webrtc { 36 37 namespace { 38 const char kNameL16[] = "L16"; 39 const char kNamePCMU[] = "PCMU"; 40 const char kNameCN[] = "CN"; 41 const char kNameRED[] = "RED"; 42 43 // These three are only used by code #ifdeffed on WEBRTC_CODEC_G722. 44 #ifdef WEBRTC_CODEC_G722 45 const char kNameISAC[] = "ISAC"; 46 const char kNameG722[] = "G722"; 47 const char kNameOPUS[] = "opus"; 48 #endif 49 } 50 51 TestRedFec::TestRedFec() 52 : _acmA(AudioCodingModule::Create(0)), 53 _acmB(AudioCodingModule::Create(1)), 54 _channelA2B(NULL), 55 _testCntr(0) { 56 } 57 58 TestRedFec::~TestRedFec() { 59 if (_channelA2B != NULL) { 60 delete _channelA2B; 61 _channelA2B = NULL; 62 } 63 } 64 65 void TestRedFec::Perform() { 66 const std::string file_name = webrtc::test::ResourcePath( 67 "audio_coding/testfile32kHz", "pcm"); 68 _inFileA.Open(file_name, 32000, "rb"); 69 70 ASSERT_EQ(0, _acmA->InitializeReceiver()); 71 ASSERT_EQ(0, _acmB->InitializeReceiver()); 72 73 uint8_t numEncoders = _acmA->NumberOfCodecs(); 74 CodecInst myCodecParam; 75 for (uint8_t n = 0; n < numEncoders; n++) { 76 EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam)); 77 // Default number of channels is 2 for opus, so we change to 1 in this test. 78 if (!strcmp(myCodecParam.plname, "opus")) { 79 myCodecParam.channels = 1; 80 } 81 EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam)); 82 } 83 84 // Create and connect the channel 85 _channelA2B = new Channel; 86 _acmA->RegisterTransportCallback(_channelA2B); 87 _channelA2B->RegisterReceiverACM(_acmB.get()); 88 89 EXPECT_EQ(0, RegisterSendCodec('A', kNameL16, 8000)); 90 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 8000)); 91 EXPECT_EQ(0, RegisterSendCodec('A', kNameRED)); 92 EXPECT_EQ(0, SetVAD(true, true, VADAggr)); 93 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 94 EXPECT_TRUE(_acmA->REDStatus()); 95 96 OpenOutFile(_testCntr); 97 Run(); 98 _outFileB.Close(); 99 100 RegisterSendCodec('A', kNamePCMU, 8000); 101 // Switch to another 8 kHz codec, RED should remain switched on. 102 EXPECT_TRUE(_acmA->REDStatus()); 103 OpenOutFile(_testCntr); 104 Run(); 105 _outFileB.Close(); 106 107 #ifndef WEBRTC_CODEC_G722 108 EXPECT_TRUE(false); 109 printf("G722 needs to be activated to run this test\n"); 110 return; 111 #else 112 EXPECT_EQ(0, RegisterSendCodec('A', kNameG722, 16000)); 113 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000)); 114 115 #ifdef SUPPORT_RED_WB 116 // Switch codec, RED should remain. 117 EXPECT_TRUE(_acmA->REDStatus()); 118 #else 119 // Switch to a 16 kHz codec, RED should have been switched off. 120 EXPECT_FALSE(_acmA->REDStatus()); 121 #endif 122 123 OpenOutFile(_testCntr); 124 EXPECT_EQ(0, SetVAD(true, true, VADAggr)); 125 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 126 EXPECT_FALSE(_acmA->REDStatus()); 127 Run(); 128 #ifdef SUPPORT_RED_WB 129 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 130 EXPECT_TRUE(_acmA->REDStatus()); 131 #else 132 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 133 EXPECT_FALSE(_acmA->REDStatus()); 134 #endif 135 Run(); 136 _outFileB.Close(); 137 138 RegisterSendCodec('A', kNameISAC, 16000); 139 140 #ifdef SUPPORT_RED_WB 141 // Switch codec, RED should remain. 142 EXPECT_TRUE(_acmA->REDStatus()); 143 #else 144 EXPECT_FALSE(_acmA->REDStatus()); 145 #endif 146 147 OpenOutFile(_testCntr); 148 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr)); 149 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 150 EXPECT_FALSE(_acmA->REDStatus()); 151 Run(); 152 _outFileB.Close(); 153 154 #ifdef SUPPORT_RED_WB 155 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 156 EXPECT_TRUE(_acmA->REDStatus()); 157 #else 158 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 159 EXPECT_FALSE(_acmA->REDStatus()); 160 #endif 161 OpenOutFile(_testCntr); 162 Run(); 163 _outFileB.Close(); 164 165 RegisterSendCodec('A', kNameISAC, 32000); 166 167 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB) 168 // Switch codec, RED should remain. 169 EXPECT_TRUE(_acmA->REDStatus()); 170 #else 171 // Switch to a 32 kHz codec, RED should have been switched off. 172 EXPECT_FALSE(_acmA->REDStatus()); 173 #endif 174 175 OpenOutFile(_testCntr); 176 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr)); 177 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 178 EXPECT_FALSE(_acmA->REDStatus()); 179 Run(); 180 _outFileB.Close(); 181 182 #ifdef SUPPORT_RED_SWB 183 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 184 EXPECT_TRUE(_acmA->REDStatus()); 185 #else 186 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 187 EXPECT_FALSE(_acmA->REDStatus()); 188 #endif 189 OpenOutFile(_testCntr); 190 Run(); 191 _outFileB.Close(); 192 193 RegisterSendCodec('A', kNameISAC, 32000); 194 EXPECT_EQ(0, SetVAD(false, false, VADNormal)); 195 196 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB) 197 OpenOutFile(_testCntr); 198 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 199 EXPECT_TRUE(_acmA->REDStatus()); 200 Run(); 201 202 RegisterSendCodec('A', kNameISAC, 16000); 203 EXPECT_TRUE(_acmA->REDStatus()); 204 Run(); 205 206 RegisterSendCodec('A', kNameISAC, 32000); 207 EXPECT_TRUE(_acmA->REDStatus()); 208 Run(); 209 210 RegisterSendCodec('A', kNameISAC, 16000); 211 EXPECT_TRUE(_acmA->REDStatus()); 212 Run(); 213 _outFileB.Close(); 214 #else 215 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 216 EXPECT_FALSE(_acmA->REDStatus()); 217 #endif 218 219 _channelA2B->SetFECTestWithPacketLoss(true); 220 // Following tests are under packet losses. 221 222 EXPECT_EQ(0, RegisterSendCodec('A', kNameG722)); 223 EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000)); 224 225 #if defined(SUPPORT_RED_WB) && defined(SUPPORT_RED_SWB) 226 // Switch codec, RED should remain. 227 EXPECT_TRUE(_acmA->REDStatus()); 228 #else 229 // Switch to a 16 kHz codec, RED should have been switched off. 230 EXPECT_FALSE(_acmA->REDStatus()); 231 #endif 232 233 OpenOutFile(_testCntr); 234 EXPECT_EQ(0, SetVAD(true, true, VADAggr)); 235 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 236 EXPECT_FALSE(_acmA->REDStatus()); 237 Run(); 238 _outFileB.Close(); 239 240 #ifdef SUPPORT_RED_WB 241 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 242 EXPECT_TRUE(_acmA->REDStatus()); 243 #else 244 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 245 EXPECT_FALSE(_acmA->REDStatus()); 246 #endif 247 OpenOutFile(_testCntr); 248 Run(); 249 _outFileB.Close(); 250 251 RegisterSendCodec('A', kNameISAC, 16000); 252 253 #ifdef SUPPORT_RED_WB 254 // Switch codec, RED should remain. 255 EXPECT_TRUE(_acmA->REDStatus()); 256 #else 257 // Switch to a 16 kHz codec, RED should have been switched off. 258 EXPECT_FALSE(_acmA->REDStatus()); 259 #endif 260 261 OpenOutFile(_testCntr); 262 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr)); 263 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 264 EXPECT_FALSE(_acmA->REDStatus()); 265 Run(); 266 _outFileB.Close(); 267 #ifdef SUPPORT_RED_WB 268 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 269 EXPECT_TRUE(_acmA->REDStatus()); 270 #else 271 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 272 EXPECT_FALSE(_acmA->REDStatus()); 273 #endif 274 OpenOutFile(_testCntr); 275 Run(); 276 _outFileB.Close(); 277 278 RegisterSendCodec('A', kNameISAC, 32000); 279 280 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB) 281 // Switch codec, RED should remain. 282 EXPECT_TRUE(_acmA->REDStatus()); 283 #else 284 // Switch to a 32 kHz codec, RED should have been switched off. 285 EXPECT_FALSE(_acmA->REDStatus()); 286 #endif 287 288 OpenOutFile(_testCntr); 289 EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr)); 290 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 291 EXPECT_FALSE(_acmA->REDStatus()); 292 #ifdef SUPPORT_RED_SWB 293 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 294 EXPECT_TRUE(_acmA->REDStatus()); 295 #else 296 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 297 EXPECT_FALSE(_acmA->REDStatus()); 298 #endif 299 OpenOutFile(_testCntr); 300 Run(); 301 _outFileB.Close(); 302 303 RegisterSendCodec('A', kNameISAC, 32000); 304 EXPECT_EQ(0, SetVAD(false, false, VADNormal)); 305 #if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB) 306 OpenOutFile(_testCntr); 307 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 308 EXPECT_TRUE(_acmA->REDStatus()); 309 Run(); 310 311 RegisterSendCodec('A', kNameISAC, 16000); 312 EXPECT_TRUE(_acmA->REDStatus()); 313 Run(); 314 315 RegisterSendCodec('A', kNameISAC, 32000); 316 EXPECT_TRUE(_acmA->REDStatus()); 317 Run(); 318 319 RegisterSendCodec('A', kNameISAC, 16000); 320 EXPECT_TRUE(_acmA->REDStatus()); 321 Run(); 322 _outFileB.Close(); 323 #else 324 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 325 EXPECT_FALSE(_acmA->REDStatus()); 326 #endif 327 328 #ifndef WEBRTC_CODEC_OPUS 329 EXPECT_TRUE(false); 330 printf("Opus needs to be activated to run this test\n"); 331 return; 332 #endif 333 334 RegisterSendCodec('A', kNameOPUS, 48000); 335 336 #if defined(SUPPORT_RED_FB) && defined(SUPPORT_RED_SWB) &&\ 337 defined(SUPPORT_RED_WB) 338 // Switch to codec, RED should remain switched on. 339 EXPECT_TRUE(_acmA->REDStatus()); 340 #else 341 EXPECT_FALSE(_acmA->REDStatus()); 342 #endif 343 344 // _channelA2B imposes 25% packet loss rate. 345 EXPECT_EQ(0, _acmA->SetPacketLossRate(25)); 346 347 #ifdef SUPPORT_RED_FB 348 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 349 EXPECT_TRUE(_acmA->REDStatus()); 350 // Codec FEC and RED are mutually exclusive. 351 EXPECT_EQ(-1, _acmA->SetCodecFEC(true)); 352 353 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 354 EXPECT_EQ(0, _acmA->SetCodecFEC(true)); 355 356 // Codec FEC and RED are mutually exclusive. 357 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 358 #else 359 EXPECT_EQ(-1, _acmA->SetREDStatus(true)); 360 EXPECT_FALSE(_acmA->REDStatus()); 361 EXPECT_EQ(0, _acmA->SetCodecFEC(true)); 362 #endif 363 364 EXPECT_TRUE(_acmA->CodecFEC()); 365 OpenOutFile(_testCntr); 366 Run(); 367 368 // Switch to L16 with RED. 369 RegisterSendCodec('A', kNameL16, 8000); 370 EXPECT_EQ(0, SetVAD(false, false, VADNormal)); 371 372 // L16 does not support FEC, so FEC should be turned off automatically. 373 EXPECT_FALSE(_acmA->CodecFEC()); 374 375 EXPECT_EQ(0, _acmA->SetREDStatus(true)); 376 EXPECT_TRUE(_acmA->REDStatus()); 377 Run(); 378 379 // Switch to Opus again. 380 RegisterSendCodec('A', kNameOPUS, 48000); 381 #ifdef SUPPORT_RED_FB 382 // Switch to codec, RED should remain switched on. 383 EXPECT_TRUE(_acmA->REDStatus()); 384 #else 385 EXPECT_FALSE(_acmA->REDStatus()); 386 #endif 387 EXPECT_EQ(0, _acmA->SetREDStatus(false)); 388 EXPECT_EQ(0, _acmA->SetCodecFEC(false)); 389 Run(); 390 391 EXPECT_EQ(0, _acmA->SetCodecFEC(true)); 392 _outFileB.Close(); 393 394 // Codecs does not support internal FEC, cannot enable FEC. 395 RegisterSendCodec('A', kNameG722, 16000); 396 EXPECT_FALSE(_acmA->REDStatus()); 397 EXPECT_EQ(-1, _acmA->SetCodecFEC(true)); 398 EXPECT_FALSE(_acmA->CodecFEC()); 399 400 RegisterSendCodec('A', kNameISAC, 16000); 401 EXPECT_FALSE(_acmA->REDStatus()); 402 EXPECT_EQ(-1, _acmA->SetCodecFEC(true)); 403 EXPECT_FALSE(_acmA->CodecFEC()); 404 405 // Codecs does not support internal FEC, disable FEC does not trigger failure. 406 RegisterSendCodec('A', kNameG722, 16000); 407 EXPECT_FALSE(_acmA->REDStatus()); 408 EXPECT_EQ(0, _acmA->SetCodecFEC(false)); 409 EXPECT_FALSE(_acmA->CodecFEC()); 410 411 RegisterSendCodec('A', kNameISAC, 16000); 412 EXPECT_FALSE(_acmA->REDStatus()); 413 EXPECT_EQ(0, _acmA->SetCodecFEC(false)); 414 EXPECT_FALSE(_acmA->CodecFEC()); 415 416 #endif // defined(WEBRTC_CODEC_G722) 417 } 418 419 int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) { 420 return _acmA->SetVAD(enableDTX, enableVAD, vadMode); 421 } 422 423 int16_t TestRedFec::RegisterSendCodec(char side, const char* codecName, 424 int32_t samplingFreqHz) { 425 std::cout << std::flush; 426 AudioCodingModule* myACM; 427 switch (side) { 428 case 'A': { 429 myACM = _acmA.get(); 430 break; 431 } 432 case 'B': { 433 myACM = _acmB.get(); 434 break; 435 } 436 default: 437 return -1; 438 } 439 440 if (myACM == NULL) { 441 assert(false); 442 return -1; 443 } 444 CodecInst myCodecParam; 445 EXPECT_GT(AudioCodingModule::Codec(codecName, &myCodecParam, 446 samplingFreqHz, 1), -1); 447 EXPECT_GT(myACM->RegisterSendCodec(myCodecParam), -1); 448 449 // Initialization was successful. 450 return 0; 451 } 452 453 void TestRedFec::Run() { 454 AudioFrame audioFrame; 455 int32_t outFreqHzB = _outFileB.SamplingFrequency(); 456 // Set test length to 500 ms (50 blocks of 10 ms each). 457 _inFileA.SetNum10MsBlocksToRead(50); 458 // Fast-forward 1 second (100 blocks) since the file starts with silence. 459 _inFileA.FastForward(100); 460 461 while (!_inFileA.EndOfFile()) { 462 EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0); 463 EXPECT_GE(_acmA->Add10MsData(audioFrame), 0); 464 EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame)); 465 _outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_); 466 } 467 _inFileA.Rewind(); 468 } 469 470 void TestRedFec::OpenOutFile(int16_t test_number) { 471 std::string file_name; 472 std::stringstream file_stream; 473 file_stream << webrtc::test::OutputPath(); 474 file_stream << "TestRedFec_outFile_"; 475 file_stream << test_number << ".pcm"; 476 file_name = file_stream.str(); 477 _outFileB.Open(file_name, 16000, "wb"); 478 } 479 480 } // namespace webrtc 481