OLD | NEW |
| (Empty) |
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/APITest.h" | |
12 | |
13 #include <ctype.h> | |
14 #include <stdio.h> | |
15 #include <stdlib.h> | |
16 #include <string.h> | |
17 | |
18 #include <iostream> | |
19 #include <ostream> | |
20 #include <string> | |
21 | |
22 #include "testing/gtest/include/gtest/gtest.h" | |
23 #include "webrtc/base/platform_thread.h" | |
24 #include "webrtc/common.h" | |
25 #include "webrtc/common_types.h" | |
26 #include "webrtc/engine_configurations.h" | |
27 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" | |
28 #include "webrtc/modules/audio_coding/main/test/utility.h" | |
29 #include "webrtc/system_wrappers/include/event_wrapper.h" | |
30 #include "webrtc/system_wrappers/include/tick_util.h" | |
31 #include "webrtc/system_wrappers/include/trace.h" | |
32 #include "webrtc/test/testsupport/fileutils.h" | |
33 | |
34 namespace webrtc { | |
35 | |
36 #define TEST_DURATION_SEC 600 | |
37 #define NUMBER_OF_SENDER_TESTS 6 | |
38 #define MAX_FILE_NAME_LENGTH_BYTE 500 | |
39 #define CHECK_THREAD_NULLITY(myThread, S) \ | |
40 if(myThread != NULL) { \ | |
41 (myThread)->Start(); \ | |
42 } else { \ | |
43 ADD_FAILURE() << S; \ | |
44 } | |
45 | |
46 void APITest::Wait(uint32_t waitLengthMs) { | |
47 if (_randomTest) { | |
48 return; | |
49 } else { | |
50 EventWrapper* myEvent = EventWrapper::Create(); | |
51 myEvent->Wait(waitLengthMs); | |
52 delete myEvent; | |
53 return; | |
54 } | |
55 } | |
56 | |
57 APITest::APITest(const Config& config) | |
58 : _acmA(AudioCodingModule::Create(1)), | |
59 _acmB(AudioCodingModule::Create(2)), | |
60 _channel_A2B(NULL), | |
61 _channel_B2A(NULL), | |
62 _writeToFile(true), | |
63 _pullEventA(NULL), | |
64 _pushEventA(NULL), | |
65 _processEventA(NULL), | |
66 _apiEventA(NULL), | |
67 _pullEventB(NULL), | |
68 _pushEventB(NULL), | |
69 _processEventB(NULL), | |
70 _apiEventB(NULL), | |
71 _codecCntrA(0), | |
72 _codecCntrB(0), | |
73 _thereIsEncoderA(false), | |
74 _thereIsEncoderB(false), | |
75 _thereIsDecoderA(false), | |
76 _thereIsDecoderB(false), | |
77 _sendVADA(false), | |
78 _sendDTXA(false), | |
79 _sendVADModeA(VADNormal), | |
80 _sendVADB(false), | |
81 _sendDTXB(false), | |
82 _sendVADModeB(VADNormal), | |
83 _minDelayA(0), | |
84 _minDelayB(0), | |
85 _dotPositionA(0), | |
86 _dotMoveDirectionA(1), | |
87 _dotPositionB(39), | |
88 _dotMoveDirectionB(-1), | |
89 _vadCallbackA(NULL), | |
90 _vadCallbackB(NULL), | |
91 _apiTestRWLock(*RWLockWrapper::CreateRWLock()), | |
92 _randomTest(false), | |
93 _testNumA(0), | |
94 _testNumB(1) { | |
95 int n; | |
96 for (n = 0; n < 32; n++) { | |
97 _payloadUsed[n] = false; | |
98 } | |
99 | |
100 _movingDot[40] = '\0'; | |
101 | |
102 for (int n = 0; n < 40; n++) { | |
103 _movingDot[n] = ' '; | |
104 } | |
105 } | |
106 | |
107 APITest::~APITest() { | |
108 DELETE_POINTER(_channel_A2B); | |
109 DELETE_POINTER(_channel_B2A); | |
110 | |
111 DELETE_POINTER(_pushEventA); | |
112 DELETE_POINTER(_pullEventA); | |
113 DELETE_POINTER(_processEventA); | |
114 DELETE_POINTER(_apiEventA); | |
115 | |
116 DELETE_POINTER(_pushEventB); | |
117 DELETE_POINTER(_pullEventB); | |
118 DELETE_POINTER(_processEventB); | |
119 DELETE_POINTER(_apiEventB); | |
120 | |
121 _inFileA.Close(); | |
122 _outFileA.Close(); | |
123 | |
124 _inFileB.Close(); | |
125 _outFileB.Close(); | |
126 | |
127 DELETE_POINTER(_vadCallbackA); | |
128 DELETE_POINTER(_vadCallbackB); | |
129 | |
130 delete &_apiTestRWLock; | |
131 } | |
132 | |
133 int16_t APITest::SetUp() { | |
134 CodecInst dummyCodec; | |
135 int lastPayloadType = 0; | |
136 | |
137 int16_t numCodecs = _acmA->NumberOfCodecs(); | |
138 for (uint8_t n = 0; n < numCodecs; n++) { | |
139 AudioCodingModule::Codec(n, &dummyCodec); | |
140 if ((STR_CASE_CMP(dummyCodec.plname, "CN") == 0) | |
141 && (dummyCodec.plfreq == 32000)) { | |
142 continue; | |
143 } | |
144 | |
145 printf("Register Receive Codec %s ", dummyCodec.plname); | |
146 | |
147 if ((n != 0) && !FixedPayloadTypeCodec(dummyCodec.plname)) { | |
148 // Check registration with an already occupied payload type | |
149 int currentPayloadType = dummyCodec.pltype; | |
150 dummyCodec.pltype = 97; //lastPayloadType; | |
151 CHECK_ERROR(_acmB->RegisterReceiveCodec(dummyCodec)); | |
152 dummyCodec.pltype = currentPayloadType; | |
153 } | |
154 | |
155 if ((n < numCodecs - 1) && !FixedPayloadTypeCodec(dummyCodec.plname)) { | |
156 // test if re-registration works; | |
157 CodecInst nextCodec; | |
158 int currentPayloadType = dummyCodec.pltype; | |
159 AudioCodingModule::Codec(n + 1, &nextCodec); | |
160 dummyCodec.pltype = nextCodec.pltype; | |
161 if (!FixedPayloadTypeCodec(nextCodec.plname)) { | |
162 _acmB->RegisterReceiveCodec(dummyCodec); | |
163 } | |
164 dummyCodec.pltype = currentPayloadType; | |
165 } | |
166 | |
167 if ((n < numCodecs - 1) && !FixedPayloadTypeCodec(dummyCodec.plname)) { | |
168 // test if un-registration works; | |
169 CodecInst nextCodec; | |
170 AudioCodingModule::Codec(n + 1, &nextCodec); | |
171 nextCodec.pltype = dummyCodec.pltype; | |
172 if (!FixedPayloadTypeCodec(nextCodec.plname)) { | |
173 CHECK_ERROR_MT(_acmA->RegisterReceiveCodec(nextCodec)); | |
174 CHECK_ERROR_MT(_acmA->UnregisterReceiveCodec(nextCodec.pltype)); | |
175 } | |
176 } | |
177 | |
178 CHECK_ERROR_MT(_acmA->RegisterReceiveCodec(dummyCodec)); | |
179 printf(" side A done!"); | |
180 CHECK_ERROR_MT(_acmB->RegisterReceiveCodec(dummyCodec)); | |
181 printf(" side B done!\n"); | |
182 | |
183 if (!strcmp(dummyCodec.plname, "CN")) { | |
184 CHECK_ERROR_MT(_acmA->RegisterSendCodec(dummyCodec)); | |
185 CHECK_ERROR_MT(_acmB->RegisterSendCodec(dummyCodec)); | |
186 } | |
187 lastPayloadType = dummyCodec.pltype; | |
188 if ((lastPayloadType >= 96) && (lastPayloadType <= 127)) { | |
189 _payloadUsed[lastPayloadType - 96] = true; | |
190 } | |
191 } | |
192 _thereIsDecoderA = true; | |
193 _thereIsDecoderB = true; | |
194 | |
195 // Register Send Codec | |
196 AudioCodingModule::Codec((uint8_t) _codecCntrA, &dummyCodec); | |
197 CHECK_ERROR_MT(_acmA->RegisterSendCodec(dummyCodec)); | |
198 _thereIsEncoderA = true; | |
199 // | |
200 AudioCodingModule::Codec((uint8_t) _codecCntrB, &dummyCodec); | |
201 CHECK_ERROR_MT(_acmB->RegisterSendCodec(dummyCodec)); | |
202 _thereIsEncoderB = true; | |
203 | |
204 uint16_t frequencyHz; | |
205 | |
206 printf("\n\nAPI Test\n"); | |
207 printf("========\n"); | |
208 printf("Hit enter to accept the default values indicated in []\n\n"); | |
209 | |
210 //--- Input A | |
211 std::string file_name = webrtc::test::ResourcePath( | |
212 "audio_coding/testfile32kHz", "pcm"); | |
213 frequencyHz = 32000; | |
214 printf("Enter input file at side A [%s]: ", file_name.c_str()); | |
215 PCMFile::ChooseFile(&file_name, 499, &frequencyHz); | |
216 _inFileA.Open(file_name, frequencyHz, "rb", true); | |
217 | |
218 //--- Output A | |
219 std::string out_file_a = webrtc::test::OutputPath() + "outA.pcm"; | |
220 printf("Enter output file at side A [%s]: ", out_file_a.c_str()); | |
221 PCMFile::ChooseFile(&out_file_a, 499, &frequencyHz); | |
222 _outFileA.Open(out_file_a, frequencyHz, "wb"); | |
223 | |
224 //--- Input B | |
225 file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); | |
226 printf("\n\nEnter input file at side B [%s]: ", file_name.c_str()); | |
227 PCMFile::ChooseFile(&file_name, 499, &frequencyHz); | |
228 _inFileB.Open(file_name, frequencyHz, "rb", true); | |
229 | |
230 //--- Output B | |
231 std::string out_file_b = webrtc::test::OutputPath() + "outB.pcm"; | |
232 printf("Enter output file at side B [%s]: ", out_file_b.c_str()); | |
233 PCMFile::ChooseFile(&out_file_b, 499, &frequencyHz); | |
234 _outFileB.Open(out_file_b, frequencyHz, "wb"); | |
235 | |
236 //--- Set A-to-B channel | |
237 _channel_A2B = new Channel(2); | |
238 CHECK_ERROR_MT(_acmA->RegisterTransportCallback(_channel_A2B)); | |
239 _channel_A2B->RegisterReceiverACM(_acmB.get()); | |
240 | |
241 //--- Set B-to-A channel | |
242 _channel_B2A = new Channel(1); | |
243 CHECK_ERROR_MT(_acmB->RegisterTransportCallback(_channel_B2A)); | |
244 _channel_B2A->RegisterReceiverACM(_acmA.get()); | |
245 | |
246 //--- EVENT TIMERS | |
247 // A | |
248 _pullEventA = EventTimerWrapper::Create(); | |
249 _pushEventA = EventTimerWrapper::Create(); | |
250 _processEventA = EventTimerWrapper::Create(); | |
251 _apiEventA = EventWrapper::Create(); | |
252 // B | |
253 _pullEventB = EventTimerWrapper::Create(); | |
254 _pushEventB = EventTimerWrapper::Create(); | |
255 _processEventB = EventTimerWrapper::Create(); | |
256 _apiEventB = EventWrapper::Create(); | |
257 | |
258 //--- I/O params | |
259 // A | |
260 _outFreqHzA = _outFileA.SamplingFrequency(); | |
261 // B | |
262 _outFreqHzB = _outFileB.SamplingFrequency(); | |
263 | |
264 //Trace::SetEncryptedTraceFile("ACMAPITestEncrypted.txt"); | |
265 | |
266 char print[11]; | |
267 | |
268 // Create a trace file. | |
269 Trace::CreateTrace(); | |
270 Trace::SetTraceFile( | |
271 (webrtc::test::OutputPath() + "acm_api_trace.txt").c_str()); | |
272 | |
273 printf("\nRandom Test (y/n)?"); | |
274 EXPECT_TRUE(fgets(print, 10, stdin) != NULL); | |
275 print[10] = '\0'; | |
276 if (strstr(print, "y") != NULL) { | |
277 _randomTest = true; | |
278 _verbose = false; | |
279 _writeToFile = false; | |
280 } else { | |
281 _randomTest = false; | |
282 printf("\nPrint Tests (y/n)? "); | |
283 EXPECT_TRUE(fgets(print, 10, stdin) != NULL); | |
284 print[10] = '\0'; | |
285 if (strstr(print, "y") == NULL) { | |
286 EXPECT_TRUE(freopen("APITest_log.txt", "w", stdout) != 0); | |
287 _verbose = false; | |
288 } | |
289 } | |
290 | |
291 _vadCallbackA = new VADCallback; | |
292 _vadCallbackB = new VADCallback; | |
293 | |
294 return 0; | |
295 } | |
296 | |
297 bool APITest::PushAudioThreadA(void* obj) { | |
298 return static_cast<APITest*>(obj)->PushAudioRunA(); | |
299 } | |
300 | |
301 bool APITest::PushAudioThreadB(void* obj) { | |
302 return static_cast<APITest*>(obj)->PushAudioRunB(); | |
303 } | |
304 | |
305 bool APITest::PullAudioThreadA(void* obj) { | |
306 return static_cast<APITest*>(obj)->PullAudioRunA(); | |
307 } | |
308 | |
309 bool APITest::PullAudioThreadB(void* obj) { | |
310 return static_cast<APITest*>(obj)->PullAudioRunB(); | |
311 } | |
312 | |
313 bool APITest::ProcessThreadA(void* obj) { | |
314 return static_cast<APITest*>(obj)->ProcessRunA(); | |
315 } | |
316 | |
317 bool APITest::ProcessThreadB(void* obj) { | |
318 return static_cast<APITest*>(obj)->ProcessRunB(); | |
319 } | |
320 | |
321 bool APITest::APIThreadA(void* obj) { | |
322 return static_cast<APITest*>(obj)->APIRunA(); | |
323 } | |
324 | |
325 bool APITest::APIThreadB(void* obj) { | |
326 return static_cast<APITest*>(obj)->APIRunB(); | |
327 } | |
328 | |
329 bool APITest::PullAudioRunA() { | |
330 _pullEventA->Wait(100); | |
331 AudioFrame audioFrame; | |
332 if (_acmA->PlayoutData10Ms(_outFreqHzA, &audioFrame) < 0) { | |
333 bool thereIsDecoder; | |
334 { | |
335 ReadLockScoped rl(_apiTestRWLock); | |
336 thereIsDecoder = _thereIsDecoderA; | |
337 } | |
338 if (thereIsDecoder) { | |
339 fprintf(stderr, "\n>>>>>> cannot pull audio A <<<<<<<< \n"); | |
340 } | |
341 } else { | |
342 if (_writeToFile) { | |
343 _outFileA.Write10MsData(audioFrame); | |
344 } | |
345 } | |
346 return true; | |
347 } | |
348 | |
349 bool APITest::PullAudioRunB() { | |
350 _pullEventB->Wait(100); | |
351 AudioFrame audioFrame; | |
352 if (_acmB->PlayoutData10Ms(_outFreqHzB, &audioFrame) < 0) { | |
353 bool thereIsDecoder; | |
354 { | |
355 ReadLockScoped rl(_apiTestRWLock); | |
356 thereIsDecoder = _thereIsDecoderB; | |
357 } | |
358 if (thereIsDecoder) { | |
359 fprintf(stderr, "\n>>>>>> cannot pull audio B <<<<<<<< \n"); | |
360 fprintf(stderr, "%d %d\n", _testNumA, _testNumB); | |
361 } | |
362 } else { | |
363 if (_writeToFile) { | |
364 _outFileB.Write10MsData(audioFrame); | |
365 } | |
366 } | |
367 return true; | |
368 } | |
369 | |
370 bool APITest::PushAudioRunA() { | |
371 _pushEventA->Wait(100); | |
372 AudioFrame audioFrame; | |
373 _inFileA.Read10MsData(audioFrame); | |
374 if (_acmA->Add10MsData(audioFrame) < 0) { | |
375 bool thereIsEncoder; | |
376 { | |
377 ReadLockScoped rl(_apiTestRWLock); | |
378 thereIsEncoder = _thereIsEncoderA; | |
379 } | |
380 if (thereIsEncoder) { | |
381 fprintf(stderr, "\n>>>> add10MsData at A failed <<<<\n"); | |
382 } | |
383 } | |
384 return true; | |
385 } | |
386 | |
387 bool APITest::PushAudioRunB() { | |
388 _pushEventB->Wait(100); | |
389 AudioFrame audioFrame; | |
390 _inFileB.Read10MsData(audioFrame); | |
391 if (_acmB->Add10MsData(audioFrame) < 0) { | |
392 bool thereIsEncoder; | |
393 { | |
394 ReadLockScoped rl(_apiTestRWLock); | |
395 thereIsEncoder = _thereIsEncoderB; | |
396 } | |
397 | |
398 if (thereIsEncoder) { | |
399 fprintf(stderr, "\n>>>> cannot add audio to B <<<<"); | |
400 } | |
401 } | |
402 | |
403 return true; | |
404 } | |
405 | |
406 bool APITest::ProcessRunA() { | |
407 _processEventA->Wait(100); | |
408 return true; | |
409 } | |
410 | |
411 bool APITest::ProcessRunB() { | |
412 _processEventB->Wait(100); | |
413 return true; | |
414 } | |
415 | |
416 /*/ | |
417 * | |
418 * In side A we test the APIs which are related to sender Side. | |
419 * | |
420 /*/ | |
421 | |
422 void APITest::RunTest(char thread) { | |
423 int testNum; | |
424 { | |
425 WriteLockScoped cs(_apiTestRWLock); | |
426 if (thread == 'A') { | |
427 _testNumA = (_testNumB + 1 + (rand() % 3)) % 4; | |
428 testNum = _testNumA; | |
429 | |
430 _movingDot[_dotPositionA] = ' '; | |
431 if (_dotPositionA == 0) { | |
432 _dotMoveDirectionA = 1; | |
433 } | |
434 if (_dotPositionA == 19) { | |
435 _dotMoveDirectionA = -1; | |
436 } | |
437 _dotPositionA += _dotMoveDirectionA; | |
438 _movingDot[_dotPositionA] = (_dotMoveDirectionA > 0) ? '>' : '<'; | |
439 } else { | |
440 _testNumB = (_testNumA + 1 + (rand() % 3)) % 4; | |
441 testNum = _testNumB; | |
442 | |
443 _movingDot[_dotPositionB] = ' '; | |
444 if (_dotPositionB == 20) { | |
445 _dotMoveDirectionB = 1; | |
446 } | |
447 if (_dotPositionB == 39) { | |
448 _dotMoveDirectionB = -1; | |
449 } | |
450 _dotPositionB += _dotMoveDirectionB; | |
451 _movingDot[_dotPositionB] = (_dotMoveDirectionB > 0) ? '>' : '<'; | |
452 } | |
453 //fprintf(stderr, "%c: %d \n", thread, testNum); | |
454 //fflush(stderr); | |
455 } | |
456 switch (testNum) { | |
457 case 0: | |
458 CurrentCodec('A'); | |
459 ChangeCodec('A'); | |
460 break; | |
461 case 1: | |
462 if (!_randomTest) { | |
463 fprintf(stdout, "\nTesting Delay ...\n"); | |
464 } | |
465 TestDelay('A'); | |
466 break; | |
467 case 2: | |
468 TestSendVAD('A'); | |
469 break; | |
470 case 3: | |
471 TestRegisteration('A'); | |
472 break; | |
473 default: | |
474 fprintf(stderr, "Wrong Test Number\n"); | |
475 getc(stdin); | |
476 exit(1); | |
477 } | |
478 } | |
479 | |
480 bool APITest::APIRunA() { | |
481 _apiEventA->Wait(50); | |
482 | |
483 bool randomTest; | |
484 { | |
485 ReadLockScoped rl(_apiTestRWLock); | |
486 randomTest = _randomTest; | |
487 } | |
488 if (randomTest) { | |
489 RunTest('A'); | |
490 } else { | |
491 CurrentCodec('A'); | |
492 ChangeCodec('A'); | |
493 if (_codecCntrA == 0) { | |
494 fprintf(stdout, "\nTesting Delay ...\n"); | |
495 TestDelay('A'); | |
496 } | |
497 // VAD TEST | |
498 TestSendVAD('A'); | |
499 TestRegisteration('A'); | |
500 } | |
501 return true; | |
502 } | |
503 | |
504 bool APITest::APIRunB() { | |
505 _apiEventB->Wait(50); | |
506 bool randomTest; | |
507 { | |
508 ReadLockScoped rl(_apiTestRWLock); | |
509 randomTest = _randomTest; | |
510 } | |
511 //_apiEventB->Wait(2000); | |
512 if (randomTest) { | |
513 RunTest('B'); | |
514 } | |
515 | |
516 return true; | |
517 } | |
518 | |
519 void APITest::Perform() { | |
520 SetUp(); | |
521 | |
522 //--- THREADS | |
523 // A | |
524 // PUSH | |
525 rtc::scoped_ptr<PlatformThread> myPushAudioThreadA = | |
526 PlatformThread::CreateThread(PushAudioThreadA, this, "PushAudioThreadA"); | |
527 CHECK_THREAD_NULLITY(myPushAudioThreadA, "Unable to start A::PUSH thread"); | |
528 // PULL | |
529 rtc::scoped_ptr<PlatformThread> myPullAudioThreadA = | |
530 PlatformThread::CreateThread(PullAudioThreadA, this, "PullAudioThreadA"); | |
531 CHECK_THREAD_NULLITY(myPullAudioThreadA, "Unable to start A::PULL thread"); | |
532 // Process | |
533 rtc::scoped_ptr<PlatformThread> myProcessThreadA = | |
534 PlatformThread::CreateThread(ProcessThreadA, this, "ProcessThreadA"); | |
535 CHECK_THREAD_NULLITY(myProcessThreadA, "Unable to start A::Process thread"); | |
536 // API | |
537 rtc::scoped_ptr<PlatformThread> myAPIThreadA = | |
538 PlatformThread::CreateThread(APIThreadA, this, "APIThreadA"); | |
539 CHECK_THREAD_NULLITY(myAPIThreadA, "Unable to start A::API thread"); | |
540 // B | |
541 // PUSH | |
542 rtc::scoped_ptr<PlatformThread> myPushAudioThreadB = | |
543 PlatformThread::CreateThread(PushAudioThreadB, this, "PushAudioThreadB"); | |
544 CHECK_THREAD_NULLITY(myPushAudioThreadB, "Unable to start B::PUSH thread"); | |
545 // PULL | |
546 rtc::scoped_ptr<PlatformThread> myPullAudioThreadB = | |
547 PlatformThread::CreateThread(PullAudioThreadB, this, "PullAudioThreadB"); | |
548 CHECK_THREAD_NULLITY(myPullAudioThreadB, "Unable to start B::PULL thread"); | |
549 // Process | |
550 rtc::scoped_ptr<PlatformThread> myProcessThreadB = | |
551 PlatformThread::CreateThread(ProcessThreadB, this, "ProcessThreadB"); | |
552 CHECK_THREAD_NULLITY(myProcessThreadB, "Unable to start B::Process thread"); | |
553 // API | |
554 rtc::scoped_ptr<PlatformThread> myAPIThreadB = | |
555 PlatformThread::CreateThread(APIThreadB, this, "APIThreadB"); | |
556 CHECK_THREAD_NULLITY(myAPIThreadB, "Unable to start B::API thread"); | |
557 | |
558 //_apiEventA->StartTimer(true, 5000); | |
559 //_apiEventB->StartTimer(true, 5000); | |
560 | |
561 _processEventA->StartTimer(true, 10); | |
562 _processEventB->StartTimer(true, 10); | |
563 | |
564 _pullEventA->StartTimer(true, 10); | |
565 _pullEventB->StartTimer(true, 10); | |
566 | |
567 _pushEventA->StartTimer(true, 10); | |
568 _pushEventB->StartTimer(true, 10); | |
569 | |
570 // Keep main thread waiting for sender/receiver | |
571 // threads to complete | |
572 EventWrapper* completeEvent = EventWrapper::Create(); | |
573 uint64_t startTime = TickTime::MillisecondTimestamp(); | |
574 uint64_t currentTime; | |
575 // Run test in 2 minutes (120000 ms). | |
576 do { | |
577 { | |
578 //ReadLockScoped rl(_apiTestRWLock); | |
579 //fprintf(stderr, "\r%s", _movingDot); | |
580 } | |
581 //fflush(stderr); | |
582 completeEvent->Wait(50); | |
583 currentTime = TickTime::MillisecondTimestamp(); | |
584 } while ((currentTime - startTime) < 120000); | |
585 | |
586 //completeEvent->Wait(0xFFFFFFFF); | |
587 //(unsigned long)((unsigned long)TEST_DURATION_SEC * (unsigned long)1000)); | |
588 delete completeEvent; | |
589 | |
590 myPushAudioThreadA->Stop(); | |
591 myPullAudioThreadA->Stop(); | |
592 myProcessThreadA->Stop(); | |
593 myAPIThreadA->Stop(); | |
594 | |
595 myPushAudioThreadB->Stop(); | |
596 myPullAudioThreadB->Stop(); | |
597 myProcessThreadB->Stop(); | |
598 myAPIThreadB->Stop(); | |
599 } | |
600 | |
601 void APITest::CheckVADStatus(char side) { | |
602 | |
603 bool dtxEnabled; | |
604 bool vadEnabled; | |
605 ACMVADMode vadMode; | |
606 | |
607 if (side == 'A') { | |
608 _acmA->VAD(&dtxEnabled, &vadEnabled, &vadMode); | |
609 _acmA->RegisterVADCallback(NULL); | |
610 _vadCallbackA->Reset(); | |
611 _acmA->RegisterVADCallback(_vadCallbackA); | |
612 | |
613 if (!_randomTest) { | |
614 if (_verbose) { | |
615 fprintf(stdout, "DTX %3s, VAD %3s, Mode %d", dtxEnabled ? "ON" : "OFF", | |
616 vadEnabled ? "ON" : "OFF", (int) vadMode); | |
617 Wait(5000); | |
618 fprintf(stdout, " => bit-rate %3.0f kbps\n", _channel_A2B->BitRate()); | |
619 } else { | |
620 Wait(5000); | |
621 fprintf(stdout, "DTX %3s, VAD %3s, Mode %d => bit-rate %3.0f kbps\n", | |
622 dtxEnabled ? "ON" : "OFF", vadEnabled ? "ON" : "OFF", | |
623 (int) vadMode, _channel_A2B->BitRate()); | |
624 } | |
625 _vadCallbackA->PrintFrameTypes(); | |
626 } | |
627 | |
628 if (dtxEnabled != _sendDTXA) { | |
629 fprintf(stderr, ">>> Error Enabling DTX <<<\n"); | |
630 } | |
631 if ((vadEnabled != _sendVADA) && (!dtxEnabled)) { | |
632 fprintf(stderr, ">>> Error Enabling VAD <<<\n"); | |
633 } | |
634 if ((vadMode != _sendVADModeA) && vadEnabled) { | |
635 fprintf(stderr, ">>> Error setting VAD-mode <<<\n"); | |
636 } | |
637 } else { | |
638 _acmB->VAD(&dtxEnabled, &vadEnabled, &vadMode); | |
639 | |
640 _acmB->RegisterVADCallback(NULL); | |
641 _vadCallbackB->Reset(); | |
642 _acmB->RegisterVADCallback(_vadCallbackB); | |
643 | |
644 if (!_randomTest) { | |
645 if (_verbose) { | |
646 fprintf(stdout, "DTX %3s, VAD %3s, Mode %d", dtxEnabled ? "ON" : "OFF", | |
647 vadEnabled ? "ON" : "OFF", (int) vadMode); | |
648 Wait(5000); | |
649 fprintf(stdout, " => bit-rate %3.0f kbps\n", _channel_B2A->BitRate()); | |
650 } else { | |
651 Wait(5000); | |
652 fprintf(stdout, "DTX %3s, VAD %3s, Mode %d => bit-rate %3.0f kbps\n", | |
653 dtxEnabled ? "ON" : "OFF", vadEnabled ? "ON" : "OFF", | |
654 (int) vadMode, _channel_B2A->BitRate()); | |
655 } | |
656 _vadCallbackB->PrintFrameTypes(); | |
657 } | |
658 | |
659 if (dtxEnabled != _sendDTXB) { | |
660 fprintf(stderr, ">>> Error Enabling DTX <<<\n"); | |
661 } | |
662 if ((vadEnabled != _sendVADB) && (!dtxEnabled)) { | |
663 fprintf(stderr, ">>> Error Enabling VAD <<<\n"); | |
664 } | |
665 if ((vadMode != _sendVADModeB) && vadEnabled) { | |
666 fprintf(stderr, ">>> Error setting VAD-mode <<<\n"); | |
667 } | |
668 } | |
669 } | |
670 | |
671 // Set Min delay, get delay, playout timestamp | |
672 void APITest::TestDelay(char side) { | |
673 AudioCodingModule* myACM; | |
674 Channel* myChannel; | |
675 int32_t* myMinDelay; | |
676 EventTimerWrapper* myEvent = EventTimerWrapper::Create(); | |
677 | |
678 uint32_t inTimestamp = 0; | |
679 uint32_t outTimestamp = 0; | |
680 double estimDelay = 0; | |
681 | |
682 double averageEstimDelay = 0; | |
683 double averageDelay = 0; | |
684 | |
685 CircularBuffer estimDelayCB(100); | |
686 estimDelayCB.SetArithMean(true); | |
687 | |
688 if (side == 'A') { | |
689 myACM = _acmA.get(); | |
690 myChannel = _channel_B2A; | |
691 myMinDelay = &_minDelayA; | |
692 } else { | |
693 myACM = _acmB.get(); | |
694 myChannel = _channel_A2B; | |
695 myMinDelay = &_minDelayB; | |
696 } | |
697 | |
698 CHECK_ERROR_MT(myACM->SetMinimumPlayoutDelay(*myMinDelay)); | |
699 | |
700 inTimestamp = myChannel->LastInTimestamp(); | |
701 CHECK_ERROR_MT(myACM->PlayoutTimestamp(&outTimestamp)); | |
702 | |
703 if (!_randomTest) { | |
704 myEvent->StartTimer(true, 30); | |
705 int n = 0; | |
706 int settlePoint = 5000; | |
707 while (n < settlePoint + 400) { | |
708 myEvent->Wait(1000); | |
709 | |
710 inTimestamp = myChannel->LastInTimestamp(); | |
711 CHECK_ERROR_MT(myACM->PlayoutTimestamp(&outTimestamp)); | |
712 | |
713 //std::cout << outTimestamp << std::endl << std::flush; | |
714 estimDelay = (double) ((uint32_t)(inTimestamp - outTimestamp)) | |
715 / ((double) myACM->ReceiveFrequency() / 1000.0); | |
716 | |
717 estimDelayCB.Update(estimDelay); | |
718 | |
719 estimDelayCB.ArithMean(averageEstimDelay); | |
720 //printf("\n %6.1f \n", estimDelay); | |
721 //std::cout << " " << std::flush; | |
722 | |
723 if (_verbose) { | |
724 fprintf(stdout, | |
725 "\rExpected: %4d, retreived: %6.1f, measured: %6.1f", | |
726 *myMinDelay, averageDelay, averageEstimDelay); | |
727 std::cout << " " << std::flush; | |
728 } | |
729 if ((averageDelay > *myMinDelay) && (n < settlePoint)) { | |
730 settlePoint = n; | |
731 } | |
732 n++; | |
733 } | |
734 myEvent->StopTimer(); | |
735 } | |
736 | |
737 if ((!_verbose) && (!_randomTest)) { | |
738 fprintf(stdout, "\nExpected: %4d, retreived: %6.1f, measured: %6.1f", | |
739 *myMinDelay, averageDelay, averageEstimDelay); | |
740 } | |
741 | |
742 *myMinDelay = (rand() % 1000) + 1; | |
743 | |
744 NetworkStatistics networkStat; | |
745 CHECK_ERROR_MT(myACM->GetNetworkStatistics(&networkStat)); | |
746 | |
747 if (!_randomTest) { | |
748 fprintf(stdout, "\n\nJitter Statistics at Side %c\n", side); | |
749 fprintf(stdout, "--------------------------------------\n"); | |
750 fprintf(stdout, "buffer-size............. %d\n", | |
751 networkStat.currentBufferSize); | |
752 fprintf(stdout, "Preferred buffer-size... %d\n", | |
753 networkStat.preferredBufferSize); | |
754 fprintf(stdout, "Peaky jitter mode........%d\n", | |
755 networkStat.jitterPeaksFound); | |
756 fprintf(stdout, "packet-size rate........ %d\n", | |
757 networkStat.currentPacketLossRate); | |
758 fprintf(stdout, "discard rate............ %d\n", | |
759 networkStat.currentDiscardRate); | |
760 fprintf(stdout, "expand rate............. %d\n", | |
761 networkStat.currentExpandRate); | |
762 fprintf(stdout, "speech expand rate...... %d\n", | |
763 networkStat.currentSpeechExpandRate); | |
764 fprintf(stdout, "Preemptive rate......... %d\n", | |
765 networkStat.currentPreemptiveRate); | |
766 fprintf(stdout, "Accelerate rate......... %d\n", | |
767 networkStat.currentAccelerateRate); | |
768 fprintf(stdout, "Secondary decoded rate.. %d\n", | |
769 networkStat.currentSecondaryDecodedRate); | |
770 fprintf(stdout, "Clock-drift............. %d\n", networkStat.clockDriftPPM); | |
771 fprintf(stdout, "Mean waiting time....... %d\n", | |
772 networkStat.meanWaitingTimeMs); | |
773 fprintf(stdout, "Median waiting time..... %d\n", | |
774 networkStat.medianWaitingTimeMs); | |
775 fprintf(stdout, "Min waiting time........ %d\n", | |
776 networkStat.minWaitingTimeMs); | |
777 fprintf(stdout, "Max waiting time........ %d\n", | |
778 networkStat.maxWaitingTimeMs); | |
779 } | |
780 | |
781 CHECK_ERROR_MT(myACM->SetMinimumPlayoutDelay(*myMinDelay)); | |
782 | |
783 if (!_randomTest) { | |
784 myEvent->Wait(500); | |
785 fprintf(stdout, "\n"); | |
786 fprintf(stdout, "\n"); | |
787 } | |
788 delete myEvent; | |
789 } | |
790 | |
791 // Unregister a codec & register again. | |
792 void APITest::TestRegisteration(char sendSide) { | |
793 AudioCodingModule* sendACM; | |
794 AudioCodingModule* receiveACM; | |
795 bool* thereIsDecoder; | |
796 EventWrapper* myEvent = EventWrapper::Create(); | |
797 | |
798 if (!_randomTest) { | |
799 fprintf(stdout, "\n\n"); | |
800 fprintf(stdout, | |
801 "---------------------------------------------------------\n"); | |
802 fprintf(stdout, " Unregister/register Receive Codec\n"); | |
803 fprintf(stdout, | |
804 "---------------------------------------------------------\n"); | |
805 } | |
806 | |
807 switch (sendSide) { | |
808 case 'A': { | |
809 sendACM = _acmA.get(); | |
810 receiveACM = _acmB.get(); | |
811 thereIsDecoder = &_thereIsDecoderB; | |
812 break; | |
813 } | |
814 case 'B': { | |
815 sendACM = _acmB.get(); | |
816 receiveACM = _acmA.get(); | |
817 thereIsDecoder = &_thereIsDecoderA; | |
818 break; | |
819 } | |
820 default: | |
821 fprintf(stderr, "Invalid sender-side in TestRegistration(%c)\n", | |
822 sendSide); | |
823 exit(-1); | |
824 } | |
825 | |
826 auto myCodec = sendACM->SendCodec(); | |
827 if (!myCodec) { | |
828 CodecInst ci; | |
829 AudioCodingModule::Codec(_codecCntrA, &ci); | |
830 myCodec = rtc::Optional<CodecInst>(ci); | |
831 } | |
832 | |
833 if (!_randomTest) { | |
834 fprintf(stdout, "Unregistering reveive codec, NO AUDIO.\n"); | |
835 fflush (stdout); | |
836 } | |
837 { | |
838 WriteLockScoped wl(_apiTestRWLock); | |
839 *thereIsDecoder = false; | |
840 } | |
841 //myEvent->Wait(20); | |
842 CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec->pltype)); | |
843 Wait(1000); | |
844 | |
845 int currentPayload = myCodec->pltype; | |
846 | |
847 if (!FixedPayloadTypeCodec(myCodec->plname)) { | |
848 int32_t i; | |
849 for (i = 0; i < 32; i++) { | |
850 if (!_payloadUsed[i]) { | |
851 if (!_randomTest) { | |
852 fprintf(stdout, | |
853 "Register receive codec with new Payload, AUDIO BACK.\n"); | |
854 } | |
855 //myCodec->pltype = i + 96; | |
856 //CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(*myCodec)); | |
857 //CHECK_ERROR_MT(sendACM->RegisterSendCodec(*myCodec)); | |
858 //myEvent->Wait(20); | |
859 //{ | |
860 // WriteLockScoped wl(_apiTestRWLock); | |
861 // *thereIsDecoder = true; | |
862 //} | |
863 Wait(1000); | |
864 | |
865 if (!_randomTest) { | |
866 fprintf(stdout, "Unregistering reveive codec, NO AUDIO.\n"); | |
867 } | |
868 //{ | |
869 // WriteLockScoped wl(_apiTestRWLock); | |
870 // *thereIsDecoder = false; | |
871 //} | |
872 //myEvent->Wait(20); | |
873 //CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec->pltype)); | |
874 Wait(1000); | |
875 | |
876 myCodec->pltype = currentPayload; | |
877 if (!_randomTest) { | |
878 fprintf(stdout, | |
879 "Register receive codec with default Payload, AUDIO BACK.\n"); | |
880 fflush (stdout); | |
881 } | |
882 CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(*myCodec)); | |
883 //CHECK_ERROR_MT(sendACM->RegisterSendCodec(*myCodec)); | |
884 myEvent->Wait(20); | |
885 { | |
886 WriteLockScoped wl(_apiTestRWLock); | |
887 *thereIsDecoder = true; | |
888 } | |
889 Wait(1000); | |
890 | |
891 break; | |
892 } | |
893 } | |
894 if (i == 32) { | |
895 CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(*myCodec)); | |
896 { | |
897 WriteLockScoped wl(_apiTestRWLock); | |
898 *thereIsDecoder = true; | |
899 } | |
900 } | |
901 } else { | |
902 if (!_randomTest) { | |
903 fprintf(stdout, | |
904 "Register receive codec with fixed Payload, AUDIO BACK.\n"); | |
905 fflush (stdout); | |
906 } | |
907 CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(*myCodec)); | |
908 //CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec->pltype)); | |
909 //CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(*myCodec)); | |
910 myEvent->Wait(20); | |
911 { | |
912 WriteLockScoped wl(_apiTestRWLock); | |
913 *thereIsDecoder = true; | |
914 } | |
915 } | |
916 delete myEvent; | |
917 if (!_randomTest) { | |
918 fprintf(stdout, | |
919 "---------------------------------------------------------\n"); | |
920 } | |
921 } | |
922 | |
923 void APITest::TestSendVAD(char side) { | |
924 if (_randomTest) { | |
925 return; | |
926 } | |
927 | |
928 bool* vad; | |
929 bool* dtx; | |
930 ACMVADMode* mode; | |
931 Channel* myChannel; | |
932 AudioCodingModule* myACM; | |
933 | |
934 CodecInst myCodec; | |
935 if (!_randomTest) { | |
936 fprintf(stdout, "\n\n"); | |
937 fprintf(stdout, "-----------------------------------------------\n"); | |
938 fprintf(stdout, " Test VAD API\n"); | |
939 fprintf(stdout, "-----------------------------------------------\n"); | |
940 } | |
941 | |
942 if (side == 'A') { | |
943 AudioCodingModule::Codec(_codecCntrA, &myCodec); | |
944 vad = &_sendVADA; | |
945 dtx = &_sendDTXA; | |
946 mode = &_sendVADModeA; | |
947 myChannel = _channel_A2B; | |
948 myACM = _acmA.get(); | |
949 } else { | |
950 AudioCodingModule::Codec(_codecCntrB, &myCodec); | |
951 vad = &_sendVADB; | |
952 dtx = &_sendDTXB; | |
953 mode = &_sendVADModeB; | |
954 myChannel = _channel_B2A; | |
955 myACM = _acmB.get(); | |
956 } | |
957 | |
958 CheckVADStatus(side); | |
959 if (!_randomTest) { | |
960 fprintf(stdout, "\n\n"); | |
961 } | |
962 | |
963 switch (*mode) { | |
964 case VADNormal: | |
965 *vad = true; | |
966 *dtx = true; | |
967 *mode = VADAggr; | |
968 break; | |
969 case VADLowBitrate: | |
970 *vad = true; | |
971 *dtx = true; | |
972 *mode = VADVeryAggr; | |
973 break; | |
974 case VADAggr: | |
975 *vad = true; | |
976 *dtx = true; | |
977 *mode = VADLowBitrate; | |
978 break; | |
979 case VADVeryAggr: | |
980 *vad = false; | |
981 *dtx = false; | |
982 *mode = VADNormal; | |
983 break; | |
984 default: | |
985 *mode = VADNormal; | |
986 } | |
987 | |
988 *dtx = (myCodec.plfreq == 32000) ? false : *dtx; | |
989 | |
990 CHECK_ERROR_MT(myACM->SetVAD(*dtx, *vad, *mode)); | |
991 myChannel->ResetStats(); | |
992 | |
993 CheckVADStatus(side); | |
994 if (!_randomTest) { | |
995 fprintf(stdout, "\n"); | |
996 fprintf(stdout, "-----------------------------------------------\n"); | |
997 } | |
998 | |
999 // Fault Test | |
1000 CHECK_PROTECTED_MT(myACM->SetVAD(false, true, (ACMVADMode) - 1)); | |
1001 CHECK_PROTECTED_MT(myACM->SetVAD(false, true, (ACMVADMode) 4)); | |
1002 | |
1003 } | |
1004 | |
1005 void APITest::CurrentCodec(char side) { | |
1006 auto myCodec = (side == 'A' ? _acmA : _acmB)->SendCodec(); | |
1007 | |
1008 if (!_randomTest) { | |
1009 fprintf(stdout, "\n\n"); | |
1010 fprintf(stdout, "Send codec in Side A\n"); | |
1011 fprintf(stdout, "----------------------------\n"); | |
1012 fprintf(stdout, "Name................. %s\n", myCodec->plname); | |
1013 fprintf(stdout, "Sampling Frequency... %d\n", myCodec->plfreq); | |
1014 fprintf(stdout, "Rate................. %d\n", myCodec->rate); | |
1015 fprintf(stdout, "Payload-type......... %d\n", myCodec->pltype); | |
1016 fprintf(stdout, "Packet-size.......... %d\n", myCodec->pacsize); | |
1017 } | |
1018 | |
1019 Wait(100); | |
1020 } | |
1021 | |
1022 void APITest::ChangeCodec(char side) { | |
1023 CodecInst myCodec; | |
1024 AudioCodingModule* myACM; | |
1025 uint8_t* codecCntr; | |
1026 bool* thereIsEncoder; | |
1027 bool* vad; | |
1028 bool* dtx; | |
1029 ACMVADMode* mode; | |
1030 Channel* myChannel; | |
1031 // Reset and Wait | |
1032 if (!_randomTest) { | |
1033 fprintf(stdout, "Reset Encoder Side A \n"); | |
1034 } | |
1035 if (side == 'A') { | |
1036 myACM = _acmA.get(); | |
1037 codecCntr = &_codecCntrA; | |
1038 { | |
1039 WriteLockScoped wl(_apiTestRWLock); | |
1040 thereIsEncoder = &_thereIsEncoderA; | |
1041 } | |
1042 vad = &_sendVADA; | |
1043 dtx = &_sendDTXA; | |
1044 mode = &_sendVADModeA; | |
1045 myChannel = _channel_A2B; | |
1046 } else { | |
1047 myACM = _acmB.get(); | |
1048 codecCntr = &_codecCntrB; | |
1049 { | |
1050 WriteLockScoped wl(_apiTestRWLock); | |
1051 thereIsEncoder = &_thereIsEncoderB; | |
1052 } | |
1053 vad = &_sendVADB; | |
1054 dtx = &_sendDTXB; | |
1055 mode = &_sendVADModeB; | |
1056 myChannel = _channel_B2A; | |
1057 } | |
1058 | |
1059 Wait(100); | |
1060 | |
1061 // Register the next codec | |
1062 do { | |
1063 *codecCntr = | |
1064 (*codecCntr < AudioCodingModule::NumberOfCodecs() - 1) ? | |
1065 (*codecCntr + 1) : 0; | |
1066 | |
1067 if (*codecCntr == 0) { | |
1068 //printf("Initialize Sender Side A \n"); | |
1069 { | |
1070 WriteLockScoped wl(_apiTestRWLock); | |
1071 *thereIsEncoder = false; | |
1072 } | |
1073 // After Initialization CN is lost, re-register them | |
1074 if (AudioCodingModule::Codec("CN", &myCodec, 8000, 1) >= 0) { | |
1075 CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec)); | |
1076 } | |
1077 if (AudioCodingModule::Codec("CN", &myCodec, 16000, 1) >= 0) { | |
1078 CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec)); | |
1079 } | |
1080 // VAD & DTX are disabled after initialization | |
1081 *vad = false; | |
1082 *dtx = false; | |
1083 _writeToFile = false; | |
1084 } | |
1085 | |
1086 AudioCodingModule::Codec(*codecCntr, &myCodec); | |
1087 } while (!STR_CASE_CMP(myCodec.plname, "CN") | |
1088 || !STR_CASE_CMP(myCodec.plname, "telephone-event") | |
1089 || !STR_CASE_CMP(myCodec.plname, "RED")); | |
1090 | |
1091 if (!_randomTest) { | |
1092 fprintf(stdout,"\n=====================================================\n"); | |
1093 fprintf(stdout, " Registering New Codec %s, %d kHz, %d kbps\n", | |
1094 myCodec.plname, myCodec.plfreq / 1000, myCodec.rate / 1000); | |
1095 } | |
1096 //std::cout<< std::flush; | |
1097 | |
1098 // NO DTX for supe-wideband codec at this point | |
1099 if (myCodec.plfreq == 32000) { | |
1100 *dtx = false; | |
1101 CHECK_ERROR_MT(myACM->SetVAD(*dtx, *vad, *mode)); | |
1102 | |
1103 } | |
1104 | |
1105 CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec)); | |
1106 myChannel->ResetStats(); | |
1107 { | |
1108 WriteLockScoped wl(_apiTestRWLock); | |
1109 *thereIsEncoder = true; | |
1110 } | |
1111 Wait(500); | |
1112 } | |
1113 | |
1114 } // namespace webrtc | |
OLD | NEW |