blob: 567903b26d9b40c046e6bce44e15d147f4ae15aa [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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 "TestVADDTX.h"
12
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <iostream>
kjellander@webrtc.org5490c712011-12-21 13:34:18 +000014
15#include "audio_coding_module_typedefs.h"
16#include "common_types.h"
17#include "engine_configurations.h"
18#include "testsupport/fileutils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include "trace.h"
kjellander@webrtc.org5490c712011-12-21 13:34:18 +000020#include "utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000021
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000022namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000023
24TestVADDTX::TestVADDTX(int testMode):
25_acmA(NULL),
26_acmB(NULL),
27_channelA2B(NULL),
28_testResults(0)
29{
30 //testMode == 1 for more extensive testing
31 //testMode == 0 for quick test (autotest)
32 _testMode = testMode;
33}
34
niklase@google.com470e71d2011-07-07 08:21:25 +000035TestVADDTX::~TestVADDTX()
36{
37 if(_acmA != NULL)
38 {
39 AudioCodingModule::Destroy(_acmA);
40 _acmA = NULL;
41 }
42 if(_acmB != NULL)
43 {
44 AudioCodingModule::Destroy(_acmB);
45 _acmB = NULL;
46 }
47 if(_channelA2B != NULL)
48 {
49 delete _channelA2B;
50 _channelA2B = NULL;
51 }
52}
53
54void TestVADDTX::Perform()
55{
niklase@google.com470e71d2011-07-07 08:21:25 +000056 if(_testMode == 0)
57 {
58 printf("Running VAD/DTX Test");
59 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceAudioCoding, -1,
60 "---------- TestVADDTX ----------");
61 }
tina.legrand@webrtc.orgba468042012-08-17 10:38:28 +000062
63 const std::string file_name =
64 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
65 _inFileA.Open(file_name, 32000, "rb");
niklase@google.com470e71d2011-07-07 08:21:25 +000066
67 _acmA = AudioCodingModule::Create(0);
68 _acmB = AudioCodingModule::Create(1);
69
70 _acmA->InitializeReceiver();
71 _acmB->InitializeReceiver();
72
73 WebRtc_UWord8 numEncoders = _acmA->NumberOfCodecs();
74 CodecInst myCodecParam;
75 if(_testMode != 0)
76 {
77 printf("Registering codecs at receiver... \n");
78 }
79 for(WebRtc_UWord8 n = 0; n < numEncoders; n++)
80 {
81 _acmB->Codec(n, myCodecParam);
82 if(_testMode != 0)
83 {
84 printf("%s\n", myCodecParam.plname);
85 }
tina.legrand@webrtc.orgc4590582012-11-28 12:23:29 +000086 if (!strcmp(myCodecParam.plname, "opus")) {
87 // Use mono decoding for Opus in the VAD/DTX test.
88 myCodecParam.channels = 1;
89 }
niklase@google.com470e71d2011-07-07 08:21:25 +000090 _acmB->RegisterReceiveCodec(myCodecParam);
91 }
92
93 // Create and connect the channel
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +000094 _channelA2B = new Channel;
niklase@google.com470e71d2011-07-07 08:21:25 +000095 _acmA->RegisterTransportCallback(_channelA2B);
96 _channelA2B->RegisterReceiverACM(_acmB);
97
98 _acmA->RegisterVADCallback(&_monitor);
99
100
101 WebRtc_Word16 testCntr = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000102 WebRtc_Word16 testResults = 0;
103
104#ifdef WEBRTC_CODEC_ISAC
105 // Open outputfile
106 OpenOutFile(testCntr++);
107
108 // Register iSAC WB as send codec
109 char nameISAC[] = "ISAC";
110 RegisterSendCodec('A', nameISAC, 16000);
111
112 // Run the five test cased
113 runTestCases();
114
115 // Close file
116 _outFileB.Close();
117
118 // Open outputfile
119 OpenOutFile(testCntr++);
120
121 // Register iSAC SWB as send codec
122 RegisterSendCodec('A', nameISAC, 32000);
123
124 // Run the five test cased
125 runTestCases();
126
127 // Close file
128 _outFileB.Close();
129#endif
130#ifdef WEBRTC_CODEC_ILBC
131 // Open outputfile
132 OpenOutFile(testCntr++);
133
134 // Register iLBC as send codec
135 char nameILBC[] = "ilbc";
136 RegisterSendCodec('A', nameILBC);
137
138 // Run the five test cased
139 runTestCases();
140
141 // Close file
142 _outFileB.Close();
143
144#endif
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +0000145#ifdef WEBRTC_CODEC_OPUS
146 // Open outputfile
147 OpenOutFile(testCntr++);
148
149 // Register Opus as send codec
150 char nameOPUS[] = "opus";
151 RegisterSendCodec('A', nameOPUS);
152
153 // Run the five test cased
154 runTestCases();
155
156 // Close file
157 _outFileB.Close();
158
159#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000160 if(_testMode) {
161 printf("Done!\n");
162 }
163
164 printf("VAD/DTX test completed with %d subtests failed\n", testResults);
165 if (testResults > 0)
166 {
tina.legrand@webrtc.org2e096922011-08-18 06:20:30 +0000167 printf("Press return\n\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 getchar();
169 }
170}
171
172void TestVADDTX::runTestCases()
173{
174 if(_testMode != 0)
175 {
176 CodecInst myCodecParam;
177 _acmA->SendCodec(myCodecParam);
178 printf("%s\n", myCodecParam.plname);
179 }
180 else
181 {
182 printf(".");
183 }
184 // #1 DTX = OFF, VAD = ON, VADNormal
185 if(_testMode != 0)
186 printf("Test #1 ");
187 SetVAD(false, true, VADNormal);
188 Run();
189 _testResults += VerifyTest();
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000190
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 // #2 DTX = OFF, VAD = ON, VADAggr
192 if(_testMode != 0)
193 printf("Test #2 ");
194 SetVAD(false, true, VADAggr);
195 Run();
196 _testResults += VerifyTest();
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000197
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 // #3 DTX = ON, VAD = ON, VADLowBitrate
199 if(_testMode != 0)
200 printf("Test #3 ");
201 SetVAD(true, true, VADLowBitrate);
202 Run();
203 _testResults += VerifyTest();
204
205 // #4 DTX = ON, VAD = ON, VADVeryAggr
206 if(_testMode != 0)
207 printf("Test #4 ");
208 SetVAD(true, true, VADVeryAggr);
209 Run();
210 _testResults += VerifyTest();
211
212 // #5 DTX = ON, VAD = OFF, VADNormal
213 if(_testMode != 0)
214 printf("Test #5 ");
215 SetVAD(true, false, VADNormal);
216 Run();
217 _testResults += VerifyTest();
218
219}
220void TestVADDTX::runTestInternalDTX()
221{
222 // #6 DTX = ON, VAD = ON, VADNormal
223 if(_testMode != 0)
224 printf("Test #6 ");
225
226 SetVAD(true, true, VADNormal);
227 if(_acmA->ReplaceInternalDTXWithWebRtc(true) < 0) {
228 printf("Was not able to replace DTX since CN was not registered\n");
229 }
230 Run();
231 _testResults += VerifyTest();
232}
233
234void TestVADDTX::SetVAD(bool statusDTX, bool statusVAD, WebRtc_Word16 vadMode)
235{
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 bool dtxEnabled, vadEnabled;
237 ACMVADMode vadModeSet;
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000238
239 if (_acmA->SetVAD(statusDTX, statusVAD, (ACMVADMode) vadMode) < 0) {
240 assert(false);
241 }
242 if (_acmA->VAD(dtxEnabled, vadEnabled, vadModeSet) < 0) {
243 assert(false);
244 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000245
246 if(_testMode != 0)
247 {
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000248 if(statusDTX != dtxEnabled)
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 {
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000250 printf("DTX: %s not the same as requested: %s\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 dtxEnabled? "ON":"OFF", dtxEnabled? "OFF":"ON");
252 }
tina.legrand@webrtc.org2e096922011-08-18 06:20:30 +0000253 if(((statusVAD == true) && (vadEnabled == false)) ||
254 ((statusVAD == false) && (vadEnabled == false) &&
255 (statusDTX == true)))
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000257 printf("VAD: %s not the same as requested: %s\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 vadEnabled? "ON":"OFF", vadEnabled? "OFF":"ON");
tina.legrand@webrtc.org2e096922011-08-18 06:20:30 +0000259 }
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000260 if(vadModeSet != vadMode)
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 {
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000262 printf("VAD mode: %d not the same as requested: %d\n",
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 (WebRtc_Word16)vadModeSet, (WebRtc_Word16)vadMode);
264 }
265 }
266
267 // Requested VAD/DTX settings
268 _setStruct.statusDTX = statusDTX;
269 _setStruct.statusVAD = statusVAD;
270 _setStruct.vadMode = (ACMVADMode) vadMode;
271
272 // VAD settings after setting VAD in ACM
273 _getStruct.statusDTX = dtxEnabled;
274 _getStruct.statusVAD = vadEnabled;
275 _getStruct.vadMode = vadModeSet;
276
277}
278
279VADDTXstruct TestVADDTX::GetVAD()
280{
281 VADDTXstruct retStruct;
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 bool dtxEnabled, vadEnabled;
283 ACMVADMode vadModeSet;
284
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000285 if (_acmA->VAD(dtxEnabled, vadEnabled, vadModeSet) < 0) {
286 assert(false);
287 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000288
289 retStruct.statusDTX = dtxEnabled;
290 retStruct.statusVAD = vadEnabled;
291 retStruct.vadMode = vadModeSet;
292 return retStruct;
293}
294
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000295WebRtc_Word16 TestVADDTX::RegisterSendCodec(char side,
296 char* codecName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 WebRtc_Word32 samplingFreqHz,
298 WebRtc_Word32 rateKbps)
299{
300 if(_testMode != 0)
301 {
302 printf("Registering %s for side %c\n", codecName, side);
303 }
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000304 std::cout << std::flush;
niklase@google.com470e71d2011-07-07 08:21:25 +0000305 AudioCodingModule* myACM;
306 switch(side)
307 {
308 case 'A':
309 {
310 myACM = _acmA;
311 break;
312 }
313 case 'B':
314 {
315 myACM = _acmB;
316 break;
317 }
318 default:
319 return -1;
320 }
321
322 if(myACM == NULL)
323 {
324 return -1;
325 }
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000326
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 CodecInst myCodecParam;
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000328 for(WebRtc_Word16 codecCntr = 0; codecCntr < myACM->NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 codecCntr++)
330 {
331 CHECK_ERROR(myACM->Codec((WebRtc_UWord8)codecCntr, myCodecParam));
332 if(!STR_CASE_CMP(myCodecParam.plname, codecName))
333 {
334 if((samplingFreqHz == -1) || (myCodecParam.plfreq == samplingFreqHz))
335 {
336 if((rateKbps == -1) || (myCodecParam.rate == rateKbps))
337 {
338 break;
339 }
340 }
341 }
342 }
343
tina.legrand@webrtc.orgc4590582012-11-28 12:23:29 +0000344 // We only allow VAD/DTX when sending mono.
345 myCodecParam.channels = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 CHECK_ERROR(myACM->RegisterSendCodec(myCodecParam));
347
348 // initialization was succesful
349 return 0;
350}
351
352void TestVADDTX::Run()
353{
354 AudioFrame audioFrame;
355
356 WebRtc_UWord16 SamplesIn10MsecA = _inFileA.PayloadLength10Ms();
357 WebRtc_UWord32 timestampA = 1;
358 WebRtc_Word32 outFreqHzB = _outFileB.SamplingFrequency();
359
360 while(!_inFileA.EndOfFile())
361 {
362 _inFileA.Read10MsData(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000363 audioFrame.timestamp_ = timestampA;
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 timestampA += SamplesIn10MsecA;
365 CHECK_ERROR(_acmA->Add10MsData(audioFrame));
366
367 CHECK_ERROR(_acmA->Process());
368
369 CHECK_ERROR(_acmB->PlayoutData10Ms(outFreqHzB, audioFrame));
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000370 _outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000371 }
372#ifdef PRINT_STAT
373 _monitor.PrintStatistics(_testMode);
374#endif
375 _inFileA.Rewind();
376 _monitor.GetStatistics(_statCounter);
377 _monitor.ResetStatistics();
378}
379
tina.legrand@webrtc.orgba468042012-08-17 10:38:28 +0000380void TestVADDTX::OpenOutFile(WebRtc_Word16 test_number) {
381 std::string file_name;
382 std::stringstream file_stream;
383 file_stream << webrtc::test::OutputPath();
384 if (_testMode == 0) {
385 file_stream << "testVADDTX_autoFile_";
386 } else {
387 file_stream << "testVADDTX_outFile_";
388 }
389 file_stream << test_number << ".pcm";
390 file_name = file_stream.str();
391 _outFileB.Open(file_name, 16000, "wb");
niklase@google.com470e71d2011-07-07 08:21:25 +0000392}
393
394
395WebRtc_Word16 TestVADDTX::VerifyTest()
396{
397 // Verify empty frame result
398 WebRtc_UWord8 statusEF = 0;
399 WebRtc_UWord8 vadPattern = 0;
400 WebRtc_UWord8 emptyFramePattern[6];
401 CodecInst myCodecParam;
402 _acmA->SendCodec(myCodecParam);
403 bool dtxInUse = true;
404 bool isReplaced = false;
405 if ((STR_CASE_CMP(myCodecParam.plname,"G729") == 0) ||
406 (STR_CASE_CMP(myCodecParam.plname,"G723") == 0) ||
407 (STR_CASE_CMP(myCodecParam.plname,"AMR") == 0) ||
408 (STR_CASE_CMP(myCodecParam.plname,"AMR-wb") == 0) ||
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000409 (STR_CASE_CMP(myCodecParam.plname,"speex") == 0))
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 {
411 _acmA->IsInternalDTXReplacedWithWebRtc(isReplaced);
412 if (!isReplaced)
413 {
414 dtxInUse = false;
415 }
416 }
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000417
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 // Check for error in VAD/DTX settings
419 if (_getStruct.statusDTX != _setStruct.statusDTX){
420 // DTX status doesn't match expected
421 vadPattern |= 4;
422 }
423 if (_getStruct.statusDTX){
424 if ((!_getStruct.statusVAD && dtxInUse) || (!dtxInUse && (_getStruct.statusVAD !=_setStruct.statusVAD)))
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000425 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 // Missmatch in VAD setting
427 vadPattern |= 2;
428 }
429 } else {
430 if (_getStruct.statusVAD != _setStruct.statusVAD){
phoglund@webrtc.orgd1a860b2012-01-26 14:49:28 +0000431 // VAD status doesn't match expected
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 vadPattern |= 2;
433 }
434 }
435 if (_getStruct.vadMode != _setStruct.vadMode){
436 // VAD Mode doesn't match expected
437 vadPattern |= 1;
438 }
439
440 // Set expected empty frame pattern
441 int ii;
442 for (ii = 0; ii < 6; ii++) {
443 emptyFramePattern[ii] = 0;
444 }
445 emptyFramePattern[0] = 1; // "kNoEncoding", not important to check. Codecs with packetsize != 80 samples will get this output.
446 emptyFramePattern[1] = 1; // Expect to always receive some frames labeled "kActiveNormalEncoded"
447 emptyFramePattern[2] = (((!_getStruct.statusDTX && _getStruct.statusVAD) || (!dtxInUse && _getStruct.statusDTX))); // "kPassiveNormalEncoded"
448 emptyFramePattern[3] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 8000))); // "kPassiveDTXNB"
449 emptyFramePattern[4] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 16000))); // "kPassiveDTXWB"
450 emptyFramePattern[5] = ((_getStruct.statusDTX && dtxInUse && (_acmA->SendFrequency() == 32000))); // "kPassiveDTXSWB"
451
452 // Check pattern 1-5 (skip 0)
453 for (int ii = 1; ii < 6; ii++)
454 {
455 if (emptyFramePattern[ii])
456 {
457 statusEF |= (_statCounter[ii] == 0);
458 }
459 else
460 {
461 statusEF |= (_statCounter[ii] > 0);
462 }
463 }
464 if ((statusEF == 0) && (vadPattern == 0))
465 {
466 if(_testMode != 0)
467 {
468 printf(" Test OK!\n");
469 }
470 return 0;
471 }
472 else
473 {
474 if (statusEF)
475 {
476 printf("\t\t\tUnexpected empty frame result!\n");
477 }
478 if (vadPattern)
479 {
480 printf("\t\t\tUnexpected SetVAD() result!\tDTX: %d\tVAD: %d\tMode: %d\n", (vadPattern >> 2) & 1, (vadPattern >> 1) & 1, vadPattern & 1);
481 }
482 return 1;
483 }
484}
485
486ActivityMonitor::ActivityMonitor()
487{
488 _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = _counter[5] = 0;
489}
490
491ActivityMonitor::~ActivityMonitor()
492{
493}
494
495WebRtc_Word32 ActivityMonitor::InFrameType(WebRtc_Word16 frameType)
496{
497 _counter[frameType]++;
498 return 0;
499}
500
501void ActivityMonitor::PrintStatistics(int testMode)
502{
503 if(testMode != 0)
504 {
505 printf("\n");
506 printf("kActiveNormalEncoded kPassiveNormalEncoded kPassiveDTXWB kPassiveDTXNB kPassiveDTXSWB kFrameEmpty\n");
507
508 printf("%19u", _counter[1]);
509 printf("%22u", _counter[2]);
510 printf("%14u", _counter[3]);
511 printf("%14u", _counter[4]);
512 printf("%14u", _counter[5]);
513 printf("%11u", _counter[0]);
514
515 printf("\n\n");
516 }
517}
518
519void ActivityMonitor::ResetStatistics()
520{
521 _counter[0] = _counter[1] = _counter[2] = _counter[3] = _counter[4] = _counter[5] = 0;
522}
523
524void ActivityMonitor::GetStatistics(WebRtc_UWord32* getCounter)
525{
526 for (int ii = 0; ii < 6; ii++)
527 {
528 getCounter[ii] = _counter[ii];
529 }
530}
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +0000531
532} // namespace webrtc