session-android/jni/webrtc/modules/audio_coding/main/test/APITest.cc
Moxie Marlinspike d83a3d71bc Support for Signal calls.
Merge in RedPhone

// FREEBIE
2015-09-30 14:30:09 -07:00

1223 lines
34 KiB
C++

/*
* Copyright (c) 2012 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 "webrtc/modules/audio_coding/main/test/APITest.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <ostream>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
#include "webrtc/modules/audio_coding/main/test/utility.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/testsupport/fileutils.h"
namespace webrtc {
#define TEST_DURATION_SEC 600
#define NUMBER_OF_SENDER_TESTS 6
#define MAX_FILE_NAME_LENGTH_BYTE 500
#define CHECK_THREAD_NULLITY(myThread, S) \
if(myThread != NULL) { \
unsigned int i; \
(myThread)->Start(i); \
} else { \
ADD_FAILURE() << S; \
}
void APITest::Wait(uint32_t waitLengthMs) {
if (_randomTest) {
return;
} else {
EventWrapper* myEvent = EventWrapper::Create();
myEvent->Wait(waitLengthMs);
delete myEvent;
return;
}
}
APITest::APITest(const Config& config)
: _acmA(AudioCodingModule::Create(1)),
_acmB(AudioCodingModule::Create(2)),
_channel_A2B(NULL),
_channel_B2A(NULL),
_writeToFile(true),
_pullEventA(NULL),
_pushEventA(NULL),
_processEventA(NULL),
_apiEventA(NULL),
_pullEventB(NULL),
_pushEventB(NULL),
_processEventB(NULL),
_apiEventB(NULL),
_codecCntrA(0),
_codecCntrB(0),
_thereIsEncoderA(false),
_thereIsEncoderB(false),
_thereIsDecoderA(false),
_thereIsDecoderB(false),
_sendVADA(false),
_sendDTXA(false),
_sendVADModeA(VADNormal),
_sendVADB(false),
_sendDTXB(false),
_sendVADModeB(VADNormal),
_minDelayA(0),
_minDelayB(0),
_dotPositionA(0),
_dotMoveDirectionA(1),
_dotPositionB(39),
_dotMoveDirectionB(-1),
_dtmfCallback(NULL),
_vadCallbackA(NULL),
_vadCallbackB(NULL),
_apiTestRWLock(*RWLockWrapper::CreateRWLock()),
_randomTest(false),
_testNumA(0),
_testNumB(1) {
int n;
for (n = 0; n < 32; n++) {
_payloadUsed[n] = false;
}
_movingDot[40] = '\0';
for (int n = 0; n < 40; n++) {
_movingDot[n] = ' ';
}
}
APITest::~APITest() {
DELETE_POINTER(_channel_A2B);
DELETE_POINTER(_channel_B2A);
DELETE_POINTER(_pushEventA);
DELETE_POINTER(_pullEventA);
DELETE_POINTER(_processEventA);
DELETE_POINTER(_apiEventA);
DELETE_POINTER(_pushEventB);
DELETE_POINTER(_pullEventB);
DELETE_POINTER(_processEventB);
DELETE_POINTER(_apiEventB);
_inFileA.Close();
_outFileA.Close();
_inFileB.Close();
_outFileB.Close();
DELETE_POINTER(_dtmfCallback);
DELETE_POINTER(_vadCallbackA);
DELETE_POINTER(_vadCallbackB);
delete &_apiTestRWLock;
}
int16_t APITest::SetUp() {
CodecInst dummyCodec;
int lastPayloadType = 0;
int16_t numCodecs = _acmA->NumberOfCodecs();
for (uint8_t n = 0; n < numCodecs; n++) {
AudioCodingModule::Codec(n, &dummyCodec);
if ((STR_CASE_CMP(dummyCodec.plname, "CN") == 0)
&& (dummyCodec.plfreq == 32000)) {
continue;
}
printf("Register Receive Codec %s ", dummyCodec.plname);
if ((n != 0) && !FixedPayloadTypeCodec(dummyCodec.plname)) {
// Check registration with an already occupied payload type
int currentPayloadType = dummyCodec.pltype;
dummyCodec.pltype = 97; //lastPayloadType;
CHECK_ERROR(_acmB->RegisterReceiveCodec(dummyCodec));
dummyCodec.pltype = currentPayloadType;
}
if ((n < numCodecs - 1) && !FixedPayloadTypeCodec(dummyCodec.plname)) {
// test if re-registration works;
CodecInst nextCodec;
int currentPayloadType = dummyCodec.pltype;
AudioCodingModule::Codec(n + 1, &nextCodec);
dummyCodec.pltype = nextCodec.pltype;
if (!FixedPayloadTypeCodec(nextCodec.plname)) {
_acmB->RegisterReceiveCodec(dummyCodec);
}
dummyCodec.pltype = currentPayloadType;
}
if ((n < numCodecs - 1) && !FixedPayloadTypeCodec(dummyCodec.plname)) {
// test if un-registration works;
CodecInst nextCodec;
AudioCodingModule::Codec(n + 1, &nextCodec);
nextCodec.pltype = dummyCodec.pltype;
if (!FixedPayloadTypeCodec(nextCodec.plname)) {
CHECK_ERROR_MT(_acmA->RegisterReceiveCodec(nextCodec));
CHECK_ERROR_MT(_acmA->UnregisterReceiveCodec(nextCodec.pltype));
}
}
CHECK_ERROR_MT(_acmA->RegisterReceiveCodec(dummyCodec));
printf(" side A done!");
CHECK_ERROR_MT(_acmB->RegisterReceiveCodec(dummyCodec));
printf(" side B done!\n");
if (!strcmp(dummyCodec.plname, "CN")) {
CHECK_ERROR_MT(_acmA->RegisterSendCodec(dummyCodec));
CHECK_ERROR_MT(_acmB->RegisterSendCodec(dummyCodec));
}
lastPayloadType = dummyCodec.pltype;
if ((lastPayloadType >= 96) && (lastPayloadType <= 127)) {
_payloadUsed[lastPayloadType - 96] = true;
}
}
_thereIsDecoderA = true;
_thereIsDecoderB = true;
// Register Send Codec
AudioCodingModule::Codec((uint8_t) _codecCntrA, &dummyCodec);
CHECK_ERROR_MT(_acmA->RegisterSendCodec(dummyCodec));
_thereIsEncoderA = true;
//
AudioCodingModule::Codec((uint8_t) _codecCntrB, &dummyCodec);
CHECK_ERROR_MT(_acmB->RegisterSendCodec(dummyCodec));
_thereIsEncoderB = true;
uint16_t frequencyHz;
printf("\n\nAPI Test\n");
printf("========\n");
printf("Hit enter to accept the default values indicated in []\n\n");
//--- Input A
std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
frequencyHz = 32000;
printf("Enter input file at side A [%s]: ", file_name.c_str());
PCMFile::ChooseFile(&file_name, 499, &frequencyHz);
_inFileA.Open(file_name, frequencyHz, "rb", true);
//--- Output A
std::string out_file_a = webrtc::test::OutputPath() + "outA.pcm";
printf("Enter output file at side A [%s]: ", out_file_a.c_str());
PCMFile::ChooseFile(&out_file_a, 499, &frequencyHz);
_outFileA.Open(out_file_a, frequencyHz, "wb");
//--- Input B
file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
printf("\n\nEnter input file at side B [%s]: ", file_name.c_str());
PCMFile::ChooseFile(&file_name, 499, &frequencyHz);
_inFileB.Open(file_name, frequencyHz, "rb", true);
//--- Output B
std::string out_file_b = webrtc::test::OutputPath() + "outB.pcm";
printf("Enter output file at side B [%s]: ", out_file_b.c_str());
PCMFile::ChooseFile(&out_file_b, 499, &frequencyHz);
_outFileB.Open(out_file_b, frequencyHz, "wb");
//--- Set A-to-B channel
_channel_A2B = new Channel(2);
CHECK_ERROR_MT(_acmA->RegisterTransportCallback(_channel_A2B));
_channel_A2B->RegisterReceiverACM(_acmB.get());
//--- Set B-to-A channel
_channel_B2A = new Channel(1);
CHECK_ERROR_MT(_acmB->RegisterTransportCallback(_channel_B2A));
_channel_B2A->RegisterReceiverACM(_acmA.get());
//--- EVENT TIMERS
// A
_pullEventA = EventWrapper::Create();
_pushEventA = EventWrapper::Create();
_processEventA = EventWrapper::Create();
_apiEventA = EventWrapper::Create();
// B
_pullEventB = EventWrapper::Create();
_pushEventB = EventWrapper::Create();
_processEventB = EventWrapper::Create();
_apiEventB = EventWrapper::Create();
//--- I/O params
// A
_outFreqHzA = _outFileA.SamplingFrequency();
// B
_outFreqHzB = _outFileB.SamplingFrequency();
//Trace::SetEncryptedTraceFile("ACMAPITestEncrypted.txt");
char print[11];
// Create a trace file.
Trace::CreateTrace();
Trace::SetTraceFile(
(webrtc::test::OutputPath() + "acm_api_trace.txt").c_str());
printf("\nRandom Test (y/n)?");
EXPECT_TRUE(fgets(print, 10, stdin) != NULL);
print[10] = '\0';
if (strstr(print, "y") != NULL) {
_randomTest = true;
_verbose = false;
_writeToFile = false;
} else {
_randomTest = false;
printf("\nPrint Tests (y/n)? ");
EXPECT_TRUE(fgets(print, 10, stdin) != NULL);
print[10] = '\0';
if (strstr(print, "y") == NULL) {
EXPECT_TRUE(freopen("APITest_log.txt", "w", stdout) != 0);
_verbose = false;
}
}
#ifdef WEBRTC_DTMF_DETECTION
_dtmfCallback = new DTMFDetector;
#endif
_vadCallbackA = new VADCallback;
_vadCallbackB = new VADCallback;
return 0;
}
bool APITest::PushAudioThreadA(void* obj) {
return static_cast<APITest*>(obj)->PushAudioRunA();
}
bool APITest::PushAudioThreadB(void* obj) {
return static_cast<APITest*>(obj)->PushAudioRunB();
}
bool APITest::PullAudioThreadA(void* obj) {
return static_cast<APITest*>(obj)->PullAudioRunA();
}
bool APITest::PullAudioThreadB(void* obj) {
return static_cast<APITest*>(obj)->PullAudioRunB();
}
bool APITest::ProcessThreadA(void* obj) {
return static_cast<APITest*>(obj)->ProcessRunA();
}
bool APITest::ProcessThreadB(void* obj) {
return static_cast<APITest*>(obj)->ProcessRunB();
}
bool APITest::APIThreadA(void* obj) {
return static_cast<APITest*>(obj)->APIRunA();
}
bool APITest::APIThreadB(void* obj) {
return static_cast<APITest*>(obj)->APIRunB();
}
bool APITest::PullAudioRunA() {
_pullEventA->Wait(100);
AudioFrame audioFrame;
if (_acmA->PlayoutData10Ms(_outFreqHzA, &audioFrame) < 0) {
bool thereIsDecoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsDecoder = _thereIsDecoderA;
}
if (thereIsDecoder) {
fprintf(stderr, "\n>>>>>> cannot pull audio A <<<<<<<< \n");
}
} else {
if (_writeToFile) {
_outFileA.Write10MsData(audioFrame);
}
}
return true;
}
bool APITest::PullAudioRunB() {
_pullEventB->Wait(100);
AudioFrame audioFrame;
if (_acmB->PlayoutData10Ms(_outFreqHzB, &audioFrame) < 0) {
bool thereIsDecoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsDecoder = _thereIsDecoderB;
}
if (thereIsDecoder) {
fprintf(stderr, "\n>>>>>> cannot pull audio B <<<<<<<< \n");
fprintf(stderr, "%d %d\n", _testNumA, _testNumB);
}
} else {
if (_writeToFile) {
_outFileB.Write10MsData(audioFrame);
}
}
return true;
}
bool APITest::PushAudioRunA() {
_pushEventA->Wait(100);
AudioFrame audioFrame;
_inFileA.Read10MsData(audioFrame);
if (_acmA->Add10MsData(audioFrame) < 0) {
bool thereIsEncoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsEncoder = _thereIsEncoderA;
}
if (thereIsEncoder) {
fprintf(stderr, "\n>>>> add10MsData at A failed <<<<\n");
}
}
return true;
}
bool APITest::PushAudioRunB() {
_pushEventB->Wait(100);
AudioFrame audioFrame;
_inFileB.Read10MsData(audioFrame);
if (_acmB->Add10MsData(audioFrame) < 0) {
bool thereIsEncoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsEncoder = _thereIsEncoderB;
}
if (thereIsEncoder) {
fprintf(stderr, "\n>>>> cannot add audio to B <<<<");
}
}
return true;
}
bool APITest::ProcessRunA() {
_processEventA->Wait(100);
if (_acmA->Process() < 0) {
// do not print error message if there is no encoder
bool thereIsEncoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsEncoder = _thereIsEncoderA;
}
if (thereIsEncoder) {
fprintf(stderr, "\n>>>>> Process Failed at A <<<<<\n");
}
}
return true;
}
bool APITest::ProcessRunB() {
_processEventB->Wait(100);
if (_acmB->Process() < 0) {
bool thereIsEncoder;
{
ReadLockScoped rl(_apiTestRWLock);
thereIsEncoder = _thereIsEncoderB;
}
if (thereIsEncoder) {
fprintf(stderr, "\n>>>>> Process Failed at B <<<<<\n");
}
}
return true;
}
/*/
*
* In side A we test the APIs which are related to sender Side.
*
/*/
void APITest::RunTest(char thread) {
int testNum;
{
WriteLockScoped cs(_apiTestRWLock);
if (thread == 'A') {
_testNumA = (_testNumB + 1 + (rand() % 4)) % 5;
testNum = _testNumA;
_movingDot[_dotPositionA] = ' ';
if (_dotPositionA == 0) {
_dotMoveDirectionA = 1;
}
if (_dotPositionA == 19) {
_dotMoveDirectionA = -1;
}
_dotPositionA += _dotMoveDirectionA;
_movingDot[_dotPositionA] = (_dotMoveDirectionA > 0) ? '>' : '<';
} else {
_testNumB = (_testNumA + 1 + (rand() % 4)) % 5;
testNum = _testNumB;
_movingDot[_dotPositionB] = ' ';
if (_dotPositionB == 20) {
_dotMoveDirectionB = 1;
}
if (_dotPositionB == 39) {
_dotMoveDirectionB = -1;
}
_dotPositionB += _dotMoveDirectionB;
_movingDot[_dotPositionB] = (_dotMoveDirectionB > 0) ? '>' : '<';
}
//fprintf(stderr, "%c: %d \n", thread, testNum);
//fflush(stderr);
}
switch (testNum) {
case 0:
CurrentCodec('A');
ChangeCodec('A');
break;
case 1:
TestPlayout('B');
break;
case 2:
if (!_randomTest) {
fprintf(stdout, "\nTesting Delay ...\n");
}
TestDelay('A');
break;
case 3:
TestSendVAD('A');
break;
case 4:
TestRegisteration('A');
break;
default:
fprintf(stderr, "Wrong Test Number\n");
getchar();
exit(1);
}
}
bool APITest::APIRunA() {
_apiEventA->Wait(50);
bool randomTest;
{
ReadLockScoped rl(_apiTestRWLock);
randomTest = _randomTest;
}
if (randomTest) {
RunTest('A');
} else {
CurrentCodec('A');
ChangeCodec('A');
TestPlayout('B');
if (_codecCntrA == 0) {
fprintf(stdout, "\nTesting Delay ...\n");
TestDelay('A');
}
// VAD TEST
TestSendVAD('A');
TestRegisteration('A');
}
return true;
}
bool APITest::APIRunB() {
_apiEventB->Wait(50);
bool randomTest;
{
ReadLockScoped rl(_apiTestRWLock);
randomTest = _randomTest;
}
//_apiEventB->Wait(2000);
if (randomTest) {
RunTest('B');
}
return true;
}
void APITest::Perform() {
SetUp();
//--- THREADS
// A
// PUSH
ThreadWrapper* myPushAudioThreadA = ThreadWrapper::CreateThread(
PushAudioThreadA, this, kNormalPriority, "PushAudioThreadA");
CHECK_THREAD_NULLITY(myPushAudioThreadA, "Unable to start A::PUSH thread");
// PULL
ThreadWrapper* myPullAudioThreadA = ThreadWrapper::CreateThread(
PullAudioThreadA, this, kNormalPriority, "PullAudioThreadA");
CHECK_THREAD_NULLITY(myPullAudioThreadA, "Unable to start A::PULL thread");
// Process
ThreadWrapper* myProcessThreadA = ThreadWrapper::CreateThread(
ProcessThreadA, this, kNormalPriority, "ProcessThreadA");
CHECK_THREAD_NULLITY(myProcessThreadA, "Unable to start A::Process thread");
// API
ThreadWrapper* myAPIThreadA = ThreadWrapper::CreateThread(APIThreadA, this,
kNormalPriority,
"APIThreadA");
CHECK_THREAD_NULLITY(myAPIThreadA, "Unable to start A::API thread");
// B
// PUSH
ThreadWrapper* myPushAudioThreadB = ThreadWrapper::CreateThread(
PushAudioThreadB, this, kNormalPriority, "PushAudioThreadB");
CHECK_THREAD_NULLITY(myPushAudioThreadB, "Unable to start B::PUSH thread");
// PULL
ThreadWrapper* myPullAudioThreadB = ThreadWrapper::CreateThread(
PullAudioThreadB, this, kNormalPriority, "PullAudioThreadB");
CHECK_THREAD_NULLITY(myPullAudioThreadB, "Unable to start B::PULL thread");
// Process
ThreadWrapper* myProcessThreadB = ThreadWrapper::CreateThread(
ProcessThreadB, this, kNormalPriority, "ProcessThreadB");
CHECK_THREAD_NULLITY(myProcessThreadB, "Unable to start B::Process thread");
// API
ThreadWrapper* myAPIThreadB = ThreadWrapper::CreateThread(APIThreadB, this,
kNormalPriority,
"APIThreadB");
CHECK_THREAD_NULLITY(myAPIThreadB, "Unable to start B::API thread");
//_apiEventA->StartTimer(true, 5000);
//_apiEventB->StartTimer(true, 5000);
_processEventA->StartTimer(true, 10);
_processEventB->StartTimer(true, 10);
_pullEventA->StartTimer(true, 10);
_pullEventB->StartTimer(true, 10);
_pushEventA->StartTimer(true, 10);
_pushEventB->StartTimer(true, 10);
// Keep main thread waiting for sender/receiver
// threads to complete
EventWrapper* completeEvent = EventWrapper::Create();
uint64_t startTime = TickTime::MillisecondTimestamp();
uint64_t currentTime;
// Run test in 2 minutes (120000 ms).
do {
{
//ReadLockScoped rl(_apiTestRWLock);
//fprintf(stderr, "\r%s", _movingDot);
}
//fflush(stderr);
completeEvent->Wait(50);
currentTime = TickTime::MillisecondTimestamp();
} while ((currentTime - startTime) < 120000);
//completeEvent->Wait(0xFFFFFFFF);
//(unsigned long)((unsigned long)TEST_DURATION_SEC * (unsigned long)1000));
delete completeEvent;
myPushAudioThreadA->Stop();
myPullAudioThreadA->Stop();
myProcessThreadA->Stop();
myAPIThreadA->Stop();
delete myPushAudioThreadA;
delete myPullAudioThreadA;
delete myProcessThreadA;
delete myAPIThreadA;
myPushAudioThreadB->Stop();
myPullAudioThreadB->Stop();
myProcessThreadB->Stop();
myAPIThreadB->Stop();
delete myPushAudioThreadB;
delete myPullAudioThreadB;
delete myProcessThreadB;
delete myAPIThreadB;
}
void APITest::CheckVADStatus(char side) {
bool dtxEnabled;
bool vadEnabled;
ACMVADMode vadMode;
if (side == 'A') {
_acmA->VAD(&dtxEnabled, &vadEnabled, &vadMode);
_acmA->RegisterVADCallback(NULL);
_vadCallbackA->Reset();
_acmA->RegisterVADCallback(_vadCallbackA);
if (!_randomTest) {
if (_verbose) {
fprintf(stdout, "DTX %3s, VAD %3s, Mode %d", dtxEnabled ? "ON" : "OFF",
vadEnabled ? "ON" : "OFF", (int) vadMode);
Wait(5000);
fprintf(stdout, " => bit-rate %3.0f kbps\n", _channel_A2B->BitRate());
} else {
Wait(5000);
fprintf(stdout, "DTX %3s, VAD %3s, Mode %d => bit-rate %3.0f kbps\n",
dtxEnabled ? "ON" : "OFF", vadEnabled ? "ON" : "OFF",
(int) vadMode, _channel_A2B->BitRate());
}
_vadCallbackA->PrintFrameTypes();
}
if (dtxEnabled != _sendDTXA) {
fprintf(stderr, ">>> Error Enabling DTX <<<\n");
}
if ((vadEnabled != _sendVADA) && (!dtxEnabled)) {
fprintf(stderr, ">>> Error Enabling VAD <<<\n");
}
if ((vadMode != _sendVADModeA) && vadEnabled) {
fprintf(stderr, ">>> Error setting VAD-mode <<<\n");
}
} else {
_acmB->VAD(&dtxEnabled, &vadEnabled, &vadMode);
_acmB->RegisterVADCallback(NULL);
_vadCallbackB->Reset();
_acmB->RegisterVADCallback(_vadCallbackB);
if (!_randomTest) {
if (_verbose) {
fprintf(stdout, "DTX %3s, VAD %3s, Mode %d", dtxEnabled ? "ON" : "OFF",
vadEnabled ? "ON" : "OFF", (int) vadMode);
Wait(5000);
fprintf(stdout, " => bit-rate %3.0f kbps\n", _channel_B2A->BitRate());
} else {
Wait(5000);
fprintf(stdout, "DTX %3s, VAD %3s, Mode %d => bit-rate %3.0f kbps\n",
dtxEnabled ? "ON" : "OFF", vadEnabled ? "ON" : "OFF",
(int) vadMode, _channel_B2A->BitRate());
}
_vadCallbackB->PrintFrameTypes();
}
if (dtxEnabled != _sendDTXB) {
fprintf(stderr, ">>> Error Enabling DTX <<<\n");
}
if ((vadEnabled != _sendVADB) && (!dtxEnabled)) {
fprintf(stderr, ">>> Error Enabling VAD <<<\n");
}
if ((vadMode != _sendVADModeB) && vadEnabled) {
fprintf(stderr, ">>> Error setting VAD-mode <<<\n");
}
}
}
// Set Min delay, get delay, playout timestamp
void APITest::TestDelay(char side) {
AudioCodingModule* myACM;
Channel* myChannel;
int32_t* myMinDelay;
EventWrapper* myEvent = EventWrapper::Create();
uint32_t inTimestamp = 0;
uint32_t outTimestamp = 0;
double estimDelay = 0;
double averageEstimDelay = 0;
double averageDelay = 0;
CircularBuffer estimDelayCB(100);
estimDelayCB.SetArithMean(true);
if (side == 'A') {
myACM = _acmA.get();
myChannel = _channel_B2A;
myMinDelay = &_minDelayA;
} else {
myACM = _acmB.get();
myChannel = _channel_A2B;
myMinDelay = &_minDelayB;
}
CHECK_ERROR_MT(myACM->SetMinimumPlayoutDelay(*myMinDelay));
inTimestamp = myChannel->LastInTimestamp();
CHECK_ERROR_MT(myACM->PlayoutTimestamp(&outTimestamp));
if (!_randomTest) {
myEvent->StartTimer(true, 30);
int n = 0;
int settlePoint = 5000;
while (n < settlePoint + 400) {
myEvent->Wait(1000);
inTimestamp = myChannel->LastInTimestamp();
CHECK_ERROR_MT(myACM->PlayoutTimestamp(&outTimestamp));
//std::cout << outTimestamp << std::endl << std::flush;
estimDelay = (double) ((uint32_t)(inTimestamp - outTimestamp))
/ ((double) myACM->ReceiveFrequency() / 1000.0);
estimDelayCB.Update(estimDelay);
estimDelayCB.ArithMean(averageEstimDelay);
//printf("\n %6.1f \n", estimDelay);
//std::cout << " " << std::flush;
if (_verbose) {
fprintf(stdout,
"\rExpected: %4d, retreived: %6.1f, measured: %6.1f",
*myMinDelay, averageDelay, averageEstimDelay);
std::cout << " " << std::flush;
}
if ((averageDelay > *myMinDelay) && (n < settlePoint)) {
settlePoint = n;
}
n++;
}
myEvent->StopTimer();
}
if ((!_verbose) && (!_randomTest)) {
fprintf(stdout, "\nExpected: %4d, retreived: %6.1f, measured: %6.1f",
*myMinDelay, averageDelay, averageEstimDelay);
}
*myMinDelay = (rand() % 1000) + 1;
ACMNetworkStatistics networkStat;
CHECK_ERROR_MT(myACM->NetworkStatistics(&networkStat));
if (!_randomTest) {
fprintf(stdout, "\n\nJitter Statistics at Side %c\n", side);
fprintf(stdout, "--------------------------------------\n");
fprintf(stdout, "buffer-size............. %d\n",
networkStat.currentBufferSize);
fprintf(stdout, "Preferred buffer-size... %d\n",
networkStat.preferredBufferSize);
fprintf(stdout, "Peaky jitter mode........%d\n",
networkStat.jitterPeaksFound);
fprintf(stdout, "packet-size rate........ %d\n",
networkStat.currentPacketLossRate);
fprintf(stdout, "discard rate............ %d\n",
networkStat.currentDiscardRate);
fprintf(stdout, "expand rate............. %d\n",
networkStat.currentExpandRate);
fprintf(stdout, "Preemptive rate......... %d\n",
networkStat.currentPreemptiveRate);
fprintf(stdout, "Accelerate rate......... %d\n",
networkStat.currentAccelerateRate);
fprintf(stdout, "Clock-drift............. %d\n", networkStat.clockDriftPPM);
fprintf(stdout, "Mean waiting time....... %d\n",
networkStat.meanWaitingTimeMs);
fprintf(stdout, "Median waiting time..... %d\n",
networkStat.medianWaitingTimeMs);
fprintf(stdout, "Min waiting time........ %d\n",
networkStat.minWaitingTimeMs);
fprintf(stdout, "Max waiting time........ %d\n",
networkStat.maxWaitingTimeMs);
}
CHECK_ERROR_MT(myACM->SetMinimumPlayoutDelay(*myMinDelay));
if (!_randomTest) {
myEvent->Wait(500);
fprintf(stdout, "\n");
fprintf(stdout, "\n");
}
delete myEvent;
}
// Unregister a codec & register again.
void APITest::TestRegisteration(char sendSide) {
AudioCodingModule* sendACM;
AudioCodingModule* receiveACM;
bool* thereIsDecoder;
EventWrapper* myEvent = EventWrapper::Create();
if (!_randomTest) {
fprintf(stdout, "\n\n");
fprintf(stdout,
"---------------------------------------------------------\n");
fprintf(stdout, " Unregister/register Receive Codec\n");
fprintf(stdout,
"---------------------------------------------------------\n");
}
switch (sendSide) {
case 'A': {
sendACM = _acmA.get();
receiveACM = _acmB.get();
thereIsDecoder = &_thereIsDecoderB;
break;
}
case 'B': {
sendACM = _acmB.get();
receiveACM = _acmA.get();
thereIsDecoder = &_thereIsDecoderA;
break;
}
default:
fprintf(stderr, "Invalid sender-side in TestRegistration(%c)\n",
sendSide);
exit(-1);
}
CodecInst myCodec;
if (sendACM->SendCodec(&myCodec) < 0) {
AudioCodingModule::Codec(_codecCntrA, &myCodec);
}
if (!_randomTest) {
fprintf(stdout, "Unregistering reveive codec, NO AUDIO.\n");
fflush (stdout);
}
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsDecoder = false;
}
//myEvent->Wait(20);
CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec.pltype));
Wait(1000);
int currentPayload = myCodec.pltype;
if (!FixedPayloadTypeCodec(myCodec.plname)) {
int32_t i;
for (i = 0; i < 32; i++) {
if (!_payloadUsed[i]) {
if (!_randomTest) {
fprintf(stdout,
"Register receive codec with new Payload, AUDIO BACK.\n");
}
//myCodec.pltype = i + 96;
//CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(myCodec));
//CHECK_ERROR_MT(sendACM->RegisterSendCodec(myCodec));
//myEvent->Wait(20);
//{
// WriteLockScoped wl(_apiTestRWLock);
// *thereIsDecoder = true;
//}
Wait(1000);
if (!_randomTest) {
fprintf(stdout, "Unregistering reveive codec, NO AUDIO.\n");
}
//{
// WriteLockScoped wl(_apiTestRWLock);
// *thereIsDecoder = false;
//}
//myEvent->Wait(20);
//CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec.pltype));
Wait(1000);
myCodec.pltype = currentPayload;
if (!_randomTest) {
fprintf(stdout,
"Register receive codec with default Payload, AUDIO BACK.\n");
fflush (stdout);
}
CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(myCodec));
//CHECK_ERROR_MT(sendACM->RegisterSendCodec(myCodec));
myEvent->Wait(20);
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsDecoder = true;
}
Wait(1000);
break;
}
}
if (i == 32) {
CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(myCodec));
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsDecoder = true;
}
}
} else {
if (!_randomTest) {
fprintf(stdout,
"Register receive codec with fixed Payload, AUDIO BACK.\n");
fflush (stdout);
}
CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(myCodec));
//CHECK_ERROR_MT(receiveACM->UnregisterReceiveCodec(myCodec.pltype));
//CHECK_ERROR_MT(receiveACM->RegisterReceiveCodec(myCodec));
myEvent->Wait(20);
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsDecoder = true;
}
}
delete myEvent;
if (!_randomTest) {
fprintf(stdout,
"---------------------------------------------------------\n");
}
}
// Playout Mode, background noise mode.
// Receiver Frequency, playout frequency.
void APITest::TestPlayout(char receiveSide) {
AudioCodingModule* receiveACM;
AudioPlayoutMode* playoutMode = NULL;
switch (receiveSide) {
case 'A': {
receiveACM = _acmA.get();
playoutMode = &_playoutModeA;
break;
}
case 'B': {
receiveACM = _acmB.get();
playoutMode = &_playoutModeB;
break;
}
default:
receiveACM = _acmA.get();
}
int32_t receiveFreqHz = receiveACM->ReceiveFrequency();
int32_t playoutFreqHz = receiveACM->PlayoutFrequency();
CHECK_ERROR_MT(receiveFreqHz);
CHECK_ERROR_MT(playoutFreqHz);
char playoutString[25];
switch (*playoutMode) {
case voice: {
*playoutMode = fax;
strncpy(playoutString, "FAX", 25);
break;
}
case fax: {
*playoutMode = streaming;
strncpy(playoutString, "Streaming", 25);
break;
}
case streaming: {
*playoutMode = voice;
strncpy(playoutString, "Voice", 25);
break;
}
default:
*playoutMode = voice;
strncpy(playoutString, "Voice", 25);
}
CHECK_ERROR_MT(receiveACM->SetPlayoutMode(*playoutMode));
playoutString[24] = '\0';
if (!_randomTest) {
fprintf(stdout, "\n");
fprintf(stdout, "In Side %c\n", receiveSide);
fprintf(stdout, "---------------------------------\n");
fprintf(stdout, "Receive Frequency....... %d Hz\n", receiveFreqHz);
fprintf(stdout, "Playout Frequency....... %d Hz\n", playoutFreqHz);
fprintf(stdout, "Audio Playout Mode...... %s\n", playoutString);
}
}
void APITest::TestSendVAD(char side) {
if (_randomTest) {
return;
}
bool* vad;
bool* dtx;
ACMVADMode* mode;
Channel* myChannel;
AudioCodingModule* myACM;
CodecInst myCodec;
if (!_randomTest) {
fprintf(stdout, "\n\n");
fprintf(stdout, "-----------------------------------------------\n");
fprintf(stdout, " Test VAD API\n");
fprintf(stdout, "-----------------------------------------------\n");
}
if (side == 'A') {
AudioCodingModule::Codec(_codecCntrA, &myCodec);
vad = &_sendVADA;
dtx = &_sendDTXA;
mode = &_sendVADModeA;
myChannel = _channel_A2B;
myACM = _acmA.get();
} else {
AudioCodingModule::Codec(_codecCntrB, &myCodec);
vad = &_sendVADB;
dtx = &_sendDTXB;
mode = &_sendVADModeB;
myChannel = _channel_B2A;
myACM = _acmB.get();
}
CheckVADStatus(side);
if (!_randomTest) {
fprintf(stdout, "\n\n");
}
switch (*mode) {
case VADNormal:
*vad = true;
*dtx = true;
*mode = VADAggr;
break;
case VADLowBitrate:
*vad = true;
*dtx = true;
*mode = VADVeryAggr;
break;
case VADAggr:
*vad = true;
*dtx = true;
*mode = VADLowBitrate;
break;
case VADVeryAggr:
*vad = false;
*dtx = false;
*mode = VADNormal;
break;
default:
*mode = VADNormal;
}
*dtx = (myCodec.plfreq == 32000) ? false : *dtx;
CHECK_ERROR_MT(myACM->SetVAD(*dtx, *vad, *mode));
myChannel->ResetStats();
CheckVADStatus(side);
if (!_randomTest) {
fprintf(stdout, "\n");
fprintf(stdout, "-----------------------------------------------\n");
}
// Fault Test
CHECK_PROTECTED_MT(myACM->SetVAD(false, true, (ACMVADMode) - 1));
CHECK_PROTECTED_MT(myACM->SetVAD(false, true, (ACMVADMode) 4));
}
void APITest::CurrentCodec(char side) {
CodecInst myCodec;
if (side == 'A') {
_acmA->SendCodec(&myCodec);
} else {
_acmB->SendCodec(&myCodec);
}
if (!_randomTest) {
fprintf(stdout, "\n\n");
fprintf(stdout, "Send codec in Side A\n");
fprintf(stdout, "----------------------------\n");
fprintf(stdout, "Name................. %s\n", myCodec.plname);
fprintf(stdout, "Sampling Frequency... %d\n", myCodec.plfreq);
fprintf(stdout, "Rate................. %d\n", myCodec.rate);
fprintf(stdout, "Payload-type......... %d\n", myCodec.pltype);
fprintf(stdout, "Packet-size.......... %d\n", myCodec.pacsize);
}
Wait(100);
}
void APITest::ChangeCodec(char side) {
CodecInst myCodec;
AudioCodingModule* myACM;
uint8_t* codecCntr;
bool* thereIsEncoder;
bool* vad;
bool* dtx;
ACMVADMode* mode;
Channel* myChannel;
// Reset and Wait
if (!_randomTest) {
fprintf(stdout, "Reset Encoder Side A \n");
}
if (side == 'A') {
myACM = _acmA.get();
codecCntr = &_codecCntrA;
{
WriteLockScoped wl(_apiTestRWLock);
thereIsEncoder = &_thereIsEncoderA;
}
vad = &_sendVADA;
dtx = &_sendDTXA;
mode = &_sendVADModeA;
myChannel = _channel_A2B;
} else {
myACM = _acmB.get();
codecCntr = &_codecCntrB;
{
WriteLockScoped wl(_apiTestRWLock);
thereIsEncoder = &_thereIsEncoderB;
}
vad = &_sendVADB;
dtx = &_sendDTXB;
mode = &_sendVADModeB;
myChannel = _channel_B2A;
}
myACM->ResetEncoder();
Wait(100);
// Register the next codec
do {
*codecCntr =
(*codecCntr < AudioCodingModule::NumberOfCodecs() - 1) ?
(*codecCntr + 1) : 0;
if (*codecCntr == 0) {
//printf("Initialize Sender Side A \n");
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsEncoder = false;
}
CHECK_ERROR_MT(myACM->InitializeSender());
Wait(1000);
// After Initialization CN is lost, re-register them
if (AudioCodingModule::Codec("CN", &myCodec, 8000, 1) >= 0) {
CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec));
}
if (AudioCodingModule::Codec("CN", &myCodec, 16000, 1) >= 0) {
CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec));
}
// VAD & DTX are disabled after initialization
*vad = false;
*dtx = false;
_writeToFile = false;
}
AudioCodingModule::Codec(*codecCntr, &myCodec);
} while (!STR_CASE_CMP(myCodec.plname, "CN")
|| !STR_CASE_CMP(myCodec.plname, "telephone-event")
|| !STR_CASE_CMP(myCodec.plname, "RED"));
if (!_randomTest) {
fprintf(stdout,"\n=====================================================\n");
fprintf(stdout, " Registering New Codec %s, %d kHz, %d kbps\n",
myCodec.plname, myCodec.plfreq / 1000, myCodec.rate / 1000);
}
//std::cout<< std::flush;
// NO DTX for supe-wideband codec at this point
if (myCodec.plfreq == 32000) {
*dtx = false;
CHECK_ERROR_MT(myACM->SetVAD(*dtx, *vad, *mode));
}
CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec));
myChannel->ResetStats();
{
WriteLockScoped wl(_apiTestRWLock);
*thereIsEncoder = true;
}
Wait(500);
}
} // namespace webrtc