/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "TestVADDTX.h" #include "common_types.h" #include "audio_coding_module_typedefs.h" #include "utility.h" #include "engine_configurations.h" #include #include "trace.h" TestVADDTX::TestVADDTX(int testMode): _acmA(NULL), _acmB(NULL), _channelA2B(NULL), _testResults(0) { //testMode == 1 for more extensive testing //testMode == 0 for quick test (autotest) _testMode = testMode; } using namespace std; TestVADDTX::~TestVADDTX() { if(_acmA != NULL) { AudioCodingModule::Destroy(_acmA); _acmA = NULL; } if(_acmB != NULL) { AudioCodingModule::Destroy(_acmB); _acmB = NULL; } if(_channelA2B != NULL) { delete _channelA2B; _channelA2B = NULL; } } void TestVADDTX::Perform() { if(_testMode == 0) { printf("Running VAD/DTX Test"); WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceAudioCoding, -1, "---------- TestVADDTX ----------"); } char fileName[] = "./modules/audio_coding/main/test/testfile32kHz.pcm"; _inFileA.Open(fileName, 32000, "rb"); _acmA = AudioCodingModule::Create(0); _acmB = AudioCodingModule::Create(1); _acmA->InitializeReceiver(); _acmB->InitializeReceiver(); WebRtc_UWord8 numEncoders = _acmA->NumberOfCodecs(); CodecInst myCodecParam; if(_testMode != 0) { printf("Registering codecs at receiver... \n"); } for(WebRtc_UWord8 n = 0; n < numEncoders; n++) { _acmB->Codec(n, myCodecParam); if(_testMode != 0) { printf("%s\n", myCodecParam.plname); } _acmB->RegisterReceiveCodec(myCodecParam); } // Create and connect the channel _channelA2B = new Channel; _acmA->RegisterTransportCallback(_channelA2B); _channelA2B->RegisterReceiverACM(_acmB); _acmA->RegisterVADCallback(&_monitor); WebRtc_Word16 testCntr = 1; VADDTXstruct setDTX, getDTX, expectedDTX; bool dtxReplaced; WebRtc_Word16 testResults = 0; #ifdef WEBRTC_CODEC_ISAC // Open outputfile OpenOutFile(testCntr++); // Register iSAC WB as send codec char nameISAC[] = "ISAC"; RegisterSendCodec('A', nameISAC, 16000); // Run the five test cased runTestCases(); // Close file _outFileB.Close(); // Open outputfile OpenOutFile(testCntr++); // Register iSAC SWB as send codec RegisterSendCodec('A', nameISAC, 32000); // Run the five test cased runTestCases(); // Close file _outFileB.Close(); #endif #ifdef WEBRTC_CODEC_ILBC // Open outputfile OpenOutFile(testCntr++); // Register iLBC as send codec char nameILBC[] = "ilbc"; RegisterSendCodec('A', nameILBC); // Run the five test cased runTestCases(); // Close file _outFileB.Close(); #endif if(_testMode) { printf("Done!\n"); } printf("VAD/DTX test completed with %d subtests failed\n", testResults); if (testResults > 0) { printf("Press return\n\n", testResults); getchar(); } } void TestVADDTX::runTestCases() { if(_testMode != 0) { CodecInst myCodecParam; _acmA->SendCodec(myCodecParam); printf("%s\n", myCodecParam.plname); } else { printf("."); } // #1 DTX = OFF, VAD = ON, VADNormal if(_testMode != 0) printf("Test #1 "); SetVAD(false, true, VADNormal); Run(); _testResults += VerifyTest(); // #2 DTX = OFF, VAD = ON, VADAggr if(_testMode != 0) printf("Test #2 "); SetVAD(false, true, VADAggr); Run(); _testResults += VerifyTest(); // #3 DTX = ON, VAD = ON, VADLowBitrate if(_testMode != 0) printf("Test #3 "); SetVAD(true, true, VADLowBitrate); Run(); _testResults += VerifyTest(); // #4 DTX = ON, VAD = ON, VADVeryAggr if(_testMode != 0) printf("Test #4 "); SetVAD(true, true, VADVeryAggr); Run(); _testResults += VerifyTest(); // #5 DTX = ON, VAD = OFF, VADNormal if(_testMode != 0) printf("Test #5 "); SetVAD(true, false, VADNormal); Run(); _testResults += VerifyTest(); } void TestVADDTX::runTestInternalDTX() { // #6 DTX = ON, VAD = ON, VADNormal if(_testMode != 0) printf("Test #6 "); SetVAD(true, true, VADNormal); if(_acmA->ReplaceInternalDTXWithWebRtc(true) < 0) { printf("Was not able to replace DTX since CN was not registered\n"); } Run(); _testResults += VerifyTest(); } void TestVADDTX::SetVAD(bool statusDTX, bool statusVAD, WebRtc_Word16 vadMode) { WebRtc_Word32 status; bool dtxEnabled, vadEnabled; ACMVADMode vadModeSet; status = _acmA->SetVAD(statusDTX, statusVAD, (ACMVADMode) vadMode); status = _acmA->VAD(dtxEnabled, vadEnabled, vadModeSet); if(_testMode != 0) { if(statusDTX != dtxEnabled) { printf("DTX: %s not the same as requested: %s\n", dtxEnabled? "ON":"OFF", dtxEnabled? "OFF":"ON"); } if((statusVAD == true) && (vadEnabled == false) || (statusVAD == false) && (vadEnabled == false) && (statusDTX == true)) { printf("VAD: %s not the same as requested: %s\n", vadEnabled? "ON":"OFF", vadEnabled? "OFF":"ON"); } if(vadModeSet != vadMode) { printf("VAD mode: %d not the same as requested: %d\n", (WebRtc_Word16)vadModeSet, (WebRtc_Word16)vadMode); } } // Requested VAD/DTX settings _setStruct.statusDTX = statusDTX; _setStruct.statusVAD = statusVAD; _setStruct.vadMode = (ACMVADMode) vadMode; // VAD settings after setting VAD in ACM _getStruct.statusDTX = dtxEnabled; _getStruct.statusVAD = vadEnabled; _getStruct.vadMode = vadModeSet; } VADDTXstruct TestVADDTX::GetVAD() { VADDTXstruct retStruct; WebRtc_Word32 status; bool dtxEnabled, vadEnabled; ACMVADMode vadModeSet; status = _acmA->VAD(dtxEnabled, vadEnabled, vadModeSet); retStruct.statusDTX = dtxEnabled; retStruct.statusVAD = vadEnabled; retStruct.vadMode = vadModeSet; return retStruct; } WebRtc_Word16 TestVADDTX::RegisterSendCodec(char side, char* codecName, WebRtc_Word32 samplingFreqHz, WebRtc_Word32 rateKbps) { if(_testMode != 0) { printf("Registering %s for side %c\n", codecName, side); } cout << flush; AudioCodingModule* myACM; switch(side) { case 'A': { myACM = _acmA; break; } case 'B': { myACM = _acmB; break; } default: return -1; } if(myACM == NULL) { return -1; } CodecInst myCodecParam; for(WebRtc_Word16 codecCntr = 0; codecCntr < myACM->NumberOfCodecs(); codecCntr++) { CHECK_ERROR(myACM->Codec((WebRtc_UWord8)codecCntr, myCodecParam)); if(!STR_CASE_CMP(myCodecParam.plname, codecName)) { if((samplingFreqHz == -1) || (myCodecParam.plfreq == samplingFreqHz)) { if((rateKbps == -1) || (myCodecParam.rate == rateKbps)) { break; } } } } CHECK_ERROR(myACM->RegisterSendCodec(myCodecParam)); // initialization was succesful return 0; } void TestVADDTX::Run() { AudioFrame audioFrame; WebRtc_UWord16 SamplesIn10MsecA = _inFileA.PayloadLength10Ms(); WebRtc_UWord32 timestampA = 1; WebRtc_Word32 outFreqHzB = _outFileB.SamplingFrequency(); while(!_inFileA.EndOfFile()) { _inFileA.Read10MsData(audioFrame); audioFrame._timeStamp = timestampA; timestampA += SamplesIn10MsecA; CHECK_ERROR(_acmA->Add10MsData(audioFrame)); CHECK_ERROR(_acmA->Process()); CHECK_ERROR(_acmB->PlayoutData10Ms(outFreqHzB, audioFrame)); _outFileB.Write10MsData(audioFrame._payloadData, audioFrame._payloadDataLengthInSamples); } #ifdef PRINT_STAT _monitor.PrintStatistics(_testMode); #endif _inFileA.Rewind(); _monitor.GetStatistics(_statCounter); _monitor.ResetStatistics(); } void TestVADDTX::OpenOutFile(WebRtc_Word16 testNumber) { char fileName[500] = "./modules/audio_coding/main/test/res_tests/testVADDTX_outFile_"; char cntrStr[10]; if(_testMode == 0) { sprintf(fileName, "./modules/audio_coding/main/test/res_autotests/testVADDTX_outFile_"); } sprintf(cntrStr, "%02d.pcm", testNumber); strcat(fileName, cntrStr); _outFileB.Open(fileName, 16000, "wb"); } WebRtc_Word16 TestVADDTX::VerifyTest() { // Verify empty frame result WebRtc_UWord8 statusEF = 0; WebRtc_UWord8 vadPattern = 0; WebRtc_UWord8 emptyFramePattern[6]; CodecInst myCodecParam; _acmA->SendCodec(myCodecParam); bool dtxInUse = true; bool isReplaced = false; if ((STR_CASE_CMP(myCodecParam.plname,"G729") == 0) || (STR_CASE_CMP(myCodecParam.plname,"G723") == 0) || (STR_CASE_CMP(myCodecParam.plname,"AMR") == 0) || (STR_CASE_CMP(myCodecParam.plname,"AMR-wb") == 0) || (STR_CASE_CMP(myCodecParam.plname,"speex") == 0)) { _acmA->IsInternalDTXReplacedWithWebRtc(isReplaced); if (!isReplaced) { dtxInUse = false; } } // Check for error in VAD/DTX settings if (_getStruct.statusDTX != _setStruct.statusDTX){ // DTX status doesn't match expected vadPattern |= 4; } if (_getStruct.statusDTX){ if ((!_getStruct.statusVAD && dtxInUse) || (!dtxInUse && (_getStruct.statusVAD !=_setStruct.statusVAD))) { // Missmatch in VAD setting vadPattern |= 2; } } else { if (_getStruct.statusVAD != _setStruct.statusVAD){ // VAD status doesn't match expected vadPattern |= 2; } } if (_getStruct.vadMode != _setStruct.vadMode){ // VAD Mode doesn't match expected vadPattern |= 1; } // Set expected empty frame pattern int ii; for (ii = 0; ii < 6; ii++) { emptyFramePattern[ii] = 0; } emptyFramePattern[0] = 1; // "kNoEncoding", not important to check. Codecs with packetsize != 80 samples will get this output. emptyFramePattern[1] = 1; // Expect to always receive some frames labeled "kActiveNormalEncoded" emptyFramePattern[2] = (((!_getStruct.statusDTX && _getStruct.statusVAD) || (!dtxInUse && _getStruct.statusDTX))); // "kPassiveNormalEncoded" emptyFramePattern[3] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 8000))); // "kPassiveDTXNB" emptyFramePattern[4] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 16000))); // "kPassiveDTXWB" emptyFramePattern[5] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 32000))); // "kPassiveDTXSWB" // Check pattern 1-5 (skip 0) for (int ii = 1; ii < 6; ii++) { if (emptyFramePattern[ii]) { statusEF |= (_statCounter[ii] == 0); } else { statusEF |= (_statCounter[ii] > 0); } } if ((statusEF == 0) && (vadPattern == 0)) { if(_testMode != 0) { printf(" Test OK!\n"); } return 0; } else { if (statusEF) { printf("\t\t\tUnexpected empty frame result!\n"); } if (vadPattern) { printf("\t\t\tUnexpected SetVAD() result!\tDTX: %d\tVAD: %d\tMode: %d\n", (vadPattern >> 2) & 1, (vadPattern >> 1) & 1, vadPattern & 1); } return 1; } } ActivityMonitor::ActivityMonitor() { _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = _counter[5] = 0; } ActivityMonitor::~ActivityMonitor() { } WebRtc_Word32 ActivityMonitor::InFrameType(WebRtc_Word16 frameType) { _counter[frameType]++; return 0; } void ActivityMonitor::PrintStatistics(int testMode) { if(testMode != 0) { printf("\n"); printf("kActiveNormalEncoded kPassiveNormalEncoded kPassiveDTXWB kPassiveDTXNB kPassiveDTXSWB kFrameEmpty\n"); printf("%19u", _counter[1]); printf("%22u", _counter[2]); printf("%14u", _counter[3]); printf("%14u", _counter[4]); printf("%14u", _counter[5]); printf("%11u", _counter[0]); printf("\n\n"); } } void ActivityMonitor::ResetStatistics() { _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = _counter[5] = 0; } void ActivityMonitor::GetStatistics(WebRtc_UWord32* getCounter) { for (int ii = 0; ii < 6; ii++) { getCounter[ii] = _counter[ii]; } }