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/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