1603 lines
43 KiB
C++
1603 lines
43 KiB
C++
/*
|
|
* 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 <cctype>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
|
|
#include "APITest.h"
|
|
#include "thread_wrapper.h"
|
|
#include "event_wrapper.h"
|
|
#include "tick_util.h"
|
|
#include "trace.h"
|
|
#include "utility.h"
|
|
#include "common_types.h"
|
|
#include "engine_configurations.h"
|
|
|
|
#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{throw S; exit(1);}
|
|
|
|
using namespace webrtc;
|
|
|
|
void
|
|
APITest::Wait(WebRtc_UWord32 waitLengthMs)
|
|
{
|
|
if(_randomTest)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
myEvent->Wait(waitLengthMs);
|
|
delete myEvent;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
APITest::APITest():
|
|
_acmA(NULL),
|
|
_acmB(NULL),
|
|
_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),
|
|
_testCntrA(1),
|
|
_testCntrB(1),
|
|
_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;
|
|
}
|
|
|
|
for(n = 0; n < 3; n++)
|
|
{
|
|
_receiveVADActivityA[n] = 0;
|
|
_receiveVADActivityB[n] = 0;
|
|
}
|
|
|
|
_movingDot[40] = '\0';
|
|
|
|
for(int n = 0; n <40; n++)
|
|
{
|
|
_movingDot[n] = ' ';
|
|
}
|
|
}
|
|
|
|
APITest::~APITest()
|
|
{
|
|
DESTROY_ACM(_acmA);
|
|
DESTROY_ACM(_acmB);
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
//WebRtc_Word16
|
|
//APITest::SetInFile(char* fileName, WebRtc_UWord16 frequencyHz)
|
|
//{
|
|
// return _inFile.Open(fileName, frequencyHz, "rb");
|
|
//}
|
|
//
|
|
//WebRtc_Word16
|
|
//APITest::SetOutFile(char* fileName, WebRtc_UWord16 frequencyHz)
|
|
//{
|
|
// return _outFile.Open(fileName, frequencyHz, "wb");
|
|
//}
|
|
|
|
WebRtc_Word16
|
|
APITest::SetUp()
|
|
{
|
|
_acmA = AudioCodingModule::Create(1);
|
|
_acmB = AudioCodingModule::Create(2);
|
|
|
|
CodecInst dummyCodec;
|
|
int lastPayloadType = 0;
|
|
|
|
WebRtc_Word16 numCodecs = _acmA->NumberOfCodecs();
|
|
for(WebRtc_UWord8 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;
|
|
int currentPayloadType = dummyCodec.pltype;
|
|
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((WebRtc_UWord8)_codecCntrA, dummyCodec);
|
|
CHECK_ERROR_MT(_acmA->RegisterSendCodec(dummyCodec));
|
|
_thereIsEncoderA = true;
|
|
//
|
|
AudioCodingModule::Codec((WebRtc_UWord8)_codecCntrB, dummyCodec);
|
|
CHECK_ERROR_MT(_acmB->RegisterSendCodec(dummyCodec));
|
|
_thereIsEncoderB = true;
|
|
|
|
char fileName[500];
|
|
WebRtc_UWord16 frequencyHz;
|
|
|
|
printf("\n\nAPI Test\n");
|
|
printf("========\n");
|
|
printf("Hit enter to accept the default values indicated in []\n\n");
|
|
|
|
//--- Input A
|
|
strcpy(fileName, "./modules/audio_coding/main/test/testfile32kHz.pcm");
|
|
frequencyHz = 32000;
|
|
printf("Enter input file at side A [%s]: ", fileName);
|
|
PCMFile::ChooseFile(fileName, 499, &frequencyHz);
|
|
_inFileA.Open(fileName, frequencyHz, "rb", true);
|
|
|
|
//--- Output A
|
|
strcpy(fileName, "./modules/audio_coding/main/test/outA.pcm");
|
|
printf("Enter output file at side A [%s]: ", fileName);
|
|
PCMFile::ChooseFile(fileName, 499, &frequencyHz);
|
|
_outFileA.Open(fileName, frequencyHz, "wb");
|
|
|
|
//--- Input B
|
|
strcpy(fileName, "./modules/audio_coding/main/test/testfile32kHz.pcm");
|
|
printf("\n\nEnter input file at side B [%s]: ", fileName);
|
|
PCMFile::ChooseFile(fileName, 499, &frequencyHz);
|
|
_inFileB.Open(fileName, frequencyHz, "rb", true);
|
|
|
|
//--- Output B
|
|
strcpy(fileName, "./modules/audio_coding/main/test/outB.pcm");
|
|
printf("Enter output file at side B [%s]: ", fileName);
|
|
PCMFile::ChooseFile(fileName, 499, &frequencyHz);
|
|
_outFileB.Open(fileName, frequencyHz, "wb");
|
|
|
|
//--- Set A-to-B channel
|
|
_channel_A2B = new Channel(2);
|
|
CHECK_ERROR_MT(_acmA->RegisterTransportCallback(_channel_A2B));
|
|
_channel_A2B->RegisterReceiverACM(_acmB);
|
|
|
|
//--- Set B-to-A channel
|
|
_channel_B2A = new Channel(1);
|
|
CHECK_ERROR_MT(_acmB->RegisterTransportCallback(_channel_B2A));
|
|
_channel_B2A->RegisterReceiverACM(_acmA);
|
|
|
|
//--- 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];
|
|
|
|
printf("\nRandom Test (y/n)?");
|
|
fgets(print, 10, stdin);
|
|
print[10] = '\0';
|
|
if(strstr(print, "y") != NULL)
|
|
{
|
|
_randomTest = true;
|
|
_verbose = false;
|
|
_writeToFile = false;
|
|
Trace::CreateTrace();
|
|
Trace::SetTraceFile("ACMAPITest.txt");
|
|
//freopen("APITest_log.txt", "w", stdout);
|
|
}
|
|
else
|
|
{
|
|
Trace::CreateTrace();
|
|
Trace::SetTraceFile("ACMAPITest.txt", true);
|
|
_randomTest = false;
|
|
printf("\nPrint Tests (y/n)? ");
|
|
fgets(print, 10, stdin);
|
|
print[10] = '\0';
|
|
if(strstr(print, "y") == NULL)
|
|
{
|
|
freopen("APITest_log.txt", "w", stdout);
|
|
_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);
|
|
}
|
|
_receiveVADActivityA[(int)audioFrame._vadActivity]++;
|
|
}
|
|
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);
|
|
}
|
|
_receiveVADActivityB[(int)audioFrame._vadActivity]++;
|
|
}
|
|
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() % 6)) % 7;
|
|
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() % 6)) % 7;
|
|
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;
|
|
case 5:
|
|
TestReceiverVAD('A');
|
|
break;
|
|
case 6:
|
|
#ifdef WEBRTC_DTMF_DETECTION
|
|
LookForDTMF('A');
|
|
#endif
|
|
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');
|
|
TestReceiverVAD('A');
|
|
#ifdef WEBRTC_DTMF_DETECTION
|
|
LookForDTMF('A');
|
|
#endif
|
|
}
|
|
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();
|
|
WebRtc_UWord64 startTime = TickTime::MillisecondTimestamp();
|
|
WebRtc_UWord64 currentTime;
|
|
do
|
|
{
|
|
{
|
|
//ReadLockScoped rl(_apiTestRWLock);
|
|
//fprintf(stderr, "\r%s", _movingDot);
|
|
}
|
|
//fflush(stderr);
|
|
completeEvent->Wait(50);
|
|
currentTime = TickTime::MillisecondTimestamp();
|
|
} while((currentTime - startTime) < 120000); // Run test in 2 minutes (120000 ms)
|
|
|
|
//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;
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
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;
|
|
WebRtc_Word32* myMinDelay;
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
|
|
WebRtc_UWord32 inTimestamp = 0;
|
|
WebRtc_UWord32 outTimestamp = 0;
|
|
double estimDelay = 0;
|
|
WebRtc_UWord16 delay = 0;
|
|
|
|
double averageEstimDelay = 0;
|
|
double averageDelay = 0;
|
|
|
|
CircularBuffer estimDelayCB(100);
|
|
CircularBuffer delayCB(100);
|
|
estimDelayCB.SetArithMean(true);
|
|
delayCB.SetArithMean(true);
|
|
|
|
|
|
if(side == 'A')
|
|
{
|
|
myACM = _acmA;
|
|
myChannel = _channel_B2A;
|
|
myMinDelay = &_minDelayA;
|
|
}
|
|
else
|
|
{
|
|
myACM = _acmB;
|
|
myChannel = _channel_A2B;
|
|
myMinDelay = &_minDelayB;
|
|
}
|
|
|
|
|
|
CHECK_ERROR_MT(myACM->SetMinimumPlayoutDelay(*myMinDelay));
|
|
|
|
|
|
inTimestamp = myChannel->LastInTimestamp();
|
|
CHECK_ERROR_MT(myACM->PlayoutTimestamp(outTimestamp));
|
|
CHECK_ERROR_MT(myACM->Delay(delay));
|
|
|
|
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)((WebRtc_UWord32)(inTimestamp - outTimestamp)) /
|
|
((double)myACM->ReceiveFrequency() / 1000.0);
|
|
|
|
estimDelayCB.Update(estimDelay);
|
|
|
|
estimDelayCB.ArithMean(averageEstimDelay);
|
|
//printf("\n %6.1f \n", estimDelay);
|
|
//std::cout << " " << std::flush;
|
|
|
|
CHECK_ERROR_MT(myACM->Delay(delay));
|
|
delayCB.Update(delay);
|
|
delayCB.ArithMean(averageDelay);
|
|
|
|
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;
|
|
|
|
ACMJitterStatistics jitterStat;
|
|
ACMNetworkStatistics networkStat;
|
|
CHECK_ERROR_MT(myACM->JitterStatistics(jitterStat));
|
|
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, "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, "\n\nJitter Statistics at side %c\n", side);
|
|
fprintf(stdout, "--------------------------------------\n");
|
|
fprintf(stdout, "Jitter buffer min size....... %d\n", jitterStat.jbMinSize);
|
|
fprintf(stdout, "Jitter buffer Max size....... %d\n", jitterStat.jbMaxSize);
|
|
fprintf(stdout, "Jitter buffer Average size... %d\n", jitterStat.jbAvgSize);
|
|
fprintf(stdout, "Change Count................. %d ms\n", jitterStat.jbChangeCount);
|
|
fprintf(stdout, "Late Loss.................... %d ms\n", jitterStat.lateLossMs);
|
|
fprintf(stdout, "Accelerate................... %d ms\n", jitterStat.accelerateMs);
|
|
fprintf(stdout, "Flushed...................... %d ms\n", jitterStat.flushedMs);
|
|
fprintf(stdout, "Generated Silence............ %d ms\n", jitterStat.generatedSilentMs);
|
|
fprintf(stdout, "Interpolated Voice........... %d ms\n", jitterStat.interpolatedVoiceMs);
|
|
fprintf(stdout, "Interpolated Silence......... %d ms\n", jitterStat.interpolatedSilentMs);
|
|
fprintf(stdout, "No tiny expand............... %d\n", jitterStat.numExpandTiny);
|
|
fprintf(stdout, "No small expand.............. %d\n", jitterStat.numExpandSmall);
|
|
fprintf(stdout, "No Medium expand............. %d\n", jitterStat.numExpandMedium);
|
|
fprintf(stdout, "No long expand............... %d\n", jitterStat.numExpandLong);
|
|
fprintf(stdout, "longest expand............... %d ms\n", jitterStat.longestExpandDurationMs);
|
|
fprintf(stdout, "No IAT 500................... %d ms\n", jitterStat.countIAT500ms);
|
|
fprintf(stdout, "No IAT 1000.................. %d ms\n", jitterStat.countIAT1000ms);
|
|
fprintf(stdout, "No IAT 2000.................. %d ms\n", jitterStat.countIAT2000ms);
|
|
fprintf(stdout, "longest IAT.................. %d ms\n", jitterStat.longestIATms);
|
|
fprintf(stdout, "Min packet delay............. %d ms\n", jitterStat.minPacketDelayMs);
|
|
fprintf(stdout, "Max packet delay............. %d ms\n", jitterStat.maxPacketDelayMs);
|
|
fprintf(stdout, "Average packet delay......... %d ms\n", jitterStat.avgPacketDelayMs);
|
|
}
|
|
|
|
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;
|
|
receiveACM = _acmB;
|
|
thereIsDecoder = &_thereIsDecoderB;
|
|
break;
|
|
}
|
|
case 'B':
|
|
{
|
|
sendACM = _acmB;
|
|
receiveACM = _acmA;
|
|
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))
|
|
{
|
|
WebRtc_Word32 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;
|
|
ACMBackgroundNoiseMode* bgnMode;
|
|
switch(receiveSide)
|
|
{
|
|
case 'A':
|
|
{
|
|
receiveACM = _acmA;
|
|
playoutMode = &_playoutModeA;
|
|
bgnMode = &_bgnModeA;
|
|
break;
|
|
}
|
|
case 'B':
|
|
{
|
|
receiveACM = _acmB;
|
|
playoutMode = &_playoutModeB;
|
|
bgnMode = &_bgnModeB;
|
|
break;
|
|
}
|
|
default:
|
|
receiveACM = _acmA;
|
|
}
|
|
|
|
WebRtc_Word32 receiveFreqHz = receiveACM->ReceiveFrequency();
|
|
WebRtc_Word32 playoutFreqHz = receiveACM->PlayoutFrequency();
|
|
|
|
CHECK_ERROR_MT(receiveFreqHz);
|
|
CHECK_ERROR_MT(playoutFreqHz);
|
|
|
|
char bgnString[25];
|
|
switch(*bgnMode)
|
|
{
|
|
case On:
|
|
{
|
|
*bgnMode = Fade;
|
|
strncpy(bgnString, "Fade", 25);
|
|
break;
|
|
}
|
|
case Fade:
|
|
{
|
|
*bgnMode = Off;
|
|
strncpy(bgnString, "OFF", 25);
|
|
break;
|
|
}
|
|
case Off:
|
|
{
|
|
*bgnMode = On;
|
|
strncpy(bgnString, "ON", 25);
|
|
break;
|
|
}
|
|
default:
|
|
*bgnMode = On;
|
|
strncpy(bgnString, "ON", 25);
|
|
}
|
|
CHECK_ERROR_MT(receiveACM->SetBackgroundNoiseMode(*bgnMode));
|
|
bgnString[24] = '\0';
|
|
|
|
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);
|
|
fprintf(stdout, "Background Noise Mode... %s\n", bgnString);
|
|
}
|
|
}
|
|
|
|
// set/get receiver VAD status & mode.
|
|
void
|
|
APITest::TestReceiverVAD(char side)
|
|
{
|
|
AudioCodingModule* myACM;
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
WebRtc_UWord64* myReceiveVADActivity;
|
|
|
|
if(side == 'A')
|
|
{
|
|
myACM = _acmA;
|
|
myReceiveVADActivity = _receiveVADActivityA;
|
|
}
|
|
else
|
|
{
|
|
myACM = _acmB;
|
|
myReceiveVADActivity = _receiveVADActivityB;
|
|
}
|
|
|
|
bool vadStatus = myACM->ReceiveVADStatus();
|
|
ACMVADMode mode = myACM->ReceiveVADMode();
|
|
|
|
CHECK_ERROR_MT(mode);
|
|
|
|
if(!_randomTest)
|
|
{
|
|
fprintf(stdout, "\n\nCurrent Receive VAD at side %c\n", side);
|
|
fprintf(stdout, "----------------------------------\n");
|
|
fprintf(stdout, "Status........ %s\n", vadStatus? "ON":"OFF");
|
|
fprintf(stdout, "mode.......... %d\n", (int)mode);
|
|
fprintf(stdout, "VAD Active.... %llu\n", myReceiveVADActivity[0]);
|
|
fprintf(stdout, "VAD Passive... %llu\n", myReceiveVADActivity[1]);
|
|
fprintf(stdout, "VAD Unknown... %llu\n", myReceiveVADActivity[2]);
|
|
}
|
|
|
|
if(vadStatus)
|
|
{
|
|
if(!_randomTest)
|
|
{
|
|
fprintf(stdout, "\nChange Receive VAD at side %c\n\n", side);
|
|
}
|
|
|
|
switch(mode)
|
|
{
|
|
case VADNormal:
|
|
mode = VADAggr;
|
|
break;
|
|
case VADLowBitrate:
|
|
mode = VADVeryAggr;
|
|
break;
|
|
case VADAggr:
|
|
mode = VADLowBitrate;
|
|
break;
|
|
case VADVeryAggr:
|
|
vadStatus = false;
|
|
mode = VADNormal;
|
|
break;
|
|
default:
|
|
mode = VADNormal;
|
|
}
|
|
|
|
CHECK_ERROR_MT(myACM->SetReceiveVADMode(mode));
|
|
CHECK_ERROR_MT(myACM->SetReceiveVADStatus(vadStatus));
|
|
}
|
|
else
|
|
{
|
|
if(!_randomTest)
|
|
{
|
|
fprintf(stdout, "\nTurn on Receive VAD at side %c\n\n", side);
|
|
}
|
|
CHECK_ERROR_MT(myACM->SetReceiveVADStatus(true));
|
|
CHECK_ERROR_MT(myACM->SetReceiveVADMode(VADNormal));
|
|
}
|
|
for(int n = 0; n < 3; n++)
|
|
{
|
|
myReceiveVADActivity[n] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
AudioCodingModule::Codec(_codecCntrB, myCodec);
|
|
vad = &_sendVADB;
|
|
dtx = &_sendDTXB;
|
|
mode = &_sendVADModeB;
|
|
myChannel = _channel_B2A;
|
|
myACM = _acmB;
|
|
}
|
|
|
|
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;
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
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;
|
|
WebRtc_UWord8* codecCntr;
|
|
bool* thereIsEncoder;
|
|
bool* vad;
|
|
bool* dtx;
|
|
ACMVADMode* mode;
|
|
Channel* myChannel;
|
|
EventWrapper* myEvent = EventWrapper::Create();
|
|
// Reset and Wait
|
|
if(!_randomTest)
|
|
{
|
|
fprintf(stdout, "Reset Encoder Side A \n");
|
|
}
|
|
if(side == 'A')
|
|
{
|
|
myACM = _acmA;
|
|
codecCntr = &_codecCntrA;
|
|
{
|
|
WriteLockScoped wl(_apiTestRWLock);
|
|
thereIsEncoder = &_thereIsEncoderA;
|
|
}
|
|
vad = &_sendVADA;
|
|
dtx = &_sendDTXA;
|
|
mode = &_sendVADModeA;
|
|
myChannel = _channel_A2B;
|
|
}
|
|
else
|
|
{
|
|
myACM = _acmB;
|
|
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) >= 0)
|
|
{
|
|
CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec));
|
|
}
|
|
if(AudioCodingModule::Codec("CN", myCodec, 16000) >= 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);
|
|
}
|
|
|
|
|
|
void
|
|
APITest::LookForDTMF(char side)
|
|
{
|
|
if(!_randomTest)
|
|
{
|
|
fprintf(stdout, "\n\nLooking for DTMF Signal in Side %c\n", side);
|
|
fprintf(stdout, "----------------------------------------\n");
|
|
}
|
|
|
|
if(side == 'A')
|
|
{
|
|
_acmB->RegisterIncomingMessagesCallback(NULL);
|
|
_acmA->RegisterIncomingMessagesCallback(_dtmfCallback);
|
|
Wait(1000);
|
|
_acmA->RegisterIncomingMessagesCallback(NULL);
|
|
}
|
|
else
|
|
{
|
|
_acmA->RegisterIncomingMessagesCallback(NULL);
|
|
_acmB->RegisterIncomingMessagesCallback(_dtmfCallback);
|
|
Wait(1000);
|
|
_acmB->RegisterIncomingMessagesCallback(NULL);
|
|
}
|
|
}
|