Home | History | Annotate | Download | only in test
      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