audio_coding: remove "main" directory
This is the last piece of the old directory layout of the modules. Duplicated header files are left in audio_coding/main/include until downstream code is updated to the new location. They have pragma warnings added to them and identical header guards as the new headers to avoid breaking things. BUG=webrtc:5095 TESTED=Passing compile-trybots with --clobber flag: git cl try --clobber --bot=win_compile_rel --bot=linux_compile_rel --bot=android_compile_rel --bot=mac_compile_rel --bot=ios_rel --bot=linux_gn_rel --bot=win_x64_gn_rel --bot=mac_x64_gn_rel --bot=android_gn_rel -m tryserver.webrtc NOTRY=True NOPRESUBMIT=True Review URL: https://codereview.webrtc.org/1481493004 Cr-Commit-Position: refs/heads/master@{#10803}
This commit is contained in:
21
webrtc/modules/audio_coding/test/ACMTest.h
Normal file
21
webrtc/modules/audio_coding/test/ACMTest.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_
|
||||
|
||||
class ACMTest {
|
||||
public:
|
||||
ACMTest() {}
|
||||
virtual ~ACMTest() {}
|
||||
virtual void Perform() = 0;
|
||||
};
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ACMTEST_H_
|
||||
1114
webrtc/modules/audio_coding/test/APITest.cc
Normal file
1114
webrtc/modules/audio_coding/test/APITest.cc
Normal file
File diff suppressed because it is too large
Load Diff
163
webrtc/modules/audio_coding/test/APITest.h
Normal file
163
webrtc/modules/audio_coding/test/APITest.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/event_wrapper.h"
|
||||
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Config;
|
||||
|
||||
enum APITESTAction {
|
||||
TEST_CHANGE_CODEC_ONLY = 0,
|
||||
DTX_TEST = 1
|
||||
};
|
||||
|
||||
class APITest : public ACMTest {
|
||||
public:
|
||||
explicit APITest(const Config& config);
|
||||
~APITest();
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
int16_t SetUp();
|
||||
|
||||
static bool PushAudioThreadA(void* obj);
|
||||
static bool PullAudioThreadA(void* obj);
|
||||
static bool ProcessThreadA(void* obj);
|
||||
static bool APIThreadA(void* obj);
|
||||
|
||||
static bool PushAudioThreadB(void* obj);
|
||||
static bool PullAudioThreadB(void* obj);
|
||||
static bool ProcessThreadB(void* obj);
|
||||
static bool APIThreadB(void* obj);
|
||||
|
||||
void CheckVADStatus(char side);
|
||||
|
||||
// Set Min delay, get delay, playout timestamp
|
||||
void TestDelay(char side);
|
||||
|
||||
// Unregister a codec & register again.
|
||||
void TestRegisteration(char side);
|
||||
|
||||
// Playout Mode, background noise mode.
|
||||
// Receiver Frequency, playout frequency.
|
||||
void TestPlayout(char receiveSide);
|
||||
|
||||
//
|
||||
void TestSendVAD(char side);
|
||||
|
||||
void CurrentCodec(char side);
|
||||
|
||||
void ChangeCodec(char side);
|
||||
|
||||
void Wait(uint32_t waitLengthMs);
|
||||
|
||||
void RunTest(char thread);
|
||||
|
||||
bool PushAudioRunA();
|
||||
bool PullAudioRunA();
|
||||
bool ProcessRunA();
|
||||
bool APIRunA();
|
||||
|
||||
bool PullAudioRunB();
|
||||
bool PushAudioRunB();
|
||||
bool ProcessRunB();
|
||||
bool APIRunB();
|
||||
|
||||
//--- ACMs
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmB;
|
||||
|
||||
//--- Channels
|
||||
Channel* _channel_A2B;
|
||||
Channel* _channel_B2A;
|
||||
|
||||
//--- I/O files
|
||||
// A
|
||||
PCMFile _inFileA;
|
||||
PCMFile _outFileA;
|
||||
// B
|
||||
PCMFile _outFileB;
|
||||
PCMFile _inFileB;
|
||||
|
||||
//--- I/O params
|
||||
// A
|
||||
int32_t _outFreqHzA;
|
||||
// B
|
||||
int32_t _outFreqHzB;
|
||||
|
||||
// Should we write to file.
|
||||
// we might skip writing to file if we
|
||||
// run the test for a long time.
|
||||
bool _writeToFile;
|
||||
//--- Events
|
||||
// A
|
||||
EventTimerWrapper* _pullEventA; // pulling data from ACM
|
||||
EventTimerWrapper* _pushEventA; // pushing data to ACM
|
||||
EventTimerWrapper* _processEventA; // process
|
||||
EventWrapper* _apiEventA; // API calls
|
||||
// B
|
||||
EventTimerWrapper* _pullEventB; // pulling data from ACM
|
||||
EventTimerWrapper* _pushEventB; // pushing data to ACM
|
||||
EventTimerWrapper* _processEventB; // process
|
||||
EventWrapper* _apiEventB; // API calls
|
||||
|
||||
// keep track of the codec in either side.
|
||||
uint8_t _codecCntrA;
|
||||
uint8_t _codecCntrB;
|
||||
|
||||
// Is set to true if there is no encoder in either side
|
||||
bool _thereIsEncoderA;
|
||||
bool _thereIsEncoderB;
|
||||
bool _thereIsDecoderA;
|
||||
bool _thereIsDecoderB;
|
||||
|
||||
bool _sendVADA;
|
||||
bool _sendDTXA;
|
||||
ACMVADMode _sendVADModeA;
|
||||
|
||||
bool _sendVADB;
|
||||
bool _sendDTXB;
|
||||
ACMVADMode _sendVADModeB;
|
||||
|
||||
int32_t _minDelayA;
|
||||
int32_t _minDelayB;
|
||||
bool _payloadUsed[32];
|
||||
|
||||
bool _verbose;
|
||||
|
||||
int _dotPositionA;
|
||||
int _dotMoveDirectionA;
|
||||
int _dotPositionB;
|
||||
int _dotMoveDirectionB;
|
||||
|
||||
char _movingDot[41];
|
||||
|
||||
VADCallback* _vadCallbackA;
|
||||
VADCallback* _vadCallbackB;
|
||||
RWLockWrapper& _apiTestRWLock;
|
||||
bool _randomTest;
|
||||
int _testNumA;
|
||||
int _testNumB;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_APITEST_H_
|
||||
424
webrtc/modules/audio_coding/test/Channel.cc
Normal file
424
webrtc/modules/audio_coding/test/Channel.cc
Normal file
@ -0,0 +1,424 @@
|
||||
/*
|
||||
* 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/test/Channel.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "webrtc/base/format_macros.h"
|
||||
#include "webrtc/system_wrappers/include/tick_util.h"
|
||||
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
int32_t Channel::SendData(FrameType frameType,
|
||||
uint8_t payloadType,
|
||||
uint32_t timeStamp,
|
||||
const uint8_t* payloadData,
|
||||
size_t payloadSize,
|
||||
const RTPFragmentationHeader* fragmentation) {
|
||||
WebRtcRTPHeader rtpInfo;
|
||||
int32_t status;
|
||||
size_t payloadDataSize = payloadSize;
|
||||
|
||||
rtpInfo.header.markerBit = false;
|
||||
rtpInfo.header.ssrc = 0;
|
||||
rtpInfo.header.sequenceNumber = (external_sequence_number_ < 0) ?
|
||||
_seqNo++ : static_cast<uint16_t>(external_sequence_number_);
|
||||
rtpInfo.header.payloadType = payloadType;
|
||||
rtpInfo.header.timestamp = (external_send_timestamp_ < 0) ? timeStamp :
|
||||
static_cast<uint32_t>(external_send_timestamp_);
|
||||
|
||||
if (frameType == kAudioFrameCN) {
|
||||
rtpInfo.type.Audio.isCNG = true;
|
||||
} else {
|
||||
rtpInfo.type.Audio.isCNG = false;
|
||||
}
|
||||
if (frameType == kEmptyFrame) {
|
||||
// When frame is empty, we should not transmit it. The frame size of the
|
||||
// next non-empty frame will be based on the previous frame size.
|
||||
_useLastFrameSize = _lastFrameSizeSample > 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtpInfo.type.Audio.channel = 1;
|
||||
// Treat fragmentation separately
|
||||
if (fragmentation != NULL) {
|
||||
// If silence for too long, send only new data.
|
||||
if ((fragmentation->fragmentationVectorSize == 2) &&
|
||||
(fragmentation->fragmentationTimeDiff[1] <= 0x3fff)) {
|
||||
// only 0x80 if we have multiple blocks
|
||||
_payloadData[0] = 0x80 + fragmentation->fragmentationPlType[1];
|
||||
size_t REDheader = (fragmentation->fragmentationTimeDiff[1] << 10) +
|
||||
fragmentation->fragmentationLength[1];
|
||||
_payloadData[1] = uint8_t((REDheader >> 16) & 0x000000FF);
|
||||
_payloadData[2] = uint8_t((REDheader >> 8) & 0x000000FF);
|
||||
_payloadData[3] = uint8_t(REDheader & 0x000000FF);
|
||||
|
||||
_payloadData[4] = fragmentation->fragmentationPlType[0];
|
||||
// copy the RED data
|
||||
memcpy(_payloadData + 5,
|
||||
payloadData + fragmentation->fragmentationOffset[1],
|
||||
fragmentation->fragmentationLength[1]);
|
||||
// copy the normal data
|
||||
memcpy(_payloadData + 5 + fragmentation->fragmentationLength[1],
|
||||
payloadData + fragmentation->fragmentationOffset[0],
|
||||
fragmentation->fragmentationLength[0]);
|
||||
payloadDataSize += 5;
|
||||
} else {
|
||||
// single block (newest one)
|
||||
memcpy(_payloadData, payloadData + fragmentation->fragmentationOffset[0],
|
||||
fragmentation->fragmentationLength[0]);
|
||||
payloadDataSize = fragmentation->fragmentationLength[0];
|
||||
rtpInfo.header.payloadType = fragmentation->fragmentationPlType[0];
|
||||
}
|
||||
} else {
|
||||
memcpy(_payloadData, payloadData, payloadDataSize);
|
||||
if (_isStereo) {
|
||||
if (_leftChannel) {
|
||||
memcpy(&_rtpInfo, &rtpInfo, sizeof(WebRtcRTPHeader));
|
||||
_leftChannel = false;
|
||||
rtpInfo.type.Audio.channel = 1;
|
||||
} else {
|
||||
memcpy(&rtpInfo, &_rtpInfo, sizeof(WebRtcRTPHeader));
|
||||
_leftChannel = true;
|
||||
rtpInfo.type.Audio.channel = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_channelCritSect->Enter();
|
||||
if (_saveBitStream) {
|
||||
//fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
|
||||
}
|
||||
|
||||
if (!_isStereo) {
|
||||
CalcStatistics(rtpInfo, payloadSize);
|
||||
}
|
||||
_useLastFrameSize = false;
|
||||
_lastInTimestamp = timeStamp;
|
||||
_totalBytes += payloadDataSize;
|
||||
_channelCritSect->Leave();
|
||||
|
||||
if (_useFECTestWithPacketLoss) {
|
||||
_packetLoss += 1;
|
||||
if (_packetLoss == 3) {
|
||||
_packetLoss = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_packets_to_drop_ > 0) {
|
||||
num_packets_to_drop_--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtpInfo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// TODO(turajs): rewite this method.
|
||||
void Channel::CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize) {
|
||||
int n;
|
||||
if ((rtpInfo.header.payloadType != _lastPayloadType)
|
||||
&& (_lastPayloadType != -1)) {
|
||||
// payload-type is changed.
|
||||
// we have to terminate the calculations on the previous payload type
|
||||
// we ignore the last packet in that payload type just to make things
|
||||
// easier.
|
||||
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
|
||||
if (_lastPayloadType == _payloadStats[n].payloadType) {
|
||||
_payloadStats[n].newPacket = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_lastPayloadType = rtpInfo.header.payloadType;
|
||||
|
||||
bool newPayload = true;
|
||||
ACMTestPayloadStats* currentPayloadStr = NULL;
|
||||
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
|
||||
if (rtpInfo.header.payloadType == _payloadStats[n].payloadType) {
|
||||
newPayload = false;
|
||||
currentPayloadStr = &_payloadStats[n];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!newPayload) {
|
||||
if (!currentPayloadStr->newPacket) {
|
||||
if (!_useLastFrameSize) {
|
||||
_lastFrameSizeSample = (uint32_t) ((uint32_t) rtpInfo.header.timestamp -
|
||||
(uint32_t) currentPayloadStr->lastTimestamp);
|
||||
}
|
||||
assert(_lastFrameSizeSample > 0);
|
||||
int k = 0;
|
||||
for (; k < MAX_NUM_FRAMESIZES; ++k) {
|
||||
if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
|
||||
_lastFrameSizeSample) ||
|
||||
(currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k == MAX_NUM_FRAMESIZES) {
|
||||
// New frame size found but no space to count statistics on it. Skip it.
|
||||
printf("No memory to store statistics for payload %d : frame size %d\n",
|
||||
_lastPayloadType, _lastFrameSizeSample);
|
||||
return;
|
||||
}
|
||||
ACMTestFrameSizeStats* currentFrameSizeStats = &(currentPayloadStr
|
||||
->frameSizeStats[k]);
|
||||
currentFrameSizeStats->frameSizeSample = (int16_t) _lastFrameSizeSample;
|
||||
|
||||
// increment the number of encoded samples.
|
||||
currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
|
||||
// increment the number of recveived packets
|
||||
currentFrameSizeStats->numPackets++;
|
||||
// increment the total number of bytes (this is based on
|
||||
// the previous payload we don't know the frame-size of
|
||||
// the current payload.
|
||||
currentFrameSizeStats->totalPayloadLenByte += currentPayloadStr
|
||||
->lastPayloadLenByte;
|
||||
// store the maximum payload-size (this is based on
|
||||
// the previous payload we don't know the frame-size of
|
||||
// the current payload.
|
||||
if (currentFrameSizeStats->maxPayloadLen
|
||||
< currentPayloadStr->lastPayloadLenByte) {
|
||||
currentFrameSizeStats->maxPayloadLen = currentPayloadStr
|
||||
->lastPayloadLenByte;
|
||||
}
|
||||
// store the current values for the next time
|
||||
currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
|
||||
currentPayloadStr->lastPayloadLenByte = payloadSize;
|
||||
} else {
|
||||
currentPayloadStr->newPacket = false;
|
||||
currentPayloadStr->lastPayloadLenByte = payloadSize;
|
||||
currentPayloadStr->lastTimestamp = rtpInfo.header.timestamp;
|
||||
currentPayloadStr->payloadType = rtpInfo.header.payloadType;
|
||||
memset(currentPayloadStr->frameSizeStats, 0, MAX_NUM_FRAMESIZES *
|
||||
sizeof(ACMTestFrameSizeStats));
|
||||
}
|
||||
} else {
|
||||
n = 0;
|
||||
while (_payloadStats[n].payloadType != -1) {
|
||||
n++;
|
||||
}
|
||||
// first packet
|
||||
_payloadStats[n].newPacket = false;
|
||||
_payloadStats[n].lastPayloadLenByte = payloadSize;
|
||||
_payloadStats[n].lastTimestamp = rtpInfo.header.timestamp;
|
||||
_payloadStats[n].payloadType = rtpInfo.header.payloadType;
|
||||
memset(_payloadStats[n].frameSizeStats, 0, MAX_NUM_FRAMESIZES *
|
||||
sizeof(ACMTestFrameSizeStats));
|
||||
}
|
||||
}
|
||||
|
||||
Channel::Channel(int16_t chID)
|
||||
: _receiverACM(NULL),
|
||||
_seqNo(0),
|
||||
_channelCritSect(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
_bitStreamFile(NULL),
|
||||
_saveBitStream(false),
|
||||
_lastPayloadType(-1),
|
||||
_isStereo(false),
|
||||
_leftChannel(true),
|
||||
_lastInTimestamp(0),
|
||||
_useLastFrameSize(false),
|
||||
_lastFrameSizeSample(0),
|
||||
_packetLoss(0),
|
||||
_useFECTestWithPacketLoss(false),
|
||||
_beginTime(TickTime::MillisecondTimestamp()),
|
||||
_totalBytes(0),
|
||||
external_send_timestamp_(-1),
|
||||
external_sequence_number_(-1),
|
||||
num_packets_to_drop_(0) {
|
||||
int n;
|
||||
int k;
|
||||
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
|
||||
_payloadStats[n].payloadType = -1;
|
||||
_payloadStats[n].newPacket = true;
|
||||
for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
|
||||
_payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
|
||||
_payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
|
||||
_payloadStats[n].frameSizeStats[k].numPackets = 0;
|
||||
_payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
|
||||
_payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
|
||||
}
|
||||
}
|
||||
if (chID >= 0) {
|
||||
_saveBitStream = true;
|
||||
char bitStreamFileName[500];
|
||||
sprintf(bitStreamFileName, "bitStream_%d.dat", chID);
|
||||
_bitStreamFile = fopen(bitStreamFileName, "wb");
|
||||
} else {
|
||||
_saveBitStream = false;
|
||||
}
|
||||
}
|
||||
|
||||
Channel::~Channel() {
|
||||
delete _channelCritSect;
|
||||
}
|
||||
|
||||
void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
|
||||
_receiverACM = acm;
|
||||
return;
|
||||
}
|
||||
|
||||
void Channel::ResetStats() {
|
||||
int n;
|
||||
int k;
|
||||
_channelCritSect->Enter();
|
||||
_lastPayloadType = -1;
|
||||
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
|
||||
_payloadStats[n].payloadType = -1;
|
||||
_payloadStats[n].newPacket = true;
|
||||
for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
|
||||
_payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
|
||||
_payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
|
||||
_payloadStats[n].frameSizeStats[k].numPackets = 0;
|
||||
_payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
|
||||
_payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
|
||||
}
|
||||
}
|
||||
_beginTime = TickTime::MillisecondTimestamp();
|
||||
_totalBytes = 0;
|
||||
_channelCritSect->Leave();
|
||||
}
|
||||
|
||||
int16_t Channel::Stats(CodecInst& codecInst,
|
||||
ACMTestPayloadStats& payloadStats) {
|
||||
_channelCritSect->Enter();
|
||||
int n;
|
||||
payloadStats.payloadType = -1;
|
||||
for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
|
||||
if (_payloadStats[n].payloadType == codecInst.pltype) {
|
||||
memcpy(&payloadStats, &_payloadStats[n], sizeof(ACMTestPayloadStats));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (payloadStats.payloadType == -1) {
|
||||
_channelCritSect->Leave();
|
||||
return -1;
|
||||
}
|
||||
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
|
||||
if (payloadStats.frameSizeStats[n].frameSizeSample == 0) {
|
||||
_channelCritSect->Leave();
|
||||
return 0;
|
||||
}
|
||||
payloadStats.frameSizeStats[n].usageLenSec = (double) payloadStats
|
||||
.frameSizeStats[n].totalEncodedSamples / (double) codecInst.plfreq;
|
||||
|
||||
payloadStats.frameSizeStats[n].rateBitPerSec =
|
||||
payloadStats.frameSizeStats[n].totalPayloadLenByte * 8
|
||||
/ payloadStats.frameSizeStats[n].usageLenSec;
|
||||
|
||||
}
|
||||
_channelCritSect->Leave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Channel::Stats(uint32_t* numPackets) {
|
||||
_channelCritSect->Enter();
|
||||
int k;
|
||||
int n;
|
||||
memset(numPackets, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
|
||||
for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
|
||||
if (_payloadStats[k].payloadType == -1) {
|
||||
break;
|
||||
}
|
||||
numPackets[k] = 0;
|
||||
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
|
||||
if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
|
||||
break;
|
||||
}
|
||||
numPackets[k] += _payloadStats[k].frameSizeStats[n].numPackets;
|
||||
}
|
||||
}
|
||||
_channelCritSect->Leave();
|
||||
}
|
||||
|
||||
void Channel::Stats(uint8_t* payloadType, uint32_t* payloadLenByte) {
|
||||
_channelCritSect->Enter();
|
||||
|
||||
int k;
|
||||
int n;
|
||||
memset(payloadLenByte, 0, MAX_NUM_PAYLOADS * sizeof(uint32_t));
|
||||
for (k = 0; k < MAX_NUM_PAYLOADS; k++) {
|
||||
if (_payloadStats[k].payloadType == -1) {
|
||||
break;
|
||||
}
|
||||
payloadType[k] = (uint8_t) _payloadStats[k].payloadType;
|
||||
payloadLenByte[k] = 0;
|
||||
for (n = 0; n < MAX_NUM_FRAMESIZES; n++) {
|
||||
if (_payloadStats[k].frameSizeStats[n].frameSizeSample == 0) {
|
||||
break;
|
||||
}
|
||||
payloadLenByte[k] += (uint16_t) _payloadStats[k].frameSizeStats[n]
|
||||
.totalPayloadLenByte;
|
||||
}
|
||||
}
|
||||
|
||||
_channelCritSect->Leave();
|
||||
}
|
||||
|
||||
void Channel::PrintStats(CodecInst& codecInst) {
|
||||
ACMTestPayloadStats payloadStats;
|
||||
Stats(codecInst, payloadStats);
|
||||
printf("%s %d kHz\n", codecInst.plname, codecInst.plfreq / 1000);
|
||||
printf("=====================================================\n");
|
||||
if (payloadStats.payloadType == -1) {
|
||||
printf("No Packets are sent with payload-type %d (%s)\n\n",
|
||||
codecInst.pltype, codecInst.plname);
|
||||
return;
|
||||
}
|
||||
for (int k = 0; k < MAX_NUM_FRAMESIZES; k++) {
|
||||
if (payloadStats.frameSizeStats[k].frameSizeSample == 0) {
|
||||
break;
|
||||
}
|
||||
printf("Frame-size.................... %d samples\n",
|
||||
payloadStats.frameSizeStats[k].frameSizeSample);
|
||||
printf("Average Rate.................. %.0f bits/sec\n",
|
||||
payloadStats.frameSizeStats[k].rateBitPerSec);
|
||||
printf("Maximum Payload-Size.......... %" PRIuS " Bytes\n",
|
||||
payloadStats.frameSizeStats[k].maxPayloadLen);
|
||||
printf(
|
||||
"Maximum Instantaneous Rate.... %.0f bits/sec\n",
|
||||
((double) payloadStats.frameSizeStats[k].maxPayloadLen * 8.0
|
||||
* (double) codecInst.plfreq)
|
||||
/ (double) payloadStats.frameSizeStats[k].frameSizeSample);
|
||||
printf("Number of Packets............. %u\n",
|
||||
(unsigned int) payloadStats.frameSizeStats[k].numPackets);
|
||||
printf("Duration...................... %0.3f sec\n\n",
|
||||
payloadStats.frameSizeStats[k].usageLenSec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t Channel::LastInTimestamp() {
|
||||
uint32_t timestamp;
|
||||
_channelCritSect->Enter();
|
||||
timestamp = _lastInTimestamp;
|
||||
_channelCritSect->Leave();
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
double Channel::BitRate() {
|
||||
double rate;
|
||||
uint64_t currTime = TickTime::MillisecondTimestamp();
|
||||
_channelCritSect->Enter();
|
||||
rate = ((double) _totalBytes * 8.0) / (double) (currTime - _beginTime);
|
||||
_channelCritSect->Leave();
|
||||
return rate;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
130
webrtc/modules/audio_coding/test/Channel.h
Normal file
130
webrtc/modules/audio_coding/test/Channel.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class CriticalSectionWrapper;
|
||||
|
||||
#define MAX_NUM_PAYLOADS 50
|
||||
#define MAX_NUM_FRAMESIZES 6
|
||||
|
||||
// TODO(turajs): Write constructor for this structure.
|
||||
struct ACMTestFrameSizeStats {
|
||||
uint16_t frameSizeSample;
|
||||
size_t maxPayloadLen;
|
||||
uint32_t numPackets;
|
||||
uint64_t totalPayloadLenByte;
|
||||
uint64_t totalEncodedSamples;
|
||||
double rateBitPerSec;
|
||||
double usageLenSec;
|
||||
};
|
||||
|
||||
// TODO(turajs): Write constructor for this structure.
|
||||
struct ACMTestPayloadStats {
|
||||
bool newPacket;
|
||||
int16_t payloadType;
|
||||
size_t lastPayloadLenByte;
|
||||
uint32_t lastTimestamp;
|
||||
ACMTestFrameSizeStats frameSizeStats[MAX_NUM_FRAMESIZES];
|
||||
};
|
||||
|
||||
class Channel : public AudioPacketizationCallback {
|
||||
public:
|
||||
|
||||
Channel(int16_t chID = -1);
|
||||
~Channel();
|
||||
|
||||
int32_t SendData(FrameType frameType,
|
||||
uint8_t payloadType,
|
||||
uint32_t timeStamp,
|
||||
const uint8_t* payloadData,
|
||||
size_t payloadSize,
|
||||
const RTPFragmentationHeader* fragmentation) override;
|
||||
|
||||
void RegisterReceiverACM(AudioCodingModule *acm);
|
||||
|
||||
void ResetStats();
|
||||
|
||||
int16_t Stats(CodecInst& codecInst, ACMTestPayloadStats& payloadStats);
|
||||
|
||||
void Stats(uint32_t* numPackets);
|
||||
|
||||
void Stats(uint8_t* payloadType, uint32_t* payloadLenByte);
|
||||
|
||||
void PrintStats(CodecInst& codecInst);
|
||||
|
||||
void SetIsStereo(bool isStereo) {
|
||||
_isStereo = isStereo;
|
||||
}
|
||||
|
||||
uint32_t LastInTimestamp();
|
||||
|
||||
void SetFECTestWithPacketLoss(bool usePacketLoss) {
|
||||
_useFECTestWithPacketLoss = usePacketLoss;
|
||||
}
|
||||
|
||||
double BitRate();
|
||||
|
||||
void set_send_timestamp(uint32_t new_send_ts) {
|
||||
external_send_timestamp_ = new_send_ts;
|
||||
}
|
||||
|
||||
void set_sequence_number(uint16_t new_sequence_number) {
|
||||
external_sequence_number_ = new_sequence_number;
|
||||
}
|
||||
|
||||
void set_num_packets_to_drop(int new_num_packets_to_drop) {
|
||||
num_packets_to_drop_ = new_num_packets_to_drop;
|
||||
}
|
||||
|
||||
private:
|
||||
void CalcStatistics(WebRtcRTPHeader& rtpInfo, size_t payloadSize);
|
||||
|
||||
AudioCodingModule* _receiverACM;
|
||||
uint16_t _seqNo;
|
||||
// 60msec * 32 sample(max)/msec * 2 description (maybe) * 2 bytes/sample
|
||||
uint8_t _payloadData[60 * 32 * 2 * 2];
|
||||
|
||||
CriticalSectionWrapper* _channelCritSect;
|
||||
FILE* _bitStreamFile;
|
||||
bool _saveBitStream;
|
||||
int16_t _lastPayloadType;
|
||||
ACMTestPayloadStats _payloadStats[MAX_NUM_PAYLOADS];
|
||||
bool _isStereo;
|
||||
WebRtcRTPHeader _rtpInfo;
|
||||
bool _leftChannel;
|
||||
uint32_t _lastInTimestamp;
|
||||
bool _useLastFrameSize;
|
||||
uint32_t _lastFrameSizeSample;
|
||||
// FEC Test variables
|
||||
int16_t _packetLoss;
|
||||
bool _useFECTestWithPacketLoss;
|
||||
uint64_t _beginTime;
|
||||
uint64_t _totalBytes;
|
||||
|
||||
// External timing info, defaulted to -1. Only used if they are
|
||||
// non-negative.
|
||||
int64_t external_send_timestamp_;
|
||||
int32_t external_sequence_number_;
|
||||
int num_packets_to_drop_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_CHANNEL_H_
|
||||
351
webrtc/modules/audio_coding/test/EncodeDecodeTest.cc
Normal file
351
webrtc/modules/audio_coding/test/EncodeDecodeTest.cc
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* 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/test/EncodeDecodeTest.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
TestPacketization::TestPacketization(RTPStream *rtpStream, uint16_t frequency)
|
||||
: _rtpStream(rtpStream),
|
||||
_frequency(frequency),
|
||||
_seqNo(0) {
|
||||
}
|
||||
|
||||
TestPacketization::~TestPacketization() {
|
||||
}
|
||||
|
||||
int32_t TestPacketization::SendData(
|
||||
const FrameType /* frameType */, const uint8_t payloadType,
|
||||
const uint32_t timeStamp, const uint8_t* payloadData,
|
||||
const size_t payloadSize,
|
||||
const RTPFragmentationHeader* /* fragmentation */) {
|
||||
_rtpStream->Write(payloadType, timeStamp, _seqNo++, payloadData, payloadSize,
|
||||
_frequency);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Sender::Sender()
|
||||
: _acm(NULL),
|
||||
_pcmFile(),
|
||||
_audioFrame(),
|
||||
_packetization(NULL) {
|
||||
}
|
||||
|
||||
void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string in_file_name, int sample_rate, int channels) {
|
||||
struct CodecInst sendCodec;
|
||||
int noOfCodecs = acm->NumberOfCodecs();
|
||||
int codecNo;
|
||||
|
||||
// Open input file
|
||||
const std::string file_name = webrtc::test::ResourcePath(in_file_name, "pcm");
|
||||
_pcmFile.Open(file_name, sample_rate, "rb");
|
||||
if (channels == 2) {
|
||||
_pcmFile.ReadStereo(true);
|
||||
}
|
||||
|
||||
// Set the codec for the current test.
|
||||
if ((testMode == 0) || (testMode == 1)) {
|
||||
// Set the codec id.
|
||||
codecNo = codeId;
|
||||
} else {
|
||||
// Choose codec on command line.
|
||||
printf("List of supported codec.\n");
|
||||
for (int n = 0; n < noOfCodecs; n++) {
|
||||
EXPECT_EQ(0, acm->Codec(n, &sendCodec));
|
||||
printf("%d %s\n", n, sendCodec.plname);
|
||||
}
|
||||
printf("Choose your codec:");
|
||||
ASSERT_GT(scanf("%d", &codecNo), 0);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, acm->Codec(codecNo, &sendCodec));
|
||||
|
||||
sendCodec.channels = channels;
|
||||
|
||||
EXPECT_EQ(0, acm->RegisterSendCodec(sendCodec));
|
||||
_packetization = new TestPacketization(rtpStream, sendCodec.plfreq);
|
||||
EXPECT_EQ(0, acm->RegisterTransportCallback(_packetization));
|
||||
|
||||
_acm = acm;
|
||||
}
|
||||
|
||||
void Sender::Teardown() {
|
||||
_pcmFile.Close();
|
||||
delete _packetization;
|
||||
}
|
||||
|
||||
bool Sender::Add10MsData() {
|
||||
if (!_pcmFile.EndOfFile()) {
|
||||
EXPECT_GT(_pcmFile.Read10MsData(_audioFrame), 0);
|
||||
int32_t ok = _acm->Add10MsData(_audioFrame);
|
||||
EXPECT_GE(ok, 0);
|
||||
return ok >= 0 ? true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sender::Run() {
|
||||
while (true) {
|
||||
if (!Add10MsData()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Receiver::Receiver()
|
||||
: _playoutLengthSmpls(WEBRTC_10MS_PCM_AUDIO),
|
||||
_payloadSizeBytes(MAX_INCOMING_PAYLOAD) {
|
||||
}
|
||||
|
||||
void Receiver::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string out_file_name, int channels) {
|
||||
struct CodecInst recvCodec = CodecInst();
|
||||
int noOfCodecs;
|
||||
EXPECT_EQ(0, acm->InitializeReceiver());
|
||||
|
||||
noOfCodecs = acm->NumberOfCodecs();
|
||||
for (int i = 0; i < noOfCodecs; i++) {
|
||||
EXPECT_EQ(0, acm->Codec(i, &recvCodec));
|
||||
if (recvCodec.channels == channels)
|
||||
EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
|
||||
// Forces mono/stereo for Opus.
|
||||
if (!strcmp(recvCodec.plname, "opus")) {
|
||||
recvCodec.channels = channels;
|
||||
EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
|
||||
}
|
||||
}
|
||||
|
||||
int playSampFreq;
|
||||
std::string file_name;
|
||||
std::stringstream file_stream;
|
||||
file_stream << webrtc::test::OutputPath() << out_file_name
|
||||
<< static_cast<int>(codeId) << ".pcm";
|
||||
file_name = file_stream.str();
|
||||
_rtpStream = rtpStream;
|
||||
|
||||
if (testMode == 1) {
|
||||
playSampFreq = recvCodec.plfreq;
|
||||
_pcmFile.Open(file_name, recvCodec.plfreq, "wb+");
|
||||
} else if (testMode == 0) {
|
||||
playSampFreq = 32000;
|
||||
_pcmFile.Open(file_name, 32000, "wb+");
|
||||
} else {
|
||||
printf("\nValid output frequencies:\n");
|
||||
printf("8000\n16000\n32000\n-1,");
|
||||
printf("which means output frequency equal to received signal frequency");
|
||||
printf("\n\nChoose output sampling frequency: ");
|
||||
ASSERT_GT(scanf("%d", &playSampFreq), 0);
|
||||
file_name = webrtc::test::OutputPath() + out_file_name + ".pcm";
|
||||
_pcmFile.Open(file_name, playSampFreq, "wb+");
|
||||
}
|
||||
|
||||
_realPayloadSizeBytes = 0;
|
||||
_playoutBuffer = new int16_t[WEBRTC_10MS_PCM_AUDIO];
|
||||
_frequency = playSampFreq;
|
||||
_acm = acm;
|
||||
_firstTime = true;
|
||||
}
|
||||
|
||||
void Receiver::Teardown() {
|
||||
delete[] _playoutBuffer;
|
||||
_pcmFile.Close();
|
||||
if (testMode > 1) {
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
}
|
||||
|
||||
bool Receiver::IncomingPacket() {
|
||||
if (!_rtpStream->EndOfFile()) {
|
||||
if (_firstTime) {
|
||||
_firstTime = false;
|
||||
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
|
||||
_payloadSizeBytes, &_nextTime);
|
||||
if (_realPayloadSizeBytes == 0) {
|
||||
if (_rtpStream->EndOfFile()) {
|
||||
_firstTime = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, _acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes,
|
||||
_rtpInfo));
|
||||
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
|
||||
_payloadSizeBytes, &_nextTime);
|
||||
if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
|
||||
_firstTime = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Receiver::PlayoutData() {
|
||||
AudioFrame audioFrame;
|
||||
|
||||
int32_t ok =_acm->PlayoutData10Ms(_frequency, &audioFrame);
|
||||
EXPECT_EQ(0, ok);
|
||||
if (ok < 0){
|
||||
return false;
|
||||
}
|
||||
if (_playoutLengthSmpls == 0) {
|
||||
return false;
|
||||
}
|
||||
_pcmFile.Write10MsData(audioFrame.data_,
|
||||
audioFrame.samples_per_channel_ * audioFrame.num_channels_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Receiver::Run() {
|
||||
uint8_t counter500Ms = 50;
|
||||
uint32_t clock = 0;
|
||||
|
||||
while (counter500Ms > 0) {
|
||||
if (clock == 0 || clock >= _nextTime) {
|
||||
EXPECT_TRUE(IncomingPacket());
|
||||
if (clock == 0) {
|
||||
clock = _nextTime;
|
||||
}
|
||||
}
|
||||
if ((clock % 10) == 0) {
|
||||
if (!PlayoutData()) {
|
||||
clock++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (_rtpStream->EndOfFile()) {
|
||||
counter500Ms--;
|
||||
}
|
||||
clock++;
|
||||
}
|
||||
}
|
||||
|
||||
EncodeDecodeTest::EncodeDecodeTest() {
|
||||
_testMode = 2;
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile(
|
||||
(webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
|
||||
}
|
||||
|
||||
EncodeDecodeTest::EncodeDecodeTest(int testMode) {
|
||||
//testMode == 0 for autotest
|
||||
//testMode == 1 for testing all codecs/parameters
|
||||
//testMode > 1 for specific user-input test (as it was used before)
|
||||
_testMode = testMode;
|
||||
if (_testMode != 0) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile(
|
||||
(webrtc::test::OutputPath() + "acm_encdec_trace.txt").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeDecodeTest::Perform() {
|
||||
int numCodecs = 1;
|
||||
int codePars[3]; // Frequency, packet size, rate.
|
||||
int numPars[52]; // Number of codec parameters sets (freq, pacsize, rate)
|
||||
// to test, for a given codec.
|
||||
|
||||
codePars[0] = 0;
|
||||
codePars[1] = 0;
|
||||
codePars[2] = 0;
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
|
||||
struct CodecInst sendCodecTmp;
|
||||
numCodecs = acm->NumberOfCodecs();
|
||||
|
||||
if (_testMode != 2) {
|
||||
for (int n = 0; n < numCodecs; n++) {
|
||||
EXPECT_EQ(0, acm->Codec(n, &sendCodecTmp));
|
||||
if (STR_CASE_CMP(sendCodecTmp.plname, "telephone-event") == 0) {
|
||||
numPars[n] = 0;
|
||||
} else if (STR_CASE_CMP(sendCodecTmp.plname, "cn") == 0) {
|
||||
numPars[n] = 0;
|
||||
} else if (STR_CASE_CMP(sendCodecTmp.plname, "red") == 0) {
|
||||
numPars[n] = 0;
|
||||
} else if (sendCodecTmp.channels == 2) {
|
||||
numPars[n] = 0;
|
||||
} else {
|
||||
numPars[n] = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
numCodecs = 1;
|
||||
numPars[0] = 1;
|
||||
}
|
||||
|
||||
_receiver.testMode = _testMode;
|
||||
|
||||
// Loop over all mono codecs:
|
||||
for (int codeId = 0; codeId < numCodecs; codeId++) {
|
||||
// Only encode using real mono encoders, not telephone-event and cng.
|
||||
for (int loopPars = 1; loopPars <= numPars[codeId]; loopPars++) {
|
||||
// Encode all data to file.
|
||||
std::string fileName = EncodeToFile(1, codeId, codePars, _testMode);
|
||||
|
||||
RTPFile rtpFile;
|
||||
rtpFile.Open(fileName.c_str(), "rb");
|
||||
|
||||
_receiver.codeId = codeId;
|
||||
|
||||
rtpFile.ReadHeader();
|
||||
_receiver.Setup(acm.get(), &rtpFile, "encodeDecode_out", 1);
|
||||
_receiver.Run();
|
||||
_receiver.Teardown();
|
||||
rtpFile.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// End tracing.
|
||||
if (_testMode == 1) {
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
}
|
||||
|
||||
std::string EncodeDecodeTest::EncodeToFile(int fileType,
|
||||
int codeId,
|
||||
int* codePars,
|
||||
int testMode) {
|
||||
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(1));
|
||||
RTPFile rtpFile;
|
||||
std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
|
||||
"encode_decode_rtp");
|
||||
rtpFile.Open(fileName.c_str(), "wb+");
|
||||
rtpFile.WriteHeader();
|
||||
|
||||
// Store for auto_test and logging.
|
||||
_sender.testMode = testMode;
|
||||
_sender.codeId = codeId;
|
||||
|
||||
_sender.Setup(acm.get(), &rtpFile, "audio_coding/testfile32kHz", 32000, 1);
|
||||
if (acm->SendCodec()) {
|
||||
_sender.Run();
|
||||
}
|
||||
_sender.Teardown();
|
||||
rtpFile.Close();
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
123
webrtc/modules/audio_coding/test/EncodeDecodeTest.h
Normal file
123
webrtc/modules/audio_coding/test/EncodeDecodeTest.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/RTPFile.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#define MAX_INCOMING_PAYLOAD 8096
|
||||
|
||||
// TestPacketization callback which writes the encoded payloads to file
|
||||
class TestPacketization : public AudioPacketizationCallback {
|
||||
public:
|
||||
TestPacketization(RTPStream *rtpStream, uint16_t frequency);
|
||||
~TestPacketization();
|
||||
int32_t SendData(const FrameType frameType,
|
||||
const uint8_t payloadType,
|
||||
const uint32_t timeStamp,
|
||||
const uint8_t* payloadData,
|
||||
const size_t payloadSize,
|
||||
const RTPFragmentationHeader* fragmentation) override;
|
||||
|
||||
private:
|
||||
static void MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
|
||||
int16_t seqNo, uint32_t timeStamp, uint32_t ssrc);
|
||||
RTPStream* _rtpStream;
|
||||
int32_t _frequency;
|
||||
int16_t _seqNo;
|
||||
};
|
||||
|
||||
class Sender {
|
||||
public:
|
||||
Sender();
|
||||
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string in_file_name, int sample_rate, int channels);
|
||||
void Teardown();
|
||||
void Run();
|
||||
bool Add10MsData();
|
||||
|
||||
//for auto_test and logging
|
||||
uint8_t testMode;
|
||||
uint8_t codeId;
|
||||
|
||||
protected:
|
||||
AudioCodingModule* _acm;
|
||||
|
||||
private:
|
||||
PCMFile _pcmFile;
|
||||
AudioFrame _audioFrame;
|
||||
TestPacketization* _packetization;
|
||||
};
|
||||
|
||||
class Receiver {
|
||||
public:
|
||||
Receiver();
|
||||
virtual ~Receiver() {};
|
||||
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string out_file_name, int channels);
|
||||
void Teardown();
|
||||
void Run();
|
||||
virtual bool IncomingPacket();
|
||||
bool PlayoutData();
|
||||
|
||||
//for auto_test and logging
|
||||
uint8_t codeId;
|
||||
uint8_t testMode;
|
||||
|
||||
private:
|
||||
PCMFile _pcmFile;
|
||||
int16_t* _playoutBuffer;
|
||||
uint16_t _playoutLengthSmpls;
|
||||
int32_t _frequency;
|
||||
bool _firstTime;
|
||||
|
||||
protected:
|
||||
AudioCodingModule* _acm;
|
||||
uint8_t _incomingPayload[MAX_INCOMING_PAYLOAD];
|
||||
RTPStream* _rtpStream;
|
||||
WebRtcRTPHeader _rtpInfo;
|
||||
size_t _realPayloadSizeBytes;
|
||||
size_t _payloadSizeBytes;
|
||||
uint32_t _nextTime;
|
||||
};
|
||||
|
||||
class EncodeDecodeTest : public ACMTest {
|
||||
public:
|
||||
EncodeDecodeTest();
|
||||
explicit EncodeDecodeTest(int testMode);
|
||||
void Perform() override;
|
||||
|
||||
uint16_t _playoutFreq;
|
||||
uint8_t _testMode;
|
||||
|
||||
private:
|
||||
std::string EncodeToFile(int fileType,
|
||||
int codeId,
|
||||
int* codePars,
|
||||
int testMode);
|
||||
|
||||
protected:
|
||||
Sender _sender;
|
||||
Receiver _receiver;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
|
||||
204
webrtc/modules/audio_coding/test/PCMFile.cc
Normal file
204
webrtc/modules/audio_coding/test/PCMFile.cc
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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 "PCMFile.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#define MAX_FILE_NAME_LENGTH_BYTE 500
|
||||
|
||||
PCMFile::PCMFile()
|
||||
: pcm_file_(NULL),
|
||||
samples_10ms_(160),
|
||||
frequency_(16000),
|
||||
end_of_file_(false),
|
||||
auto_rewind_(false),
|
||||
rewinded_(false),
|
||||
read_stereo_(false),
|
||||
save_stereo_(false) {
|
||||
timestamp_ = (((uint32_t) rand() & 0x0000FFFF) << 16) |
|
||||
((uint32_t) rand() & 0x0000FFFF);
|
||||
}
|
||||
|
||||
PCMFile::PCMFile(uint32_t timestamp)
|
||||
: pcm_file_(NULL),
|
||||
samples_10ms_(160),
|
||||
frequency_(16000),
|
||||
end_of_file_(false),
|
||||
auto_rewind_(false),
|
||||
rewinded_(false),
|
||||
read_stereo_(false),
|
||||
save_stereo_(false) {
|
||||
timestamp_ = timestamp;
|
||||
}
|
||||
|
||||
int16_t PCMFile::ChooseFile(std::string* file_name, int16_t max_len,
|
||||
uint16_t* frequency_hz) {
|
||||
char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
|
||||
|
||||
EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
|
||||
tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
|
||||
int16_t n = 0;
|
||||
|
||||
// Removing trailing spaces.
|
||||
while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (tmp_name[n] != 0)
|
||||
&& (n < MAX_FILE_NAME_LENGTH_BYTE)) {
|
||||
n++;
|
||||
}
|
||||
if (n > 0) {
|
||||
memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
|
||||
}
|
||||
|
||||
// Removing trailing spaces.
|
||||
n = (int16_t)(strlen(tmp_name) - 1);
|
||||
if (n >= 0) {
|
||||
while ((isspace(tmp_name[n]) || iscntrl(tmp_name[n])) && (n >= 0)) {
|
||||
n--;
|
||||
}
|
||||
}
|
||||
if (n >= 0) {
|
||||
tmp_name[n + 1] = '\0';
|
||||
}
|
||||
|
||||
int16_t len = (int16_t) strlen(tmp_name);
|
||||
if (len > max_len) {
|
||||
return -1;
|
||||
}
|
||||
if (len > 0) {
|
||||
std::string tmp_string(tmp_name, len + 1);
|
||||
*file_name = tmp_string;
|
||||
}
|
||||
printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
|
||||
*frequency_hz);
|
||||
EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
|
||||
uint16_t tmp_frequency = (uint16_t) atoi(tmp_name);
|
||||
if (tmp_frequency > 0) {
|
||||
*frequency_hz = tmp_frequency;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PCMFile::Open(const std::string& file_name, uint16_t frequency,
|
||||
const char* mode, bool auto_rewind) {
|
||||
if ((pcm_file_ = fopen(file_name.c_str(), mode)) == NULL) {
|
||||
printf("Cannot open file %s.\n", file_name.c_str());
|
||||
ADD_FAILURE() << "Unable to read file";
|
||||
}
|
||||
frequency_ = frequency;
|
||||
samples_10ms_ = (uint16_t)(frequency_ / 100);
|
||||
auto_rewind_ = auto_rewind;
|
||||
end_of_file_ = false;
|
||||
rewinded_ = false;
|
||||
}
|
||||
|
||||
int32_t PCMFile::SamplingFrequency() const {
|
||||
return frequency_;
|
||||
}
|
||||
|
||||
uint16_t PCMFile::PayloadLength10Ms() const {
|
||||
return samples_10ms_;
|
||||
}
|
||||
|
||||
int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
|
||||
uint16_t channels = 1;
|
||||
if (read_stereo_) {
|
||||
channels = 2;
|
||||
}
|
||||
|
||||
int32_t payload_size = (int32_t) fread(audio_frame.data_, sizeof(uint16_t),
|
||||
samples_10ms_ * channels, pcm_file_);
|
||||
if (payload_size < samples_10ms_ * channels) {
|
||||
for (int k = payload_size; k < samples_10ms_ * channels; k++) {
|
||||
audio_frame.data_[k] = 0;
|
||||
}
|
||||
if (auto_rewind_) {
|
||||
rewind(pcm_file_);
|
||||
rewinded_ = true;
|
||||
} else {
|
||||
end_of_file_ = true;
|
||||
}
|
||||
}
|
||||
audio_frame.samples_per_channel_ = samples_10ms_;
|
||||
audio_frame.sample_rate_hz_ = frequency_;
|
||||
audio_frame.num_channels_ = channels;
|
||||
audio_frame.timestamp_ = timestamp_;
|
||||
timestamp_ += samples_10ms_;
|
||||
return samples_10ms_;
|
||||
}
|
||||
|
||||
void PCMFile::Write10MsData(AudioFrame& audio_frame) {
|
||||
if (audio_frame.num_channels_ == 1) {
|
||||
if (!save_stereo_) {
|
||||
if (fwrite(audio_frame.data_, sizeof(uint16_t),
|
||||
audio_frame.samples_per_channel_, pcm_file_) !=
|
||||
static_cast<size_t>(audio_frame.samples_per_channel_)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int16_t* stereo_audio = new int16_t[2 * audio_frame.samples_per_channel_];
|
||||
for (size_t k = 0; k < audio_frame.samples_per_channel_; k++) {
|
||||
stereo_audio[k << 1] = audio_frame.data_[k];
|
||||
stereo_audio[(k << 1) + 1] = audio_frame.data_[k];
|
||||
}
|
||||
if (fwrite(stereo_audio, sizeof(int16_t),
|
||||
2 * audio_frame.samples_per_channel_, pcm_file_) !=
|
||||
static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
|
||||
return;
|
||||
}
|
||||
delete[] stereo_audio;
|
||||
}
|
||||
} else {
|
||||
if (fwrite(audio_frame.data_, sizeof(int16_t),
|
||||
audio_frame.num_channels_ * audio_frame.samples_per_channel_,
|
||||
pcm_file_) !=
|
||||
static_cast<size_t>(audio_frame.num_channels_ *
|
||||
audio_frame.samples_per_channel_)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCMFile::Write10MsData(int16_t* playout_buffer, size_t length_smpls) {
|
||||
if (fwrite(playout_buffer, sizeof(uint16_t), length_smpls, pcm_file_) !=
|
||||
length_smpls) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void PCMFile::Close() {
|
||||
fclose(pcm_file_);
|
||||
pcm_file_ = NULL;
|
||||
}
|
||||
|
||||
void PCMFile::Rewind() {
|
||||
rewind(pcm_file_);
|
||||
end_of_file_ = false;
|
||||
}
|
||||
|
||||
bool PCMFile::Rewinded() {
|
||||
return rewinded_;
|
||||
}
|
||||
|
||||
void PCMFile::SaveStereo(bool is_stereo) {
|
||||
save_stereo_ = is_stereo;
|
||||
}
|
||||
|
||||
void PCMFile::ReadStereo(bool is_stereo) {
|
||||
read_stereo_ = is_stereo;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
68
webrtc/modules/audio_coding/test/PCMFile.h
Normal file
68
webrtc/modules/audio_coding/test/PCMFile.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class PCMFile {
|
||||
public:
|
||||
PCMFile();
|
||||
PCMFile(uint32_t timestamp);
|
||||
~PCMFile() {
|
||||
if (pcm_file_ != NULL) {
|
||||
fclose(pcm_file_);
|
||||
}
|
||||
}
|
||||
|
||||
void Open(const std::string& filename, uint16_t frequency, const char* mode,
|
||||
bool auto_rewind = false);
|
||||
|
||||
int32_t Read10MsData(AudioFrame& audio_frame);
|
||||
|
||||
void Write10MsData(int16_t *playout_buffer, size_t length_smpls);
|
||||
void Write10MsData(AudioFrame& audio_frame);
|
||||
|
||||
uint16_t PayloadLength10Ms() const;
|
||||
int32_t SamplingFrequency() const;
|
||||
void Close();
|
||||
bool EndOfFile() const {
|
||||
return end_of_file_;
|
||||
}
|
||||
void Rewind();
|
||||
static int16_t ChooseFile(std::string* file_name, int16_t max_len,
|
||||
uint16_t* frequency_hz);
|
||||
bool Rewinded();
|
||||
void SaveStereo(bool is_stereo = true);
|
||||
void ReadStereo(bool is_stereo = true);
|
||||
private:
|
||||
FILE* pcm_file_;
|
||||
uint16_t samples_10ms_;
|
||||
int32_t frequency_;
|
||||
bool end_of_file_;
|
||||
bool auto_rewind_;
|
||||
bool rewinded_;
|
||||
uint32_t timestamp_;
|
||||
bool read_stereo_;
|
||||
bool save_stereo_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_PCMFILE_H_
|
||||
167
webrtc/modules/audio_coding/test/PacketLossTest.cc
Normal file
167
webrtc/modules/audio_coding/test/PacketLossTest.cc
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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/test/PacketLossTest.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
ReceiverWithPacketLoss::ReceiverWithPacketLoss()
|
||||
: loss_rate_(0),
|
||||
burst_length_(1),
|
||||
packet_counter_(0),
|
||||
lost_packet_counter_(0),
|
||||
burst_lost_counter_(burst_length_) {
|
||||
}
|
||||
|
||||
void ReceiverWithPacketLoss::Setup(AudioCodingModule *acm,
|
||||
RTPStream *rtpStream,
|
||||
std::string out_file_name,
|
||||
int channels,
|
||||
int loss_rate,
|
||||
int burst_length) {
|
||||
loss_rate_ = loss_rate;
|
||||
burst_length_ = burst_length;
|
||||
burst_lost_counter_ = burst_length_; // To prevent first packet gets lost.
|
||||
std::stringstream ss;
|
||||
ss << out_file_name << "_" << loss_rate_ << "_" << burst_length_ << "_";
|
||||
Receiver::Setup(acm, rtpStream, ss.str(), channels);
|
||||
}
|
||||
|
||||
bool ReceiverWithPacketLoss::IncomingPacket() {
|
||||
if (!_rtpStream->EndOfFile()) {
|
||||
if (packet_counter_ == 0) {
|
||||
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
|
||||
_payloadSizeBytes, &_nextTime);
|
||||
if (_realPayloadSizeBytes == 0) {
|
||||
if (_rtpStream->EndOfFile()) {
|
||||
packet_counter_ = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!PacketLost()) {
|
||||
_acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes, _rtpInfo);
|
||||
}
|
||||
packet_counter_++;
|
||||
_realPayloadSizeBytes = _rtpStream->Read(&_rtpInfo, _incomingPayload,
|
||||
_payloadSizeBytes, &_nextTime);
|
||||
if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
|
||||
packet_counter_ = 0;
|
||||
lost_packet_counter_ = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReceiverWithPacketLoss::PacketLost() {
|
||||
if (burst_lost_counter_ < burst_length_) {
|
||||
lost_packet_counter_++;
|
||||
burst_lost_counter_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lost_packet_counter_ * 100 < loss_rate_ * packet_counter_) {
|
||||
lost_packet_counter_++;
|
||||
burst_lost_counter_ = 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SenderWithFEC::SenderWithFEC()
|
||||
: expected_loss_rate_(0) {
|
||||
}
|
||||
|
||||
void SenderWithFEC::Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string in_file_name, int sample_rate,
|
||||
int channels, int expected_loss_rate) {
|
||||
Sender::Setup(acm, rtpStream, in_file_name, sample_rate, channels);
|
||||
EXPECT_TRUE(SetFEC(true));
|
||||
EXPECT_TRUE(SetPacketLossRate(expected_loss_rate));
|
||||
}
|
||||
|
||||
bool SenderWithFEC::SetFEC(bool enable_fec) {
|
||||
if (_acm->SetCodecFEC(enable_fec) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SenderWithFEC::SetPacketLossRate(int expected_loss_rate) {
|
||||
if (_acm->SetPacketLossRate(expected_loss_rate) == 0) {
|
||||
expected_loss_rate_ = expected_loss_rate;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PacketLossTest::PacketLossTest(int channels, int expected_loss_rate,
|
||||
int actual_loss_rate, int burst_length)
|
||||
: channels_(channels),
|
||||
in_file_name_(channels_ == 1 ? "audio_coding/testfile32kHz" :
|
||||
"audio_coding/teststereo32kHz"),
|
||||
sample_rate_hz_(32000),
|
||||
sender_(new SenderWithFEC),
|
||||
receiver_(new ReceiverWithPacketLoss),
|
||||
expected_loss_rate_(expected_loss_rate),
|
||||
actual_loss_rate_(actual_loss_rate),
|
||||
burst_length_(burst_length) {
|
||||
}
|
||||
|
||||
void PacketLossTest::Perform() {
|
||||
#ifndef WEBRTC_CODEC_OPUS
|
||||
return;
|
||||
#else
|
||||
rtc::scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
|
||||
|
||||
int codec_id = acm->Codec("opus", 48000, channels_);
|
||||
|
||||
RTPFile rtpFile;
|
||||
std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
|
||||
"packet_loss_test");
|
||||
|
||||
// Encode to file
|
||||
rtpFile.Open(fileName.c_str(), "wb+");
|
||||
rtpFile.WriteHeader();
|
||||
|
||||
sender_->testMode = 0;
|
||||
sender_->codeId = codec_id;
|
||||
|
||||
sender_->Setup(acm.get(), &rtpFile, in_file_name_, sample_rate_hz_, channels_,
|
||||
expected_loss_rate_);
|
||||
if (acm->SendCodec()) {
|
||||
sender_->Run();
|
||||
}
|
||||
sender_->Teardown();
|
||||
rtpFile.Close();
|
||||
|
||||
// Decode to file
|
||||
rtpFile.Open(fileName.c_str(), "rb");
|
||||
rtpFile.ReadHeader();
|
||||
|
||||
receiver_->testMode = 0;
|
||||
receiver_->codeId = codec_id;
|
||||
|
||||
receiver_->Setup(acm.get(), &rtpFile, "packetLoss_out", channels_,
|
||||
actual_loss_rate_, burst_length_);
|
||||
receiver_->Run();
|
||||
receiver_->Teardown();
|
||||
rtpFile.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
67
webrtc/modules/audio_coding/test/PacketLossTest.h
Normal file
67
webrtc/modules/audio_coding/test/PacketLossTest.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
|
||||
|
||||
#include <string>
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/test/EncodeDecodeTest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class ReceiverWithPacketLoss : public Receiver {
|
||||
public:
|
||||
ReceiverWithPacketLoss();
|
||||
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string out_file_name, int channels, int loss_rate,
|
||||
int burst_length);
|
||||
bool IncomingPacket() override;
|
||||
|
||||
protected:
|
||||
bool PacketLost();
|
||||
int loss_rate_;
|
||||
int burst_length_;
|
||||
int packet_counter_;
|
||||
int lost_packet_counter_;
|
||||
int burst_lost_counter_;
|
||||
};
|
||||
|
||||
class SenderWithFEC : public Sender {
|
||||
public:
|
||||
SenderWithFEC();
|
||||
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
|
||||
std::string in_file_name, int sample_rate, int channels,
|
||||
int expected_loss_rate);
|
||||
bool SetPacketLossRate(int expected_loss_rate);
|
||||
bool SetFEC(bool enable_fec);
|
||||
protected:
|
||||
int expected_loss_rate_;
|
||||
};
|
||||
|
||||
class PacketLossTest : public ACMTest {
|
||||
public:
|
||||
PacketLossTest(int channels, int expected_loss_rate_, int actual_loss_rate,
|
||||
int burst_length);
|
||||
void Perform();
|
||||
protected:
|
||||
int channels_;
|
||||
std::string in_file_name_;
|
||||
int sample_rate_hz_;
|
||||
rtc::scoped_ptr<SenderWithFEC> sender_;
|
||||
rtc::scoped_ptr<ReceiverWithPacketLoss> receiver_;
|
||||
int expected_loss_rate_;
|
||||
int actual_loss_rate_;
|
||||
int burst_length_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
|
||||
227
webrtc/modules/audio_coding/test/RTPFile.cc
Normal file
227
webrtc/modules/audio_coding/test/RTPFile.cc
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 "RTPFile.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <Winsock2.h>
|
||||
#else
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#include "audio_coding_module.h"
|
||||
#include "engine_configurations.h"
|
||||
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
|
||||
// TODO(tlegrand): Consider removing usage of gtest.
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void RTPStream::ParseRTPHeader(WebRtcRTPHeader* rtpInfo,
|
||||
const uint8_t* rtpHeader) {
|
||||
rtpInfo->header.payloadType = rtpHeader[1];
|
||||
rtpInfo->header.sequenceNumber = (static_cast<uint16_t>(rtpHeader[2]) << 8) |
|
||||
rtpHeader[3];
|
||||
rtpInfo->header.timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
|
||||
(static_cast<uint32_t>(rtpHeader[5]) << 16) |
|
||||
(static_cast<uint32_t>(rtpHeader[6]) << 8) | rtpHeader[7];
|
||||
rtpInfo->header.ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
|
||||
(static_cast<uint32_t>(rtpHeader[9]) << 16) |
|
||||
(static_cast<uint32_t>(rtpHeader[10]) << 8) | rtpHeader[11];
|
||||
}
|
||||
|
||||
void RTPStream::MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType,
|
||||
int16_t seqNo, uint32_t timeStamp,
|
||||
uint32_t ssrc) {
|
||||
rtpHeader[0] = 0x80;
|
||||
rtpHeader[1] = payloadType;
|
||||
rtpHeader[2] = (seqNo >> 8) & 0xFF;
|
||||
rtpHeader[3] = seqNo & 0xFF;
|
||||
rtpHeader[4] = timeStamp >> 24;
|
||||
rtpHeader[5] = (timeStamp >> 16) & 0xFF;
|
||||
rtpHeader[6] = (timeStamp >> 8) & 0xFF;
|
||||
rtpHeader[7] = timeStamp & 0xFF;
|
||||
rtpHeader[8] = ssrc >> 24;
|
||||
rtpHeader[9] = (ssrc >> 16) & 0xFF;
|
||||
rtpHeader[10] = (ssrc >> 8) & 0xFF;
|
||||
rtpHeader[11] = ssrc & 0xFF;
|
||||
}
|
||||
|
||||
RTPPacket::RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
|
||||
const uint8_t* payloadData, size_t payloadSize,
|
||||
uint32_t frequency)
|
||||
: payloadType(payloadType),
|
||||
timeStamp(timeStamp),
|
||||
seqNo(seqNo),
|
||||
payloadSize(payloadSize),
|
||||
frequency(frequency) {
|
||||
if (payloadSize > 0) {
|
||||
this->payloadData = new uint8_t[payloadSize];
|
||||
memcpy(this->payloadData, payloadData, payloadSize);
|
||||
}
|
||||
}
|
||||
|
||||
RTPPacket::~RTPPacket() {
|
||||
delete[] payloadData;
|
||||
}
|
||||
|
||||
RTPBuffer::RTPBuffer() {
|
||||
_queueRWLock = RWLockWrapper::CreateRWLock();
|
||||
}
|
||||
|
||||
RTPBuffer::~RTPBuffer() {
|
||||
delete _queueRWLock;
|
||||
}
|
||||
|
||||
void RTPBuffer::Write(const uint8_t payloadType, const uint32_t timeStamp,
|
||||
const int16_t seqNo, const uint8_t* payloadData,
|
||||
const size_t payloadSize, uint32_t frequency) {
|
||||
RTPPacket *packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
|
||||
payloadSize, frequency);
|
||||
_queueRWLock->AcquireLockExclusive();
|
||||
_rtpQueue.push(packet);
|
||||
_queueRWLock->ReleaseLockExclusive();
|
||||
}
|
||||
|
||||
size_t RTPBuffer::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
|
||||
size_t payloadSize, uint32_t* offset) {
|
||||
_queueRWLock->AcquireLockShared();
|
||||
RTPPacket *packet = _rtpQueue.front();
|
||||
_rtpQueue.pop();
|
||||
_queueRWLock->ReleaseLockShared();
|
||||
rtpInfo->header.markerBit = 1;
|
||||
rtpInfo->header.payloadType = packet->payloadType;
|
||||
rtpInfo->header.sequenceNumber = packet->seqNo;
|
||||
rtpInfo->header.ssrc = 0;
|
||||
rtpInfo->header.timestamp = packet->timeStamp;
|
||||
if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
|
||||
memcpy(payloadData, packet->payloadData, packet->payloadSize);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
*offset = (packet->timeStamp / (packet->frequency / 1000));
|
||||
|
||||
return packet->payloadSize;
|
||||
}
|
||||
|
||||
bool RTPBuffer::EndOfFile() const {
|
||||
_queueRWLock->AcquireLockShared();
|
||||
bool eof = _rtpQueue.empty();
|
||||
_queueRWLock->ReleaseLockShared();
|
||||
return eof;
|
||||
}
|
||||
|
||||
void RTPFile::Open(const char *filename, const char *mode) {
|
||||
if ((_rtpFile = fopen(filename, mode)) == NULL) {
|
||||
printf("Cannot write file %s.\n", filename);
|
||||
ADD_FAILURE() << "Unable to write file";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void RTPFile::Close() {
|
||||
if (_rtpFile != NULL) {
|
||||
fclose(_rtpFile);
|
||||
_rtpFile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void RTPFile::WriteHeader() {
|
||||
// Write data in a format that NetEQ and RTP Play can parse
|
||||
fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
|
||||
uint32_t dummy_variable = 0;
|
||||
// should be converted to network endian format, but does not matter when 0
|
||||
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
|
||||
fflush(_rtpFile);
|
||||
}
|
||||
|
||||
void RTPFile::ReadHeader() {
|
||||
uint32_t start_sec, start_usec, source;
|
||||
uint16_t port, padding;
|
||||
char fileHeader[40];
|
||||
EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
|
||||
EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
|
||||
start_sec = ntohl(start_sec);
|
||||
EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
|
||||
start_usec = ntohl(start_usec);
|
||||
EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
|
||||
source = ntohl(source);
|
||||
EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
|
||||
port = ntohs(port);
|
||||
EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
|
||||
padding = ntohs(padding);
|
||||
}
|
||||
|
||||
void RTPFile::Write(const uint8_t payloadType, const uint32_t timeStamp,
|
||||
const int16_t seqNo, const uint8_t* payloadData,
|
||||
const size_t payloadSize, uint32_t frequency) {
|
||||
/* write RTP packet to file */
|
||||
uint8_t rtpHeader[12];
|
||||
MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
|
||||
ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
|
||||
uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
|
||||
uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
|
||||
uint32_t offsetMs;
|
||||
|
||||
offsetMs = (timeStamp / (frequency / 1000));
|
||||
offsetMs = htonl(offsetMs);
|
||||
EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
|
||||
EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
|
||||
}
|
||||
|
||||
size_t RTPFile::Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
|
||||
size_t payloadSize, uint32_t* offset) {
|
||||
uint16_t lengthBytes;
|
||||
uint16_t plen;
|
||||
uint8_t rtpHeader[12];
|
||||
size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
|
||||
/* Check if we have reached end of file. */
|
||||
if ((read_len == 0) && feof(_rtpFile)) {
|
||||
_rtpEOF = true;
|
||||
return 0;
|
||||
}
|
||||
EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
|
||||
EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
|
||||
lengthBytes = ntohs(lengthBytes);
|
||||
plen = ntohs(plen);
|
||||
*offset = ntohl(*offset);
|
||||
EXPECT_GT(plen, 11);
|
||||
|
||||
EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
|
||||
ParseRTPHeader(rtpInfo, rtpHeader);
|
||||
rtpInfo->type.Audio.isCNG = false;
|
||||
rtpInfo->type.Audio.channel = 1;
|
||||
EXPECT_EQ(lengthBytes, plen + 8);
|
||||
|
||||
if (plen == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (lengthBytes < 20) {
|
||||
return 0;
|
||||
}
|
||||
if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
|
||||
return 0;
|
||||
}
|
||||
lengthBytes -= 20;
|
||||
EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
|
||||
return lengthBytes;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
126
webrtc/modules/audio_coding/test/RTPFile.h
Normal file
126
webrtc/modules/audio_coding/test/RTPFile.h
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <queue>
|
||||
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RTPStream {
|
||||
public:
|
||||
virtual ~RTPStream() {
|
||||
}
|
||||
|
||||
virtual void Write(const uint8_t payloadType, const uint32_t timeStamp,
|
||||
const int16_t seqNo, const uint8_t* payloadData,
|
||||
const size_t payloadSize, uint32_t frequency) = 0;
|
||||
|
||||
// Returns the packet's payload size. Zero should be treated as an
|
||||
// end-of-stream (in the case that EndOfFile() is true) or an error.
|
||||
virtual size_t Read(WebRtcRTPHeader* rtpInfo, uint8_t* payloadData,
|
||||
size_t payloadSize, uint32_t* offset) = 0;
|
||||
virtual bool EndOfFile() const = 0;
|
||||
|
||||
protected:
|
||||
void MakeRTPheader(uint8_t* rtpHeader, uint8_t payloadType, int16_t seqNo,
|
||||
uint32_t timeStamp, uint32_t ssrc);
|
||||
|
||||
void ParseRTPHeader(WebRtcRTPHeader* rtpInfo, const uint8_t* rtpHeader);
|
||||
};
|
||||
|
||||
class RTPPacket {
|
||||
public:
|
||||
RTPPacket(uint8_t payloadType, uint32_t timeStamp, int16_t seqNo,
|
||||
const uint8_t* payloadData, size_t payloadSize,
|
||||
uint32_t frequency);
|
||||
|
||||
~RTPPacket();
|
||||
|
||||
uint8_t payloadType;
|
||||
uint32_t timeStamp;
|
||||
int16_t seqNo;
|
||||
uint8_t* payloadData;
|
||||
size_t payloadSize;
|
||||
uint32_t frequency;
|
||||
};
|
||||
|
||||
class RTPBuffer : public RTPStream {
|
||||
public:
|
||||
RTPBuffer();
|
||||
|
||||
~RTPBuffer();
|
||||
|
||||
void Write(const uint8_t payloadType,
|
||||
const uint32_t timeStamp,
|
||||
const int16_t seqNo,
|
||||
const uint8_t* payloadData,
|
||||
const size_t payloadSize,
|
||||
uint32_t frequency) override;
|
||||
|
||||
size_t Read(WebRtcRTPHeader* rtpInfo,
|
||||
uint8_t* payloadData,
|
||||
size_t payloadSize,
|
||||
uint32_t* offset) override;
|
||||
|
||||
bool EndOfFile() const override;
|
||||
|
||||
private:
|
||||
RWLockWrapper* _queueRWLock;
|
||||
std::queue<RTPPacket *> _rtpQueue;
|
||||
};
|
||||
|
||||
class RTPFile : public RTPStream {
|
||||
public:
|
||||
~RTPFile() {
|
||||
}
|
||||
|
||||
RTPFile()
|
||||
: _rtpFile(NULL),
|
||||
_rtpEOF(false) {
|
||||
}
|
||||
|
||||
void Open(const char *outFilename, const char *mode);
|
||||
|
||||
void Close();
|
||||
|
||||
void WriteHeader();
|
||||
|
||||
void ReadHeader();
|
||||
|
||||
void Write(const uint8_t payloadType,
|
||||
const uint32_t timeStamp,
|
||||
const int16_t seqNo,
|
||||
const uint8_t* payloadData,
|
||||
const size_t payloadSize,
|
||||
uint32_t frequency) override;
|
||||
|
||||
size_t Read(WebRtcRTPHeader* rtpInfo,
|
||||
uint8_t* payloadData,
|
||||
size_t payloadSize,
|
||||
uint32_t* offset) override;
|
||||
|
||||
bool EndOfFile() const override { return _rtpEOF; }
|
||||
|
||||
private:
|
||||
FILE* _rtpFile;
|
||||
bool _rtpEOF;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_RTPFILE_H_
|
||||
196
webrtc/modules/audio_coding/test/SpatialAudio.cc
Normal file
196
webrtc/modules/audio_coding/test/SpatialAudio.cc
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/test/SpatialAudio.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#define NUM_PANN_COEFFS 10
|
||||
|
||||
SpatialAudio::SpatialAudio(int testMode)
|
||||
: _acmLeft(AudioCodingModule::Create(1)),
|
||||
_acmRight(AudioCodingModule::Create(2)),
|
||||
_acmReceiver(AudioCodingModule::Create(3)),
|
||||
_testMode(testMode) {
|
||||
}
|
||||
|
||||
SpatialAudio::~SpatialAudio() {
|
||||
delete _channel;
|
||||
_inFile.Close();
|
||||
_outFile.Close();
|
||||
}
|
||||
|
||||
int16_t SpatialAudio::Setup() {
|
||||
_channel = new Channel;
|
||||
|
||||
// Register callback for the sender side.
|
||||
CHECK_ERROR(_acmLeft->RegisterTransportCallback(_channel));
|
||||
CHECK_ERROR(_acmRight->RegisterTransportCallback(_channel));
|
||||
// Register the receiver ACM in channel
|
||||
_channel->RegisterReceiverACM(_acmReceiver.get());
|
||||
|
||||
uint16_t sampFreqHz = 32000;
|
||||
|
||||
const std::string file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
_inFile.Open(file_name, sampFreqHz, "rb", false);
|
||||
|
||||
std::string output_file = webrtc::test::OutputPath()
|
||||
+ "out_spatial_autotest.pcm";
|
||||
if (_testMode == 1) {
|
||||
output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
|
||||
printf("\n");
|
||||
printf("Enter the output file [%s]: ", output_file.c_str());
|
||||
PCMFile::ChooseFile(&output_file, MAX_FILE_NAME_LENGTH_BYTE, &sampFreqHz);
|
||||
} else {
|
||||
output_file = webrtc::test::OutputPath() + "testspatial_out.pcm";
|
||||
}
|
||||
_outFile.Open(output_file, sampFreqHz, "wb", false);
|
||||
_outFile.SaveStereo(true);
|
||||
|
||||
// Register all available codes as receiving codecs.
|
||||
CodecInst codecInst;
|
||||
int status;
|
||||
uint8_t num_encoders = _acmReceiver->NumberOfCodecs();
|
||||
// Register all available codes as receiving codecs once more.
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
status = _acmReceiver->Codec(n, &codecInst);
|
||||
if (status < 0) {
|
||||
printf("Error in Codec(), no matching codec found");
|
||||
}
|
||||
status = _acmReceiver->RegisterReceiveCodec(codecInst);
|
||||
if (status < 0) {
|
||||
printf("Error in RegisterReceiveCodec() for payload type %d",
|
||||
codecInst.pltype);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpatialAudio::Perform() {
|
||||
if (_testMode == 0) {
|
||||
printf("Running SpatialAudio Test");
|
||||
WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceAudioCoding, -1,
|
||||
"---------- SpatialAudio ----------");
|
||||
}
|
||||
|
||||
Setup();
|
||||
|
||||
CodecInst codecInst;
|
||||
_acmLeft->Codec((uint8_t) 1, &codecInst);
|
||||
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
|
||||
EncodeDecode();
|
||||
|
||||
int16_t pannCntr = 0;
|
||||
|
||||
double leftPanning[NUM_PANN_COEFFS] = { 1.00, 0.95, 0.90, 0.85, 0.80, 0.75,
|
||||
0.70, 0.60, 0.55, 0.50 };
|
||||
double rightPanning[NUM_PANN_COEFFS] = { 0.50, 0.55, 0.60, 0.70, 0.75, 0.80,
|
||||
0.85, 0.90, 0.95, 1.00 };
|
||||
|
||||
while ((pannCntr + 1) < NUM_PANN_COEFFS) {
|
||||
_acmLeft->Codec((uint8_t) 0, &codecInst);
|
||||
codecInst.pacsize = 480;
|
||||
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
|
||||
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
|
||||
|
||||
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
|
||||
pannCntr++;
|
||||
|
||||
// Change codec
|
||||
_acmLeft->Codec((uint8_t) 3, &codecInst);
|
||||
codecInst.pacsize = 320;
|
||||
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
|
||||
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
|
||||
|
||||
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
|
||||
pannCntr++;
|
||||
if (_testMode == 0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
_acmLeft->Codec((uint8_t) 4, &codecInst);
|
||||
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
|
||||
EncodeDecode();
|
||||
|
||||
_acmLeft->Codec((uint8_t) 0, &codecInst);
|
||||
codecInst.pacsize = 480;
|
||||
CHECK_ERROR(_acmLeft->RegisterSendCodec(codecInst));
|
||||
CHECK_ERROR(_acmRight->RegisterSendCodec(codecInst));
|
||||
pannCntr = NUM_PANN_COEFFS - 1;
|
||||
while (pannCntr >= 0) {
|
||||
EncodeDecode(leftPanning[pannCntr], rightPanning[pannCntr]);
|
||||
pannCntr--;
|
||||
if (_testMode == 0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
if (_testMode == 0) {
|
||||
printf("Done!\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SpatialAudio::EncodeDecode(const double leftPanning,
|
||||
const double rightPanning) {
|
||||
AudioFrame audioFrame;
|
||||
int32_t outFileSampFreq = _outFile.SamplingFrequency();
|
||||
|
||||
const double rightToLeftRatio = rightPanning / leftPanning;
|
||||
|
||||
_channel->SetIsStereo(true);
|
||||
|
||||
while (!_inFile.EndOfFile()) {
|
||||
_inFile.Read10MsData(audioFrame);
|
||||
for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
|
||||
audioFrame.data_[n] = (int16_t) floor(
|
||||
audioFrame.data_[n] * leftPanning + 0.5);
|
||||
}
|
||||
CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
|
||||
|
||||
for (size_t n = 0; n < audioFrame.samples_per_channel_; n++) {
|
||||
audioFrame.data_[n] = (int16_t) floor(
|
||||
audioFrame.data_[n] * rightToLeftRatio + 0.5);
|
||||
}
|
||||
CHECK_ERROR(_acmRight->Add10MsData(audioFrame));
|
||||
|
||||
CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
|
||||
_outFile.Write10MsData(audioFrame);
|
||||
}
|
||||
_inFile.Rewind();
|
||||
}
|
||||
|
||||
void SpatialAudio::EncodeDecode() {
|
||||
AudioFrame audioFrame;
|
||||
int32_t outFileSampFreq = _outFile.SamplingFrequency();
|
||||
|
||||
_channel->SetIsStereo(false);
|
||||
|
||||
while (!_inFile.EndOfFile()) {
|
||||
_inFile.Read10MsData(audioFrame);
|
||||
CHECK_ERROR(_acmLeft->Add10MsData(audioFrame));
|
||||
|
||||
CHECK_ERROR(_acmReceiver->PlayoutData10Ms(outFileSampFreq, &audioFrame));
|
||||
_outFile.Write10MsData(audioFrame);
|
||||
}
|
||||
_inFile.Rewind();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
47
webrtc/modules/audio_coding/test/SpatialAudio.h
Normal file
47
webrtc/modules/audio_coding/test/SpatialAudio.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
|
||||
#define MAX_FILE_NAME_LENGTH_BYTE 500
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class SpatialAudio : public ACMTest {
|
||||
public:
|
||||
SpatialAudio(int testMode);
|
||||
~SpatialAudio();
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
int16_t Setup();
|
||||
void EncodeDecode(double leftPanning, double rightPanning);
|
||||
void EncodeDecode();
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmLeft;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmRight;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmReceiver;
|
||||
Channel* _channel;
|
||||
PCMFile _inFile;
|
||||
PCMFile _outFile;
|
||||
int _testMode;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_SPATIALAUDIO_H_
|
||||
485
webrtc/modules/audio_coding/test/TestAllCodecs.cc
Normal file
485
webrtc/modules/audio_coding/test/TestAllCodecs.cc
Normal file
@ -0,0 +1,485 @@
|
||||
/*
|
||||
* 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/test/TestAllCodecs.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Description of the test:
|
||||
// In this test we set up a one-way communication channel from a participant
|
||||
// called "a" to a participant called "b".
|
||||
// a -> channel_a_to_b -> b
|
||||
//
|
||||
// The test loops through all available mono codecs, encode at "a" sends over
|
||||
// the channel, and decodes at "b".
|
||||
|
||||
namespace {
|
||||
const size_t kVariableSize = std::numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class for simulating packet handling.
|
||||
TestPack::TestPack()
|
||||
: receiver_acm_(NULL),
|
||||
sequence_number_(0),
|
||||
timestamp_diff_(0),
|
||||
last_in_timestamp_(0),
|
||||
total_bytes_(0),
|
||||
payload_size_(0) {
|
||||
}
|
||||
|
||||
TestPack::~TestPack() {
|
||||
}
|
||||
|
||||
void TestPack::RegisterReceiverACM(AudioCodingModule* acm) {
|
||||
receiver_acm_ = acm;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t TestPack::SendData(FrameType frame_type, uint8_t payload_type,
|
||||
uint32_t timestamp, const uint8_t* payload_data,
|
||||
size_t payload_size,
|
||||
const RTPFragmentationHeader* fragmentation) {
|
||||
WebRtcRTPHeader rtp_info;
|
||||
int32_t status;
|
||||
|
||||
rtp_info.header.markerBit = false;
|
||||
rtp_info.header.ssrc = 0;
|
||||
rtp_info.header.sequenceNumber = sequence_number_++;
|
||||
rtp_info.header.payloadType = payload_type;
|
||||
rtp_info.header.timestamp = timestamp;
|
||||
if (frame_type == kAudioFrameCN) {
|
||||
rtp_info.type.Audio.isCNG = true;
|
||||
} else {
|
||||
rtp_info.type.Audio.isCNG = false;
|
||||
}
|
||||
if (frame_type == kEmptyFrame) {
|
||||
// Skip this frame.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Only run mono for all test cases.
|
||||
rtp_info.type.Audio.channel = 1;
|
||||
memcpy(payload_data_, payload_data, payload_size);
|
||||
|
||||
status = receiver_acm_->IncomingPacket(payload_data_, payload_size, rtp_info);
|
||||
|
||||
payload_size_ = payload_size;
|
||||
timestamp_diff_ = timestamp - last_in_timestamp_;
|
||||
last_in_timestamp_ = timestamp;
|
||||
total_bytes_ += payload_size;
|
||||
return status;
|
||||
}
|
||||
|
||||
size_t TestPack::payload_size() {
|
||||
return payload_size_;
|
||||
}
|
||||
|
||||
uint32_t TestPack::timestamp_diff() {
|
||||
return timestamp_diff_;
|
||||
}
|
||||
|
||||
void TestPack::reset_payload_size() {
|
||||
payload_size_ = 0;
|
||||
}
|
||||
|
||||
TestAllCodecs::TestAllCodecs(int test_mode)
|
||||
: acm_a_(AudioCodingModule::Create(0)),
|
||||
acm_b_(AudioCodingModule::Create(1)),
|
||||
channel_a_to_b_(NULL),
|
||||
test_count_(0),
|
||||
packet_size_samples_(0),
|
||||
packet_size_bytes_(0) {
|
||||
// test_mode = 0 for silent test (auto test)
|
||||
test_mode_ = test_mode;
|
||||
}
|
||||
|
||||
TestAllCodecs::~TestAllCodecs() {
|
||||
if (channel_a_to_b_ != NULL) {
|
||||
delete channel_a_to_b_;
|
||||
channel_a_to_b_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TestAllCodecs::Perform() {
|
||||
const std::string file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
infile_a_.Open(file_name, 32000, "rb");
|
||||
|
||||
if (test_mode_ == 0) {
|
||||
WEBRTC_TRACE(kTraceStateInfo, kTraceAudioCoding, -1,
|
||||
"---------- TestAllCodecs ----------");
|
||||
}
|
||||
|
||||
acm_a_->InitializeReceiver();
|
||||
acm_b_->InitializeReceiver();
|
||||
|
||||
uint8_t num_encoders = acm_a_->NumberOfCodecs();
|
||||
CodecInst my_codec_param;
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
acm_b_->Codec(n, &my_codec_param);
|
||||
if (!strcmp(my_codec_param.plname, "opus")) {
|
||||
my_codec_param.channels = 1;
|
||||
}
|
||||
acm_b_->RegisterReceiveCodec(my_codec_param);
|
||||
}
|
||||
|
||||
// Create and connect the channel
|
||||
channel_a_to_b_ = new TestPack;
|
||||
acm_a_->RegisterTransportCallback(channel_a_to_b_);
|
||||
channel_a_to_b_->RegisterReceiverACM(acm_b_.get());
|
||||
|
||||
// All codecs are tested for all allowed sampling frequencies, rates and
|
||||
// packet sizes.
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_g722[] = "G722";
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 480, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 640, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 800, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 960, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_ilbc[] = "ILBC";
|
||||
RegisterSendCodec('A', codec_ilbc, 8000, 13300, 240, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_ilbc, 8000, 13300, 480, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_ilbc, 8000, 15200, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_ilbc, 8000, 15200, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#endif
|
||||
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_isac[] = "ISAC";
|
||||
RegisterSendCodec('A', codec_isac, 16000, -1, 480, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 16000, -1, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 16000, 15000, 480, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 16000, 32000, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
RegisterSendCodec('A', codec_isac, 32000, -1, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 32000, 56000, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 32000, 37000, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_isac, 32000, 32000, 960, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#endif
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_l16[] = "L16";
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 240, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 480, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 640, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 640, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_pcma[] = "PCMA";
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, 0);
|
||||
Run(channel_a_to_b_);
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
char codec_pcmu[] = "PCMU";
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, 0);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, 0);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
}
|
||||
test_count_++;
|
||||
OpenOutFile(test_count_);
|
||||
char codec_opus[] = "OPUS";
|
||||
RegisterSendCodec('A', codec_opus, 48000, 6000, 480, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 20000, 480*2, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 32000, 480*4, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 48000, 480, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*4, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 96000, 480*6, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 500000, 480*2, kVariableSize);
|
||||
Run(channel_a_to_b_);
|
||||
outfile_b_.Close();
|
||||
#endif
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
|
||||
/* Print out all codecs that were not tested in the run */
|
||||
printf("The following codecs was not included in the test:\n");
|
||||
#ifndef WEBRTC_CODEC_G722
|
||||
printf(" G.722\n");
|
||||
#endif
|
||||
#ifndef WEBRTC_CODEC_ILBC
|
||||
printf(" iLBC\n");
|
||||
#endif
|
||||
#ifndef WEBRTC_CODEC_ISAC
|
||||
printf(" ISAC float\n");
|
||||
#endif
|
||||
#ifndef WEBRTC_CODEC_ISACFX
|
||||
printf(" ISAC fix\n");
|
||||
#endif
|
||||
|
||||
printf("\nTo complete the test, listen to the %d number of output files.\n",
|
||||
test_count_);
|
||||
}
|
||||
}
|
||||
|
||||
// Register Codec to use in the test
|
||||
//
|
||||
// Input: side - which ACM to use, 'A' or 'B'
|
||||
// codec_name - name to use when register the codec
|
||||
// sampling_freq_hz - sampling frequency in Herz
|
||||
// rate - bitrate in bytes
|
||||
// packet_size - packet size in samples
|
||||
// extra_byte - if extra bytes needed compared to the bitrate
|
||||
// used when registering, can be an internal header
|
||||
// set to kVariableSize if the codec is a variable
|
||||
// rate codec
|
||||
void TestAllCodecs::RegisterSendCodec(char side, char* codec_name,
|
||||
int32_t sampling_freq_hz, int rate,
|
||||
int packet_size, size_t extra_byte) {
|
||||
if (test_mode_ != 0) {
|
||||
// Print out codec and settings.
|
||||
printf("codec: %s Freq: %d Rate: %d PackSize: %d\n", codec_name,
|
||||
sampling_freq_hz, rate, packet_size);
|
||||
}
|
||||
|
||||
// Store packet-size in samples, used to validate the received packet.
|
||||
// If G.722, store half the size to compensate for the timestamp bug in the
|
||||
// RFC for G.722.
|
||||
// If iSAC runs in adaptive mode, packet size in samples can change on the
|
||||
// fly, so we exclude this test by setting |packet_size_samples_| to -1.
|
||||
if (!strcmp(codec_name, "G722")) {
|
||||
packet_size_samples_ = packet_size / 2;
|
||||
} else if (!strcmp(codec_name, "ISAC") && (rate == -1)) {
|
||||
packet_size_samples_ = -1;
|
||||
} else {
|
||||
packet_size_samples_ = packet_size;
|
||||
}
|
||||
|
||||
// Store the expected packet size in bytes, used to validate the received
|
||||
// packet. If variable rate codec (extra_byte == -1), set to -1.
|
||||
if (extra_byte != kVariableSize) {
|
||||
// Add 0.875 to always round up to a whole byte
|
||||
packet_size_bytes_ = static_cast<size_t>(
|
||||
static_cast<float>(packet_size * rate) /
|
||||
static_cast<float>(sampling_freq_hz * 8) + 0.875) + extra_byte;
|
||||
} else {
|
||||
// Packets will have a variable size.
|
||||
packet_size_bytes_ = kVariableSize;
|
||||
}
|
||||
|
||||
// Set pointer to the ACM where to register the codec.
|
||||
AudioCodingModule* my_acm = NULL;
|
||||
switch (side) {
|
||||
case 'A': {
|
||||
my_acm = acm_a_.get();
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
my_acm = acm_b_.get();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(my_acm != NULL);
|
||||
|
||||
// Get all codec parameters before registering
|
||||
CodecInst my_codec_param;
|
||||
CHECK_ERROR(AudioCodingModule::Codec(codec_name, &my_codec_param,
|
||||
sampling_freq_hz, 1));
|
||||
my_codec_param.rate = rate;
|
||||
my_codec_param.pacsize = packet_size;
|
||||
CHECK_ERROR(my_acm->RegisterSendCodec(my_codec_param));
|
||||
}
|
||||
|
||||
void TestAllCodecs::Run(TestPack* channel) {
|
||||
AudioFrame audio_frame;
|
||||
|
||||
int32_t out_freq_hz = outfile_b_.SamplingFrequency();
|
||||
size_t receive_size;
|
||||
uint32_t timestamp_diff;
|
||||
channel->reset_payload_size();
|
||||
int error_count = 0;
|
||||
|
||||
int counter = 0;
|
||||
while (!infile_a_.EndOfFile()) {
|
||||
// Add 10 msec to ACM.
|
||||
infile_a_.Read10MsData(audio_frame);
|
||||
CHECK_ERROR(acm_a_->Add10MsData(audio_frame));
|
||||
|
||||
// Verify that the received packet size matches the settings.
|
||||
receive_size = channel->payload_size();
|
||||
if (receive_size) {
|
||||
if ((receive_size != packet_size_bytes_) &&
|
||||
(packet_size_bytes_ != kVariableSize)) {
|
||||
error_count++;
|
||||
}
|
||||
|
||||
// Verify that the timestamp is updated with expected length. The counter
|
||||
// is used to avoid problems when switching codec or frame size in the
|
||||
// test.
|
||||
timestamp_diff = channel->timestamp_diff();
|
||||
if ((counter > 10) &&
|
||||
(static_cast<int>(timestamp_diff) != packet_size_samples_) &&
|
||||
(packet_size_samples_ > -1))
|
||||
error_count++;
|
||||
}
|
||||
|
||||
// Run received side of ACM.
|
||||
CHECK_ERROR(acm_b_->PlayoutData10Ms(out_freq_hz, &audio_frame));
|
||||
|
||||
// Write output speech to file.
|
||||
outfile_b_.Write10MsData(audio_frame.data_,
|
||||
audio_frame.samples_per_channel_);
|
||||
|
||||
// Update loop counter
|
||||
counter++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, error_count);
|
||||
|
||||
if (infile_a_.EndOfFile()) {
|
||||
infile_a_.Rewind();
|
||||
}
|
||||
}
|
||||
|
||||
void TestAllCodecs::OpenOutFile(int test_number) {
|
||||
std::string filename = webrtc::test::OutputPath();
|
||||
std::ostringstream test_number_str;
|
||||
test_number_str << test_number;
|
||||
filename += "testallcodecs_out_";
|
||||
filename += test_number_str.str();
|
||||
filename += ".pcm";
|
||||
outfile_b_.Open(filename, 32000, "wb");
|
||||
}
|
||||
|
||||
void TestAllCodecs::DisplaySendReceiveCodec() {
|
||||
CodecInst my_codec_param;
|
||||
printf("%s -> ", acm_a_->SendCodec()->plname);
|
||||
acm_b_->ReceiveCodec(&my_codec_param);
|
||||
printf("%s\n", my_codec_param.plname);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
84
webrtc/modules/audio_coding/test/TestAllCodecs.h
Normal file
84
webrtc/modules/audio_coding/test/TestAllCodecs.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Config;
|
||||
|
||||
class TestPack : public AudioPacketizationCallback {
|
||||
public:
|
||||
TestPack();
|
||||
~TestPack();
|
||||
|
||||
void RegisterReceiverACM(AudioCodingModule* acm);
|
||||
|
||||
int32_t SendData(FrameType frame_type,
|
||||
uint8_t payload_type,
|
||||
uint32_t timestamp,
|
||||
const uint8_t* payload_data,
|
||||
size_t payload_size,
|
||||
const RTPFragmentationHeader* fragmentation) override;
|
||||
|
||||
size_t payload_size();
|
||||
uint32_t timestamp_diff();
|
||||
void reset_payload_size();
|
||||
|
||||
private:
|
||||
AudioCodingModule* receiver_acm_;
|
||||
uint16_t sequence_number_;
|
||||
uint8_t payload_data_[60 * 32 * 2 * 2];
|
||||
uint32_t timestamp_diff_;
|
||||
uint32_t last_in_timestamp_;
|
||||
uint64_t total_bytes_;
|
||||
size_t payload_size_;
|
||||
};
|
||||
|
||||
class TestAllCodecs : public ACMTest {
|
||||
public:
|
||||
explicit TestAllCodecs(int test_mode);
|
||||
~TestAllCodecs();
|
||||
|
||||
void Perform() override;
|
||||
|
||||
private:
|
||||
// The default value of '-1' indicates that the registration is based only on
|
||||
// codec name, and a sampling frequency matching is not required.
|
||||
// This is useful for codecs which support several sampling frequency.
|
||||
// Note! Only mono mode is tested in this test.
|
||||
void RegisterSendCodec(char side, char* codec_name, int32_t sampling_freq_hz,
|
||||
int rate, int packet_size, size_t extra_byte);
|
||||
|
||||
void Run(TestPack* channel);
|
||||
void OpenOutFile(int test_number);
|
||||
void DisplaySendReceiveCodec();
|
||||
|
||||
int test_mode_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_a_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_b_;
|
||||
TestPack* channel_a_to_b_;
|
||||
PCMFile infile_a_;
|
||||
PCMFile outfile_b_;
|
||||
int test_count_;
|
||||
int packet_size_samples_;
|
||||
size_t packet_size_bytes_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
|
||||
476
webrtc/modules/audio_coding/test/TestRedFec.cc
Normal file
476
webrtc/modules/audio_coding/test/TestRedFec.cc
Normal file
@ -0,0 +1,476 @@
|
||||
/*
|
||||
* 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/test/TestRedFec.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
#undef SUPPORT_RED_WB
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_RED_SWB
|
||||
#undef SUPPORT_RED_SWB
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_RED_FB
|
||||
#undef SUPPORT_RED_FB
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
const char kNameL16[] = "L16";
|
||||
const char kNamePCMU[] = "PCMU";
|
||||
const char kNameCN[] = "CN";
|
||||
const char kNameRED[] = "RED";
|
||||
|
||||
// These three are only used by code #ifdeffed on WEBRTC_CODEC_G722.
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
const char kNameISAC[] = "ISAC";
|
||||
const char kNameG722[] = "G722";
|
||||
const char kNameOPUS[] = "opus";
|
||||
#endif
|
||||
}
|
||||
|
||||
TestRedFec::TestRedFec()
|
||||
: _acmA(AudioCodingModule::Create(0)),
|
||||
_acmB(AudioCodingModule::Create(1)),
|
||||
_channelA2B(NULL),
|
||||
_testCntr(0) {
|
||||
}
|
||||
|
||||
TestRedFec::~TestRedFec() {
|
||||
if (_channelA2B != NULL) {
|
||||
delete _channelA2B;
|
||||
_channelA2B = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TestRedFec::Perform() {
|
||||
const std::string file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
_inFileA.Open(file_name, 32000, "rb");
|
||||
|
||||
ASSERT_EQ(0, _acmA->InitializeReceiver());
|
||||
ASSERT_EQ(0, _acmB->InitializeReceiver());
|
||||
|
||||
uint8_t numEncoders = _acmA->NumberOfCodecs();
|
||||
CodecInst myCodecParam;
|
||||
for (uint8_t n = 0; n < numEncoders; n++) {
|
||||
EXPECT_EQ(0, _acmB->Codec(n, &myCodecParam));
|
||||
// Default number of channels is 2 for opus, so we change to 1 in this test.
|
||||
if (!strcmp(myCodecParam.plname, "opus")) {
|
||||
myCodecParam.channels = 1;
|
||||
}
|
||||
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(myCodecParam));
|
||||
}
|
||||
|
||||
// Create and connect the channel
|
||||
_channelA2B = new Channel;
|
||||
_acmA->RegisterTransportCallback(_channelA2B);
|
||||
_channelA2B->RegisterReceiverACM(_acmB.get());
|
||||
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameL16, 8000));
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 8000));
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameRED));
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNamePCMU, 8000);
|
||||
// Switch to another 8 kHz codec, RED should remain switched on.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
#ifndef WEBRTC_CODEC_G722
|
||||
EXPECT_TRUE(false);
|
||||
printf("G722 needs to be activated to run this test\n");
|
||||
return;
|
||||
#else
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameG722, 16000));
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
// Switch to a 16 kHz codec, RED should have been switched off.
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
Run();
|
||||
#ifdef SUPPORT_RED_WB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
|
||||
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
// Switch to a 32 kHz codec, RED should have been switched off.
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
#ifdef SUPPORT_RED_SWB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
|
||||
|
||||
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
_channelA2B->SetFECTestWithPacketLoss(true);
|
||||
// Following tests are under packet losses.
|
||||
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameG722));
|
||||
EXPECT_EQ(0, RegisterSendCodec('A', kNameCN, 16000));
|
||||
|
||||
#if defined(SUPPORT_RED_WB) && defined(SUPPORT_RED_SWB)
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
// Switch to a 16 kHz codec, RED should have been switched off.
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
|
||||
#ifdef SUPPORT_RED_WB
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
// Switch to a 16 kHz codec, RED should have been switched off.
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
#ifdef SUPPORT_RED_WB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
|
||||
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
|
||||
// Switch codec, RED should remain.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
// Switch to a 32 kHz codec, RED should have been switched off.
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#ifdef SUPPORT_RED_SWB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
|
||||
#if defined(SUPPORT_RED_SWB) && defined(SUPPORT_RED_WB)
|
||||
OpenOutFile(_testCntr);
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 32000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
_outFileB.Close();
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
#ifndef WEBRTC_CODEC_OPUS
|
||||
EXPECT_TRUE(false);
|
||||
printf("Opus needs to be activated to run this test\n");
|
||||
return;
|
||||
#endif
|
||||
|
||||
RegisterSendCodec('A', kNameOPUS, 48000);
|
||||
|
||||
#if defined(SUPPORT_RED_FB) && defined(SUPPORT_RED_SWB) &&\
|
||||
defined(SUPPORT_RED_WB)
|
||||
// Switch to codec, RED should remain switched on.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
|
||||
// _channelA2B imposes 25% packet loss rate.
|
||||
EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
|
||||
|
||||
#ifdef SUPPORT_RED_FB
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
// Codec FEC and RED are mutually exclusive.
|
||||
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
|
||||
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
|
||||
|
||||
// Codec FEC and RED are mutually exclusive.
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
#else
|
||||
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(_acmA->CodecFEC());
|
||||
OpenOutFile(_testCntr);
|
||||
Run();
|
||||
|
||||
// Switch to L16 with RED.
|
||||
RegisterSendCodec('A', kNameL16, 8000);
|
||||
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
|
||||
|
||||
// L16 does not support FEC, so FEC should be turned off automatically.
|
||||
EXPECT_FALSE(_acmA->CodecFEC());
|
||||
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(true));
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
Run();
|
||||
|
||||
// Switch to Opus again.
|
||||
RegisterSendCodec('A', kNameOPUS, 48000);
|
||||
#ifdef SUPPORT_RED_FB
|
||||
// Switch to codec, RED should remain switched on.
|
||||
EXPECT_TRUE(_acmA->REDStatus());
|
||||
#else
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
#endif
|
||||
EXPECT_EQ(0, _acmA->SetREDStatus(false));
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
|
||||
Run();
|
||||
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
|
||||
_outFileB.Close();
|
||||
|
||||
// Codecs does not support internal FEC, cannot enable FEC.
|
||||
RegisterSendCodec('A', kNameG722, 16000);
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
|
||||
EXPECT_FALSE(_acmA->CodecFEC());
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
|
||||
EXPECT_FALSE(_acmA->CodecFEC());
|
||||
|
||||
// Codecs does not support internal FEC, disable FEC does not trigger failure.
|
||||
RegisterSendCodec('A', kNameG722, 16000);
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
|
||||
EXPECT_FALSE(_acmA->CodecFEC());
|
||||
|
||||
RegisterSendCodec('A', kNameISAC, 16000);
|
||||
EXPECT_FALSE(_acmA->REDStatus());
|
||||
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
|
||||
EXPECT_FALSE(_acmA->CodecFEC());
|
||||
|
||||
#endif // defined(WEBRTC_CODEC_G722)
|
||||
}
|
||||
|
||||
int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
|
||||
return _acmA->SetVAD(enableDTX, enableVAD, vadMode);
|
||||
}
|
||||
|
||||
int16_t TestRedFec::RegisterSendCodec(char side, const char* codecName,
|
||||
int32_t samplingFreqHz) {
|
||||
std::cout << std::flush;
|
||||
AudioCodingModule* myACM;
|
||||
switch (side) {
|
||||
case 'A': {
|
||||
myACM = _acmA.get();
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
myACM = _acmB.get();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (myACM == NULL) {
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
CodecInst myCodecParam;
|
||||
EXPECT_GT(AudioCodingModule::Codec(codecName, &myCodecParam,
|
||||
samplingFreqHz, 1), -1);
|
||||
EXPECT_GT(myACM->RegisterSendCodec(myCodecParam), -1);
|
||||
|
||||
// Initialization was successful.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TestRedFec::Run() {
|
||||
AudioFrame audioFrame;
|
||||
int32_t outFreqHzB = _outFileB.SamplingFrequency();
|
||||
|
||||
while (!_inFileA.EndOfFile()) {
|
||||
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
|
||||
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
|
||||
_outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
|
||||
}
|
||||
_inFileA.Rewind();
|
||||
}
|
||||
|
||||
void TestRedFec::OpenOutFile(int16_t test_number) {
|
||||
std::string file_name;
|
||||
std::stringstream file_stream;
|
||||
file_stream << webrtc::test::OutputPath();
|
||||
file_stream << "TestRedFec_outFile_";
|
||||
file_stream << test_number << ".pcm";
|
||||
file_name = file_stream.str();
|
||||
_outFileB.Open(file_name, 16000, "wb");
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
51
webrtc/modules/audio_coding/test/TestRedFec.h
Normal file
51
webrtc/modules/audio_coding/test/TestRedFec.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
|
||||
|
||||
#include <string>
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class Config;
|
||||
|
||||
class TestRedFec : public ACMTest {
|
||||
public:
|
||||
explicit TestRedFec();
|
||||
~TestRedFec();
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
// The default value of '-1' indicates that the registration is based only on
|
||||
// codec name and a sampling frequency matching is not required. This is
|
||||
// useful for codecs which support several sampling frequency.
|
||||
int16_t RegisterSendCodec(char side, const char* codecName,
|
||||
int32_t sampFreqHz = -1);
|
||||
void Run();
|
||||
void OpenOutFile(int16_t testNumber);
|
||||
int32_t SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode);
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmB;
|
||||
|
||||
Channel* _channelA2B;
|
||||
|
||||
PCMFile _inFileA;
|
||||
PCMFile _outFileB;
|
||||
int16_t _testCntr;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
|
||||
838
webrtc/modules/audio_coding/test/TestStereo.cc
Normal file
838
webrtc/modules/audio_coding/test/TestStereo.cc
Normal file
@ -0,0 +1,838 @@
|
||||
/*
|
||||
* 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/test/TestStereo.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class for simulating packet handling
|
||||
TestPackStereo::TestPackStereo()
|
||||
: receiver_acm_(NULL),
|
||||
seq_no_(0),
|
||||
timestamp_diff_(0),
|
||||
last_in_timestamp_(0),
|
||||
total_bytes_(0),
|
||||
payload_size_(0),
|
||||
codec_mode_(kNotSet),
|
||||
lost_packet_(false) {
|
||||
}
|
||||
|
||||
TestPackStereo::~TestPackStereo() {
|
||||
}
|
||||
|
||||
void TestPackStereo::RegisterReceiverACM(AudioCodingModule* acm) {
|
||||
receiver_acm_ = acm;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t TestPackStereo::SendData(const FrameType frame_type,
|
||||
const uint8_t payload_type,
|
||||
const uint32_t timestamp,
|
||||
const uint8_t* payload_data,
|
||||
const size_t payload_size,
|
||||
const RTPFragmentationHeader* fragmentation) {
|
||||
WebRtcRTPHeader rtp_info;
|
||||
int32_t status = 0;
|
||||
|
||||
rtp_info.header.markerBit = false;
|
||||
rtp_info.header.ssrc = 0;
|
||||
rtp_info.header.sequenceNumber = seq_no_++;
|
||||
rtp_info.header.payloadType = payload_type;
|
||||
rtp_info.header.timestamp = timestamp;
|
||||
if (frame_type == kEmptyFrame) {
|
||||
// Skip this frame
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lost_packet_ == false) {
|
||||
if (frame_type != kAudioFrameCN) {
|
||||
rtp_info.type.Audio.isCNG = false;
|
||||
rtp_info.type.Audio.channel = static_cast<int>(codec_mode_);
|
||||
} else {
|
||||
rtp_info.type.Audio.isCNG = true;
|
||||
rtp_info.type.Audio.channel = static_cast<int>(kMono);
|
||||
}
|
||||
status = receiver_acm_->IncomingPacket(payload_data, payload_size,
|
||||
rtp_info);
|
||||
|
||||
if (frame_type != kAudioFrameCN) {
|
||||
payload_size_ = static_cast<int>(payload_size);
|
||||
} else {
|
||||
payload_size_ = -1;
|
||||
}
|
||||
|
||||
timestamp_diff_ = timestamp - last_in_timestamp_;
|
||||
last_in_timestamp_ = timestamp;
|
||||
total_bytes_ += payload_size;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t TestPackStereo::payload_size() {
|
||||
return static_cast<uint16_t>(payload_size_);
|
||||
}
|
||||
|
||||
uint32_t TestPackStereo::timestamp_diff() {
|
||||
return timestamp_diff_;
|
||||
}
|
||||
|
||||
void TestPackStereo::reset_payload_size() {
|
||||
payload_size_ = 0;
|
||||
}
|
||||
|
||||
void TestPackStereo::set_codec_mode(enum StereoMonoMode mode) {
|
||||
codec_mode_ = mode;
|
||||
}
|
||||
|
||||
void TestPackStereo::set_lost_packet(bool lost) {
|
||||
lost_packet_ = lost;
|
||||
}
|
||||
|
||||
TestStereo::TestStereo(int test_mode)
|
||||
: acm_a_(AudioCodingModule::Create(0)),
|
||||
acm_b_(AudioCodingModule::Create(1)),
|
||||
channel_a2b_(NULL),
|
||||
test_cntr_(0),
|
||||
pack_size_samp_(0),
|
||||
pack_size_bytes_(0),
|
||||
counter_(0)
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
, g722_pltype_(0)
|
||||
#endif
|
||||
, l16_8khz_pltype_(-1)
|
||||
, l16_16khz_pltype_(-1)
|
||||
, l16_32khz_pltype_(-1)
|
||||
#ifdef PCMA_AND_PCMU
|
||||
, pcma_pltype_(-1)
|
||||
, pcmu_pltype_(-1)
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
, opus_pltype_(-1)
|
||||
#endif
|
||||
{
|
||||
// test_mode = 0 for silent test (auto test)
|
||||
test_mode_ = test_mode;
|
||||
}
|
||||
|
||||
TestStereo::~TestStereo() {
|
||||
if (channel_a2b_ != NULL) {
|
||||
delete channel_a2b_;
|
||||
channel_a2b_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void TestStereo::Perform() {
|
||||
uint16_t frequency_hz;
|
||||
int audio_channels;
|
||||
int codec_channels;
|
||||
bool dtx;
|
||||
bool vad;
|
||||
ACMVADMode vad_mode;
|
||||
|
||||
// Open both mono and stereo test files in 32 kHz.
|
||||
const std::string file_name_stereo = webrtc::test::ResourcePath(
|
||||
"audio_coding/teststereo32kHz", "pcm");
|
||||
const std::string file_name_mono = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
frequency_hz = 32000;
|
||||
in_file_stereo_ = new PCMFile();
|
||||
in_file_mono_ = new PCMFile();
|
||||
in_file_stereo_->Open(file_name_stereo, frequency_hz, "rb");
|
||||
in_file_stereo_->ReadStereo(true);
|
||||
in_file_mono_->Open(file_name_mono, frequency_hz, "rb");
|
||||
in_file_mono_->ReadStereo(false);
|
||||
|
||||
// Create and initialize two ACMs, one for each side of a one-to-one call.
|
||||
ASSERT_TRUE((acm_a_.get() != NULL) && (acm_b_.get() != NULL));
|
||||
EXPECT_EQ(0, acm_a_->InitializeReceiver());
|
||||
EXPECT_EQ(0, acm_b_->InitializeReceiver());
|
||||
|
||||
// Register all available codes as receiving codecs.
|
||||
uint8_t num_encoders = acm_a_->NumberOfCodecs();
|
||||
CodecInst my_codec_param;
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
|
||||
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param));
|
||||
}
|
||||
|
||||
// Test that unregister all receive codecs works.
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
|
||||
EXPECT_EQ(0, acm_b_->UnregisterReceiveCodec(my_codec_param.pltype));
|
||||
}
|
||||
|
||||
// Register all available codes as receiving codecs once more.
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param));
|
||||
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param));
|
||||
}
|
||||
|
||||
// Create and connect the channel.
|
||||
channel_a2b_ = new TestPackStereo;
|
||||
EXPECT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_));
|
||||
channel_a2b_->RegisterReceiverACM(acm_b_.get());
|
||||
|
||||
// Start with setting VAD/DTX, before we know we will send stereo.
|
||||
// Continue with setting a stereo codec as send codec and verify that
|
||||
// VAD/DTX gets turned off.
|
||||
EXPECT_EQ(0, acm_a_->SetVAD(true, true, VADNormal));
|
||||
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
|
||||
EXPECT_TRUE(dtx);
|
||||
EXPECT_TRUE(vad);
|
||||
char codec_pcma_temp[] = "PCMA";
|
||||
RegisterSendCodec('A', codec_pcma_temp, 8000, 64000, 80, 2, pcma_pltype_);
|
||||
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
|
||||
EXPECT_FALSE(dtx);
|
||||
EXPECT_FALSE(vad);
|
||||
if (test_mode_ != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Test Stereo-To-Stereo for all codecs.
|
||||
//
|
||||
audio_channels = 2;
|
||||
codec_channels = 2;
|
||||
|
||||
// All codecs are tested for all allowed sampling frequencies, rates and
|
||||
// packet sizes.
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
char codec_g722[] = "G722";
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 320, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 480, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 640, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 800, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 960, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
char codec_l16[] = "L16";
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 160, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 240, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 320, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 320, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 480, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 640, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
|
||||
l16_32khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 640, codec_channels,
|
||||
l16_32khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#ifdef PCMA_AND_PCMU
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
audio_channels = 2;
|
||||
codec_channels = 2;
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
char codec_pcma[] = "PCMA";
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
|
||||
// Test that VAD/DTX cannot be turned on while sending stereo.
|
||||
EXPECT_EQ(-1, acm_a_->SetVAD(true, true, VADNormal));
|
||||
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
|
||||
EXPECT_FALSE(dtx);
|
||||
EXPECT_FALSE(vad);
|
||||
EXPECT_EQ(0, acm_a_->SetVAD(false, false, VADNormal));
|
||||
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
|
||||
EXPECT_FALSE(dtx);
|
||||
EXPECT_FALSE(vad);
|
||||
|
||||
out_file_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
char codec_pcmu[] = "PCMU";
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
if (test_mode_ != 0) {
|
||||
printf("===========================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-stereo\n");
|
||||
}
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
audio_channels = 2;
|
||||
codec_channels = 2;
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
|
||||
char codec_opus[] = "opus";
|
||||
// Run Opus with 10 ms frame size.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 480, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
// Run Opus with 20 ms frame size.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*2, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
// Run Opus with 40 ms frame size.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*4, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
// Run Opus with 60 ms frame size.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 480*6, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
// Run Opus with 20 ms frame size and different bitrates.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 40000, 960, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 510000, 960, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
//
|
||||
// Test Mono-To-Stereo for all codecs.
|
||||
//
|
||||
audio_channels = 1;
|
||||
codec_channels = 2;
|
||||
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
|
||||
g722_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
|
||||
l16_32khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#ifdef PCMA_AND_PCMU
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Mono-to-stereo\n");
|
||||
}
|
||||
|
||||
// Keep encode and decode in stereo.
|
||||
test_cntr_++;
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 960, codec_channels,
|
||||
opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
|
||||
// Encode in mono, decode in stereo mode.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 64000, 960, 1, opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
|
||||
//
|
||||
// Test Stereo-To-Mono for all codecs.
|
||||
//
|
||||
audio_channels = 2;
|
||||
codec_channels = 1;
|
||||
channel_a2b_->set_codec_mode(kMono);
|
||||
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
// Run stereo audio and mono codec.
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels,
|
||||
g722_pltype_);
|
||||
|
||||
// Make sure it is possible to set VAD/CNG, now that we are sending mono
|
||||
// again.
|
||||
EXPECT_EQ(0, acm_a_->SetVAD(true, true, VADNormal));
|
||||
EXPECT_EQ(0, acm_a_->VAD(&dtx, &vad, &vad_mode));
|
||||
EXPECT_TRUE(dtx);
|
||||
EXPECT_TRUE(vad);
|
||||
EXPECT_EQ(0, acm_a_->SetVAD(false, false, VADNormal));
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels,
|
||||
l16_8khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels,
|
||||
l16_16khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
if (test_mode_ != 0) {
|
||||
printf("==============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels,
|
||||
l16_32khz_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#ifdef PCMA_AND_PCMU
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels,
|
||||
pcmu_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels,
|
||||
pcma_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
if (test_mode_ != 0) {
|
||||
printf("===============================================================\n");
|
||||
printf("Test number: %d\n", test_cntr_ + 1);
|
||||
printf("Test type: Stereo-to-mono\n");
|
||||
}
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
// Encode and decode in mono.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 32000, 960, codec_channels,
|
||||
opus_pltype_);
|
||||
CodecInst opus_codec_param;
|
||||
for (uint8_t n = 0; n < num_encoders; n++) {
|
||||
EXPECT_EQ(0, acm_b_->Codec(n, &opus_codec_param));
|
||||
if (!strcmp(opus_codec_param.plname, "opus")) {
|
||||
opus_codec_param.channels = 1;
|
||||
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
|
||||
// Encode in stereo, decode in mono.
|
||||
RegisterSendCodec('A', codec_opus, 48000, 32000, 960, 2, opus_pltype_);
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
|
||||
out_file_.Close();
|
||||
|
||||
// Test switching between decoding mono and stereo for Opus.
|
||||
|
||||
// Decode in mono.
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
if (test_mode_ != 0) {
|
||||
// Print out codec and settings
|
||||
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
|
||||
" Decode: mono\n", test_cntr_);
|
||||
}
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
// Decode in stereo.
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
if (test_mode_ != 0) {
|
||||
// Print out codec and settings
|
||||
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
|
||||
" Decode: stereo\n", test_cntr_);
|
||||
}
|
||||
opus_codec_param.channels = 2;
|
||||
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
|
||||
Run(channel_a2b_, audio_channels, 2);
|
||||
out_file_.Close();
|
||||
// Decode in mono.
|
||||
test_cntr_++;
|
||||
OpenOutFile(test_cntr_);
|
||||
if (test_mode_ != 0) {
|
||||
// Print out codec and settings
|
||||
printf("Test number: %d\nCodec: Opus Freq: 48000 Rate :32000 PackSize: 960"
|
||||
" Decode: mono\n", test_cntr_);
|
||||
}
|
||||
opus_codec_param.channels = 1;
|
||||
EXPECT_EQ(0, acm_b_->RegisterReceiveCodec(opus_codec_param));
|
||||
Run(channel_a2b_, audio_channels, codec_channels);
|
||||
out_file_.Close();
|
||||
|
||||
#endif
|
||||
|
||||
// Print out which codecs were tested, and which were not, in the run.
|
||||
if (test_mode_ != 0) {
|
||||
printf("\nThe following codecs was INCLUDED in the test:\n");
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
printf(" G.722\n");
|
||||
#endif
|
||||
printf(" PCM16\n");
|
||||
printf(" G.711\n");
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
printf(" Opus\n");
|
||||
#endif
|
||||
printf("\nTo complete the test, listen to the %d number of output "
|
||||
"files.\n",
|
||||
test_cntr_);
|
||||
}
|
||||
|
||||
// Delete the file pointers.
|
||||
delete in_file_stereo_;
|
||||
delete in_file_mono_;
|
||||
}
|
||||
|
||||
// Register Codec to use in the test
|
||||
//
|
||||
// Input: side - which ACM to use, 'A' or 'B'
|
||||
// codec_name - name to use when register the codec
|
||||
// sampling_freq_hz - sampling frequency in Herz
|
||||
// rate - bitrate in bytes
|
||||
// pack_size - packet size in samples
|
||||
// channels - number of channels; 1 for mono, 2 for stereo
|
||||
// payload_type - payload type for the codec
|
||||
void TestStereo::RegisterSendCodec(char side, char* codec_name,
|
||||
int32_t sampling_freq_hz, int rate,
|
||||
int pack_size, int channels,
|
||||
int payload_type) {
|
||||
if (test_mode_ != 0) {
|
||||
// Print out codec and settings
|
||||
printf("Codec: %s Freq: %d Rate: %d PackSize: %d\n", codec_name,
|
||||
sampling_freq_hz, rate, pack_size);
|
||||
}
|
||||
|
||||
// Store packet size in samples, used to validate the received packet
|
||||
pack_size_samp_ = pack_size;
|
||||
|
||||
// Store the expected packet size in bytes, used to validate the received
|
||||
// packet. Add 0.875 to always round up to a whole byte.
|
||||
pack_size_bytes_ = (uint16_t)(static_cast<float>(pack_size * rate) /
|
||||
static_cast<float>(sampling_freq_hz * 8) +
|
||||
0.875);
|
||||
|
||||
// Set pointer to the ACM where to register the codec
|
||||
AudioCodingModule* my_acm = NULL;
|
||||
switch (side) {
|
||||
case 'A': {
|
||||
my_acm = acm_a_.get();
|
||||
break;
|
||||
}
|
||||
case 'B': {
|
||||
my_acm = acm_b_.get();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ASSERT_TRUE(my_acm != NULL);
|
||||
|
||||
CodecInst my_codec_param;
|
||||
// Get all codec parameters before registering
|
||||
EXPECT_GT(AudioCodingModule::Codec(codec_name, &my_codec_param,
|
||||
sampling_freq_hz, channels), -1);
|
||||
my_codec_param.rate = rate;
|
||||
my_codec_param.pacsize = pack_size;
|
||||
EXPECT_EQ(0, my_acm->RegisterSendCodec(my_codec_param));
|
||||
|
||||
send_codec_name_ = codec_name;
|
||||
}
|
||||
|
||||
void TestStereo::Run(TestPackStereo* channel, int in_channels, int out_channels,
|
||||
int percent_loss) {
|
||||
AudioFrame audio_frame;
|
||||
|
||||
int32_t out_freq_hz_b = out_file_.SamplingFrequency();
|
||||
uint16_t rec_size;
|
||||
uint32_t time_stamp_diff;
|
||||
channel->reset_payload_size();
|
||||
int error_count = 0;
|
||||
int variable_bytes = 0;
|
||||
int variable_packets = 0;
|
||||
|
||||
while (1) {
|
||||
// Simulate packet loss by setting |packet_loss_| to "true" in
|
||||
// |percent_loss| percent of the loops.
|
||||
if (percent_loss > 0) {
|
||||
if (counter_ == floor((100 / percent_loss) + 0.5)) {
|
||||
counter_ = 0;
|
||||
channel->set_lost_packet(true);
|
||||
} else {
|
||||
channel->set_lost_packet(false);
|
||||
}
|
||||
counter_++;
|
||||
}
|
||||
|
||||
// Add 10 msec to ACM
|
||||
if (in_channels == 1) {
|
||||
if (in_file_mono_->EndOfFile()) {
|
||||
break;
|
||||
}
|
||||
in_file_mono_->Read10MsData(audio_frame);
|
||||
} else {
|
||||
if (in_file_stereo_->EndOfFile()) {
|
||||
break;
|
||||
}
|
||||
in_file_stereo_->Read10MsData(audio_frame);
|
||||
}
|
||||
EXPECT_GE(acm_a_->Add10MsData(audio_frame), 0);
|
||||
|
||||
// Verify that the received packet size matches the settings.
|
||||
rec_size = channel->payload_size();
|
||||
if ((0 < rec_size) & (rec_size < 65535)) {
|
||||
if (strcmp(send_codec_name_, "opus") == 0) {
|
||||
// Opus is a variable rate codec, hence calculate the average packet
|
||||
// size, and later make sure the average is in the right range.
|
||||
variable_bytes += rec_size;
|
||||
variable_packets++;
|
||||
} else {
|
||||
// For fixed rate codecs, check that packet size is correct.
|
||||
if ((rec_size != pack_size_bytes_ * out_channels)
|
||||
&& (pack_size_bytes_ < 65535)) {
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
// Verify that the timestamp is updated with expected length
|
||||
time_stamp_diff = channel->timestamp_diff();
|
||||
if ((counter_ > 10) && (time_stamp_diff != pack_size_samp_)) {
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Run received side of ACM
|
||||
EXPECT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
|
||||
|
||||
// Write output speech to file
|
||||
out_file_.Write10MsData(
|
||||
audio_frame.data_,
|
||||
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, error_count);
|
||||
|
||||
// Check that packet size is in the right range for variable rate codecs,
|
||||
// such as Opus.
|
||||
if (variable_packets > 0) {
|
||||
variable_bytes /= variable_packets;
|
||||
EXPECT_NEAR(variable_bytes, pack_size_bytes_, 3);
|
||||
}
|
||||
|
||||
if (in_file_mono_->EndOfFile()) {
|
||||
in_file_mono_->Rewind();
|
||||
}
|
||||
if (in_file_stereo_->EndOfFile()) {
|
||||
in_file_stereo_->Rewind();
|
||||
}
|
||||
// Reset in case we ended with a lost packet
|
||||
channel->set_lost_packet(false);
|
||||
}
|
||||
|
||||
void TestStereo::OpenOutFile(int16_t test_number) {
|
||||
std::string file_name;
|
||||
std::stringstream file_stream;
|
||||
file_stream << webrtc::test::OutputPath() << "teststereo_out_" << test_number
|
||||
<< ".pcm";
|
||||
file_name = file_stream.str();
|
||||
out_file_.Open(file_name, 32000, "wb");
|
||||
}
|
||||
|
||||
void TestStereo::DisplaySendReceiveCodec() {
|
||||
auto send_codec = acm_a_->SendCodec();
|
||||
if (test_mode_ != 0) {
|
||||
ASSERT_TRUE(send_codec);
|
||||
printf("%s -> ", send_codec->plname);
|
||||
}
|
||||
CodecInst receive_codec;
|
||||
acm_b_->ReceiveCodec(&receive_codec);
|
||||
if (test_mode_ != 0) {
|
||||
printf("%s\n", receive_codec.plname);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
117
webrtc/modules/audio_coding/test/TestStereo.h
Normal file
117
webrtc/modules/audio_coding/test/TestStereo.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
|
||||
#define PCMA_AND_PCMU
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
enum StereoMonoMode {
|
||||
kNotSet,
|
||||
kMono,
|
||||
kStereo
|
||||
};
|
||||
|
||||
class TestPackStereo : public AudioPacketizationCallback {
|
||||
public:
|
||||
TestPackStereo();
|
||||
~TestPackStereo();
|
||||
|
||||
void RegisterReceiverACM(AudioCodingModule* acm);
|
||||
|
||||
int32_t SendData(const FrameType frame_type,
|
||||
const uint8_t payload_type,
|
||||
const uint32_t timestamp,
|
||||
const uint8_t* payload_data,
|
||||
const size_t payload_size,
|
||||
const RTPFragmentationHeader* fragmentation) override;
|
||||
|
||||
uint16_t payload_size();
|
||||
uint32_t timestamp_diff();
|
||||
void reset_payload_size();
|
||||
void set_codec_mode(StereoMonoMode mode);
|
||||
void set_lost_packet(bool lost);
|
||||
|
||||
private:
|
||||
AudioCodingModule* receiver_acm_;
|
||||
int16_t seq_no_;
|
||||
uint32_t timestamp_diff_;
|
||||
uint32_t last_in_timestamp_;
|
||||
uint64_t total_bytes_;
|
||||
int payload_size_;
|
||||
StereoMonoMode codec_mode_;
|
||||
// Simulate packet losses
|
||||
bool lost_packet_;
|
||||
};
|
||||
|
||||
class TestStereo : public ACMTest {
|
||||
public:
|
||||
explicit TestStereo(int test_mode);
|
||||
~TestStereo();
|
||||
|
||||
void Perform() override;
|
||||
|
||||
private:
|
||||
// The default value of '-1' indicates that the registration is based only on
|
||||
// codec name and a sampling frequncy matching is not required. This is useful
|
||||
// for codecs which support several sampling frequency.
|
||||
void RegisterSendCodec(char side, char* codec_name, int32_t samp_freq_hz,
|
||||
int rate, int pack_size, int channels,
|
||||
int payload_type);
|
||||
|
||||
void Run(TestPackStereo* channel, int in_channels, int out_channels,
|
||||
int percent_loss = 0);
|
||||
void OpenOutFile(int16_t test_number);
|
||||
void DisplaySendReceiveCodec();
|
||||
|
||||
int test_mode_;
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_a_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_b_;
|
||||
|
||||
TestPackStereo* channel_a2b_;
|
||||
|
||||
PCMFile* in_file_stereo_;
|
||||
PCMFile* in_file_mono_;
|
||||
PCMFile out_file_;
|
||||
int16_t test_cntr_;
|
||||
uint16_t pack_size_samp_;
|
||||
uint16_t pack_size_bytes_;
|
||||
int counter_;
|
||||
char* send_codec_name_;
|
||||
|
||||
// Payload types for stereo codecs and CNG
|
||||
#ifdef WEBRTC_CODEC_G722
|
||||
int g722_pltype_;
|
||||
#endif
|
||||
int l16_8khz_pltype_;
|
||||
int l16_16khz_pltype_;
|
||||
int l16_32khz_pltype_;
|
||||
#ifdef PCMA_AND_PCMU
|
||||
int pcma_pltype_;
|
||||
int pcmu_pltype_;
|
||||
#endif
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
int opus_pltype_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
|
||||
271
webrtc/modules/audio_coding/test/TestVADDTX.cc
Normal file
271
webrtc/modules/audio_coding/test/TestVADDTX.cc
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* 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/test/TestVADDTX.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
const CodecInst kIsacWb = {103, "ISAC", 16000, 480, 1, 32000};
|
||||
const CodecInst kIsacSwb = {104, "ISAC", 32000, 960, 1, 56000};
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
const CodecInst kIlbc = {102, "ILBC", 8000, 240, 1, 13300};
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
const CodecInst kOpus = {120, "opus", 48000, 960, 1, 64000};
|
||||
const CodecInst kOpusStereo = {120, "opus", 48000, 960, 2, 64000};
|
||||
#endif
|
||||
|
||||
ActivityMonitor::ActivityMonitor() {
|
||||
ResetStatistics();
|
||||
}
|
||||
|
||||
int32_t ActivityMonitor::InFrameType(FrameType frame_type) {
|
||||
counter_[frame_type]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ActivityMonitor::PrintStatistics() {
|
||||
printf("\n");
|
||||
printf("kEmptyFrame %u\n", counter_[kEmptyFrame]);
|
||||
printf("kAudioFrameSpeech %u\n", counter_[kAudioFrameSpeech]);
|
||||
printf("kAudioFrameCN %u\n", counter_[kAudioFrameCN]);
|
||||
printf("kVideoFrameKey %u\n", counter_[kVideoFrameKey]);
|
||||
printf("kVideoFrameDelta %u\n", counter_[kVideoFrameDelta]);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void ActivityMonitor::ResetStatistics() {
|
||||
memset(counter_, 0, sizeof(counter_));
|
||||
}
|
||||
|
||||
void ActivityMonitor::GetStatistics(uint32_t* counter) {
|
||||
memcpy(counter, counter_, sizeof(counter_));
|
||||
}
|
||||
|
||||
TestVadDtx::TestVadDtx()
|
||||
: acm_send_(AudioCodingModule::Create(0)),
|
||||
acm_receive_(AudioCodingModule::Create(1)),
|
||||
channel_(new Channel),
|
||||
monitor_(new ActivityMonitor) {
|
||||
EXPECT_EQ(0, acm_send_->RegisterTransportCallback(channel_.get()));
|
||||
channel_->RegisterReceiverACM(acm_receive_.get());
|
||||
EXPECT_EQ(0, acm_send_->RegisterVADCallback(monitor_.get()));
|
||||
}
|
||||
|
||||
void TestVadDtx::RegisterCodec(CodecInst codec_param) {
|
||||
// Set the codec for sending and receiving.
|
||||
EXPECT_EQ(0, acm_send_->RegisterSendCodec(codec_param));
|
||||
EXPECT_EQ(0, acm_receive_->RegisterReceiveCodec(codec_param));
|
||||
channel_->SetIsStereo(codec_param.channels > 1);
|
||||
}
|
||||
|
||||
// Encoding a file and see if the numbers that various packets occur follow
|
||||
// the expectation.
|
||||
void TestVadDtx::Run(std::string in_filename, int frequency, int channels,
|
||||
std::string out_filename, bool append,
|
||||
const int* expects) {
|
||||
monitor_->ResetStatistics();
|
||||
|
||||
PCMFile in_file;
|
||||
in_file.Open(in_filename, frequency, "rb");
|
||||
in_file.ReadStereo(channels > 1);
|
||||
|
||||
PCMFile out_file;
|
||||
if (append) {
|
||||
out_file.Open(out_filename, kOutputFreqHz, "ab");
|
||||
} else {
|
||||
out_file.Open(out_filename, kOutputFreqHz, "wb");
|
||||
}
|
||||
|
||||
uint16_t frame_size_samples = in_file.PayloadLength10Ms();
|
||||
uint32_t time_stamp = 0x12345678;
|
||||
AudioFrame audio_frame;
|
||||
while (!in_file.EndOfFile()) {
|
||||
in_file.Read10MsData(audio_frame);
|
||||
audio_frame.timestamp_ = time_stamp;
|
||||
time_stamp += frame_size_samples;
|
||||
EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
|
||||
acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame);
|
||||
out_file.Write10MsData(audio_frame);
|
||||
}
|
||||
|
||||
in_file.Close();
|
||||
out_file.Close();
|
||||
|
||||
#ifdef PRINT_STAT
|
||||
monitor_->PrintStatistics();
|
||||
#endif
|
||||
|
||||
uint32_t stats[5];
|
||||
monitor_->GetStatistics(stats);
|
||||
monitor_->ResetStatistics();
|
||||
|
||||
for (const auto& st : stats) {
|
||||
int i = &st - stats; // Calculate the current position in stats.
|
||||
switch (expects[i]) {
|
||||
case 0: {
|
||||
EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Following is the implementation of TestWebRtcVadDtx.
|
||||
TestWebRtcVadDtx::TestWebRtcVadDtx()
|
||||
: vad_enabled_(false),
|
||||
dtx_enabled_(false),
|
||||
output_file_num_(0) {
|
||||
}
|
||||
|
||||
void TestWebRtcVadDtx::Perform() {
|
||||
// Go through various test cases.
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// Register iSAC WB as send codec
|
||||
RegisterCodec(kIsacWb);
|
||||
RunTestCases();
|
||||
|
||||
// Register iSAC SWB as send codec
|
||||
RegisterCodec(kIsacSwb);
|
||||
RunTestCases();
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_ILBC
|
||||
// Register iLBC as send codec
|
||||
RegisterCodec(kIlbc);
|
||||
RunTestCases();
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
// Register Opus as send codec
|
||||
RegisterCodec(kOpus);
|
||||
RunTestCases();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Test various configurations on VAD/DTX.
|
||||
void TestWebRtcVadDtx::RunTestCases() {
|
||||
// #1 DTX = OFF, VAD = OFF, VADNormal
|
||||
SetVAD(false, false, VADNormal);
|
||||
Test(true);
|
||||
|
||||
// #2 DTX = ON, VAD = ON, VADAggr
|
||||
SetVAD(true, true, VADAggr);
|
||||
Test(false);
|
||||
|
||||
// #3 DTX = ON, VAD = ON, VADLowBitrate
|
||||
SetVAD(true, true, VADLowBitrate);
|
||||
Test(false);
|
||||
|
||||
// #4 DTX = ON, VAD = ON, VADVeryAggr
|
||||
SetVAD(true, true, VADVeryAggr);
|
||||
Test(false);
|
||||
|
||||
// #5 DTX = ON, VAD = ON, VADNormal
|
||||
SetVAD(true, true, VADNormal);
|
||||
Test(false);
|
||||
}
|
||||
|
||||
// Set the expectation and run the test.
|
||||
void TestWebRtcVadDtx::Test(bool new_outfile) {
|
||||
int expects[] = {-1, 1, dtx_enabled_, 0, 0};
|
||||
if (new_outfile) {
|
||||
output_file_num_++;
|
||||
}
|
||||
std::stringstream out_filename;
|
||||
out_filename << webrtc::test::OutputPath()
|
||||
<< "testWebRtcVadDtx_outFile_"
|
||||
<< output_file_num_
|
||||
<< ".pcm";
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename.str(), !new_outfile, expects);
|
||||
}
|
||||
|
||||
void TestWebRtcVadDtx::SetVAD(bool enable_dtx, bool enable_vad,
|
||||
ACMVADMode vad_mode) {
|
||||
ACMVADMode mode;
|
||||
EXPECT_EQ(0, acm_send_->SetVAD(enable_dtx, enable_vad, vad_mode));
|
||||
EXPECT_EQ(0, acm_send_->VAD(&dtx_enabled_, &vad_enabled_, &mode));
|
||||
|
||||
auto codec_param = acm_send_->SendCodec();
|
||||
ASSERT_TRUE(codec_param);
|
||||
if (STR_CASE_CMP(codec_param->plname, "opus") == 0) {
|
||||
// If send codec is Opus, WebRTC VAD/DTX cannot be used.
|
||||
enable_dtx = enable_vad = false;
|
||||
}
|
||||
|
||||
EXPECT_EQ(dtx_enabled_ , enable_dtx); // DTX should be set as expected.
|
||||
|
||||
if (dtx_enabled_) {
|
||||
EXPECT_TRUE(vad_enabled_); // WebRTC DTX cannot run without WebRTC VAD.
|
||||
} else {
|
||||
// Using no DTX should not affect setting of VAD.
|
||||
EXPECT_EQ(enable_vad, vad_enabled_);
|
||||
}
|
||||
}
|
||||
|
||||
// Following is the implementation of TestOpusDtx.
|
||||
void TestOpusDtx::Perform() {
|
||||
#ifdef WEBRTC_CODEC_ISAC
|
||||
// If we set other codec than Opus, DTX cannot be toggled.
|
||||
RegisterCodec(kIsacWb);
|
||||
EXPECT_EQ(-1, acm_send_->EnableOpusDtx());
|
||||
EXPECT_EQ(-1, acm_send_->DisableOpusDtx());
|
||||
#endif
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
int expects[] = {0, 1, 0, 0, 0};
|
||||
|
||||
// Register Opus as send codec
|
||||
std::string out_filename = webrtc::test::OutputPath() +
|
||||
"testOpusDtx_outFile_mono.pcm";
|
||||
RegisterCodec(kOpus);
|
||||
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
|
||||
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename, false, expects);
|
||||
|
||||
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
|
||||
expects[kEmptyFrame] = 1;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"),
|
||||
32000, 1, out_filename, true, expects);
|
||||
|
||||
// Register stereo Opus as send codec
|
||||
out_filename = webrtc::test::OutputPath() + "testOpusDtx_outFile_stereo.pcm";
|
||||
RegisterCodec(kOpusStereo);
|
||||
EXPECT_EQ(0, acm_send_->DisableOpusDtx());
|
||||
expects[kEmptyFrame] = 0;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
|
||||
32000, 2, out_filename, false, expects);
|
||||
|
||||
EXPECT_EQ(0, acm_send_->EnableOpusDtx());
|
||||
|
||||
expects[kEmptyFrame] = 1;
|
||||
Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"),
|
||||
32000, 2, out_filename, true, expects);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
102
webrtc/modules/audio_coding/test/TestVADDTX.h
Normal file
102
webrtc/modules/audio_coding/test/TestVADDTX.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
|
||||
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class ActivityMonitor : public ACMVADCallback {
|
||||
public:
|
||||
ActivityMonitor();
|
||||
int32_t InFrameType(FrameType frame_type);
|
||||
void PrintStatistics();
|
||||
void ResetStatistics();
|
||||
void GetStatistics(uint32_t* stats);
|
||||
private:
|
||||
// 0 - kEmptyFrame
|
||||
// 1 - kAudioFrameSpeech
|
||||
// 2 - kAudioFrameCN
|
||||
// 3 - kVideoFrameKey (not used by audio)
|
||||
// 4 - kVideoFrameDelta (not used by audio)
|
||||
uint32_t counter_[5];
|
||||
};
|
||||
|
||||
|
||||
// TestVadDtx is to verify that VAD/DTX perform as they should. It runs through
|
||||
// an audio file and check if the occurrence of various packet types follows
|
||||
// expectation. TestVadDtx needs its derived class to implement the Perform()
|
||||
// to put the test together.
|
||||
class TestVadDtx : public ACMTest {
|
||||
public:
|
||||
static const int kOutputFreqHz = 16000;
|
||||
|
||||
TestVadDtx();
|
||||
|
||||
virtual void Perform() = 0;
|
||||
|
||||
protected:
|
||||
void RegisterCodec(CodecInst codec_param);
|
||||
|
||||
// Encoding a file and see if the numbers that various packets occur follow
|
||||
// the expectation. Saves result to a file.
|
||||
// expects[x] means
|
||||
// -1 : do not care,
|
||||
// 0 : there have been no packets of type |x|,
|
||||
// 1 : there have been packets of type |x|,
|
||||
// with |x| indicates the following packet types
|
||||
// 0 - kEmptyFrame
|
||||
// 1 - kAudioFrameSpeech
|
||||
// 2 - kAudioFrameCN
|
||||
// 3 - kVideoFrameKey (not used by audio)
|
||||
// 4 - kVideoFrameDelta (not used by audio)
|
||||
void Run(std::string in_filename, int frequency, int channels,
|
||||
std::string out_filename, bool append, const int* expects);
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_send_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_receive_;
|
||||
rtc::scoped_ptr<Channel> channel_;
|
||||
rtc::scoped_ptr<ActivityMonitor> monitor_;
|
||||
};
|
||||
|
||||
// TestWebRtcVadDtx is to verify that the WebRTC VAD/DTX perform as they should.
|
||||
class TestWebRtcVadDtx final : public TestVadDtx {
|
||||
public:
|
||||
TestWebRtcVadDtx();
|
||||
|
||||
void Perform() override;
|
||||
|
||||
private:
|
||||
void RunTestCases();
|
||||
void Test(bool new_outfile);
|
||||
void SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode vad_mode);
|
||||
|
||||
bool vad_enabled_;
|
||||
bool dtx_enabled_;
|
||||
int output_file_num_;
|
||||
};
|
||||
|
||||
// TestOpusDtx is to verify that the Opus DTX performs as it should.
|
||||
class TestOpusDtx final : public TestVadDtx {
|
||||
public:
|
||||
void Perform() override;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
|
||||
171
webrtc/modules/audio_coding/test/Tester.cc
Normal file
171
webrtc/modules/audio_coding/test/Tester.cc
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/APITest.h"
|
||||
#include "webrtc/modules/audio_coding/test/EncodeDecodeTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/iSACTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/opus_test.h"
|
||||
#include "webrtc/modules/audio_coding/test/PacketLossTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestAllCodecs.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestRedFec.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestStereo.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestVADDTX.h"
|
||||
#include "webrtc/modules/audio_coding/test/TwoWayCommunication.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||
|
||||
using webrtc::Trace;
|
||||
|
||||
// This parameter is used to describe how to run the tests. It is normally
|
||||
// set to 0, and all tests are run in quite mode.
|
||||
#define ACM_TEST_MODE 0
|
||||
|
||||
TEST(AudioCodingModuleTest, TestAllCodecs) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_allcodecs_trace.txt").c_str());
|
||||
webrtc::TestAllCodecs(ACM_TEST_MODE).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestEncodeDecode)) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_encodedecode_trace.txt").c_str());
|
||||
webrtc::EncodeDecodeTest(ACM_TEST_MODE).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_CODEC_RED
|
||||
#define IF_RED(x) x
|
||||
#else
|
||||
#define IF_RED(x) DISABLED_##x
|
||||
#endif
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(IF_RED(TestRedFec))) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_fec_trace.txt").c_str());
|
||||
webrtc::TestRedFec().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
#define IF_ISAC(x) x
|
||||
#else
|
||||
#define IF_ISAC(x) DISABLED_##x
|
||||
#endif
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(IF_ISAC(TestIsac))) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_isac_trace.txt").c_str());
|
||||
webrtc::ISACTest(ACM_TEST_MODE).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \
|
||||
defined(WEBRTC_CODEC_ILBC) && defined(WEBRTC_CODEC_G722)
|
||||
#define IF_ALL_CODECS(x) x
|
||||
#else
|
||||
#define IF_ALL_CODECS(x) DISABLED_##x
|
||||
#endif
|
||||
|
||||
TEST(AudioCodingModuleTest,
|
||||
DISABLED_ON_ANDROID(IF_ALL_CODECS(TwoWayCommunication))) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_twowaycom_trace.txt").c_str());
|
||||
webrtc::TwoWayCommunication(ACM_TEST_MODE).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestStereo)) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_stereo_trace.txt").c_str());
|
||||
webrtc::TestStereo(ACM_TEST_MODE).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestWebRtcVadDtx)) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_vaddtx_trace.txt").c_str());
|
||||
webrtc::TestWebRtcVadDtx().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestOpusDtx) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_opusdtx_trace.txt").c_str());
|
||||
webrtc::TestOpusDtx().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestOpus) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_opus_trace.txt").c_str());
|
||||
webrtc::OpusTest().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestPacketLoss) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_packetloss_trace.txt").c_str());
|
||||
webrtc::PacketLossTest(1, 10, 10, 1).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestPacketLossBurst) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_packetloss_burst_trace.txt").c_str());
|
||||
webrtc::PacketLossTest(1, 10, 10, 2).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestPacketLossStereo) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_packetloss_trace.txt").c_str());
|
||||
webrtc::PacketLossTest(2, 10, 10, 1).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
TEST(AudioCodingModuleTest, TestPacketLossStereoBurst) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_packetloss_burst_trace.txt").c_str());
|
||||
webrtc::PacketLossTest(2, 10, 10, 2).Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
|
||||
// The full API test is too long to run automatically on bots, but can be used
|
||||
// for offline testing. User interaction is needed.
|
||||
#ifdef ACM_TEST_FULL_API
|
||||
TEST(AudioCodingModuleTest, TestAPI) {
|
||||
Trace::CreateTrace();
|
||||
Trace::SetTraceFile((webrtc::test::OutputPath() +
|
||||
"acm_apitest_trace.txt").c_str());
|
||||
webrtc::APITest().Perform();
|
||||
Trace::ReturnTrace();
|
||||
}
|
||||
#endif
|
||||
58
webrtc/modules/audio_coding/test/TimedTrace.cc
Normal file
58
webrtc/modules/audio_coding/test/TimedTrace.cc
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 "TimedTrace.h"
|
||||
#include <math.h>
|
||||
|
||||
double TimedTrace::_timeEllapsedSec = 0;
|
||||
FILE* TimedTrace::_timedTraceFile = NULL;
|
||||
|
||||
TimedTrace::TimedTrace() {
|
||||
|
||||
}
|
||||
|
||||
TimedTrace::~TimedTrace() {
|
||||
if (_timedTraceFile != NULL) {
|
||||
fclose(_timedTraceFile);
|
||||
}
|
||||
_timedTraceFile = NULL;
|
||||
}
|
||||
|
||||
int16_t TimedTrace::SetUp(char* fileName) {
|
||||
if (_timedTraceFile == NULL) {
|
||||
_timedTraceFile = fopen(fileName, "w");
|
||||
}
|
||||
if (_timedTraceFile == NULL) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TimedTrace::SetTimeEllapsed(double timeEllapsedSec) {
|
||||
_timeEllapsedSec = timeEllapsedSec;
|
||||
}
|
||||
|
||||
double TimedTrace::TimeEllapsed() {
|
||||
return _timeEllapsedSec;
|
||||
}
|
||||
|
||||
void TimedTrace::Tick10Msec() {
|
||||
_timeEllapsedSec += 0.010;
|
||||
}
|
||||
|
||||
void TimedTrace::TimedLogg(char* message) {
|
||||
unsigned int minutes = (uint32_t) floor(_timeEllapsedSec / 60.0);
|
||||
double seconds = _timeEllapsedSec - minutes * 60;
|
||||
//char myFormat[100] = "%8.2f, %3u:%05.2f: %s\n";
|
||||
if (_timedTraceFile != NULL) {
|
||||
fprintf(_timedTraceFile, "%8.2f, %3u:%05.2f: %s\n", _timeEllapsedSec,
|
||||
minutes, seconds, message);
|
||||
}
|
||||
}
|
||||
36
webrtc/modules/audio_coding/test/TimedTrace.h
Normal file
36
webrtc/modules/audio_coding/test/TimedTrace.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
class TimedTrace {
|
||||
public:
|
||||
TimedTrace();
|
||||
~TimedTrace();
|
||||
|
||||
void SetTimeEllapsed(double myTime);
|
||||
double TimeEllapsed();
|
||||
void Tick10Msec();
|
||||
int16_t SetUp(char* fileName);
|
||||
void TimedLogg(char* message);
|
||||
|
||||
private:
|
||||
static double _timeEllapsedSec;
|
||||
static FILE* _timedTraceFile;
|
||||
|
||||
};
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TIMEDTRACE_H_
|
||||
299
webrtc/modules/audio_coding/test/TwoWayCommunication.cc
Normal file
299
webrtc/modules/audio_coding/test/TwoWayCommunication.cc
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 "TwoWayCommunication.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#define MAX_FILE_NAME_LENGTH_BYTE 500
|
||||
|
||||
TwoWayCommunication::TwoWayCommunication(int testMode)
|
||||
: _acmA(AudioCodingModule::Create(1)),
|
||||
_acmRefA(AudioCodingModule::Create(3)),
|
||||
_testMode(testMode) {
|
||||
AudioCodingModule::Config config;
|
||||
// The clicks will be more obvious in FAX mode. TODO(henrik.lundin) Really?
|
||||
config.neteq_config.playout_mode = kPlayoutFax;
|
||||
config.id = 2;
|
||||
_acmB.reset(AudioCodingModule::Create(config));
|
||||
config.id = 4;
|
||||
_acmRefB.reset(AudioCodingModule::Create(config));
|
||||
}
|
||||
|
||||
TwoWayCommunication::~TwoWayCommunication() {
|
||||
delete _channel_A2B;
|
||||
delete _channel_B2A;
|
||||
delete _channelRef_A2B;
|
||||
delete _channelRef_B2A;
|
||||
#ifdef WEBRTC_DTMF_DETECTION
|
||||
if (_dtmfDetectorA != NULL) {
|
||||
delete _dtmfDetectorA;
|
||||
}
|
||||
if (_dtmfDetectorB != NULL) {
|
||||
delete _dtmfDetectorB;
|
||||
}
|
||||
#endif
|
||||
_inFileA.Close();
|
||||
_inFileB.Close();
|
||||
_outFileA.Close();
|
||||
_outFileB.Close();
|
||||
_outFileRefA.Close();
|
||||
_outFileRefB.Close();
|
||||
}
|
||||
|
||||
void TwoWayCommunication::ChooseCodec(uint8_t* codecID_A,
|
||||
uint8_t* codecID_B) {
|
||||
rtc::scoped_ptr<AudioCodingModule> tmpACM(AudioCodingModule::Create(0));
|
||||
uint8_t noCodec = tmpACM->NumberOfCodecs();
|
||||
CodecInst codecInst;
|
||||
printf("List of Supported Codecs\n");
|
||||
printf("========================\n");
|
||||
for (uint8_t codecCntr = 0; codecCntr < noCodec; codecCntr++) {
|
||||
EXPECT_EQ(tmpACM->Codec(codecCntr, &codecInst), 0);
|
||||
printf("%d- %s\n", codecCntr, codecInst.plname);
|
||||
}
|
||||
printf("\nChoose a send codec for side A [0]: ");
|
||||
char myStr[15] = "";
|
||||
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
|
||||
*codecID_A = (uint8_t) atoi(myStr);
|
||||
|
||||
printf("\nChoose a send codec for side B [0]: ");
|
||||
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
|
||||
*codecID_B = (uint8_t) atoi(myStr);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void TwoWayCommunication::SetUp() {
|
||||
uint8_t codecID_A;
|
||||
uint8_t codecID_B;
|
||||
|
||||
ChooseCodec(&codecID_A, &codecID_B);
|
||||
CodecInst codecInst_A;
|
||||
CodecInst codecInst_B;
|
||||
CodecInst dummyCodec;
|
||||
EXPECT_EQ(0, _acmA->Codec(codecID_A, &codecInst_A));
|
||||
EXPECT_EQ(0, _acmB->Codec(codecID_B, &codecInst_B));
|
||||
EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
|
||||
|
||||
//--- Set A codecs
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
|
||||
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(codecInst_B));
|
||||
//--- Set ref-A codecs
|
||||
EXPECT_EQ(0, _acmRefA->RegisterSendCodec(codecInst_A));
|
||||
EXPECT_EQ(0, _acmRefA->RegisterReceiveCodec(codecInst_B));
|
||||
|
||||
//--- Set B codecs
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(codecInst_B));
|
||||
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(codecInst_A));
|
||||
|
||||
//--- Set ref-B codecs
|
||||
EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
|
||||
EXPECT_EQ(0, _acmRefB->RegisterReceiveCodec(codecInst_A));
|
||||
|
||||
uint16_t frequencyHz;
|
||||
|
||||
//--- Input A
|
||||
std::string in_file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
frequencyHz = 32000;
|
||||
printf("Enter input file at side A [%s]: ", in_file_name.c_str());
|
||||
PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
|
||||
_inFileA.Open(in_file_name, frequencyHz, "rb");
|
||||
|
||||
//--- Output A
|
||||
std::string out_file_a = webrtc::test::OutputPath() + "outA.pcm";
|
||||
printf("Output file at side A: %s\n", out_file_a.c_str());
|
||||
printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
|
||||
_outFileA.Open(out_file_a, frequencyHz, "wb");
|
||||
std::string ref_file_name = webrtc::test::OutputPath() + "ref_outA.pcm";
|
||||
_outFileRefA.Open(ref_file_name, frequencyHz, "wb");
|
||||
|
||||
//--- Input B
|
||||
in_file_name = webrtc::test::ResourcePath("audio_coding/testfile32kHz",
|
||||
"pcm");
|
||||
frequencyHz = 32000;
|
||||
printf("\n\nEnter input file at side B [%s]: ", in_file_name.c_str());
|
||||
PCMFile::ChooseFile(&in_file_name, 499, &frequencyHz);
|
||||
_inFileB.Open(in_file_name, frequencyHz, "rb");
|
||||
|
||||
//--- Output B
|
||||
std::string out_file_b = webrtc::test::OutputPath() + "outB.pcm";
|
||||
printf("Output file at side B: %s\n", out_file_b.c_str());
|
||||
printf("Sampling frequency (in Hz) of the above file: %u\n", frequencyHz);
|
||||
_outFileB.Open(out_file_b, frequencyHz, "wb");
|
||||
ref_file_name = webrtc::test::OutputPath() + "ref_outB.pcm";
|
||||
_outFileRefB.Open(ref_file_name, frequencyHz, "wb");
|
||||
|
||||
//--- Set A-to-B channel
|
||||
_channel_A2B = new Channel;
|
||||
_acmA->RegisterTransportCallback(_channel_A2B);
|
||||
_channel_A2B->RegisterReceiverACM(_acmB.get());
|
||||
//--- Do the same for the reference
|
||||
_channelRef_A2B = new Channel;
|
||||
_acmRefA->RegisterTransportCallback(_channelRef_A2B);
|
||||
_channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
|
||||
|
||||
//--- Set B-to-A channel
|
||||
_channel_B2A = new Channel;
|
||||
_acmB->RegisterTransportCallback(_channel_B2A);
|
||||
_channel_B2A->RegisterReceiverACM(_acmA.get());
|
||||
//--- Do the same for reference
|
||||
_channelRef_B2A = new Channel;
|
||||
_acmRefB->RegisterTransportCallback(_channelRef_B2A);
|
||||
_channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
|
||||
}
|
||||
|
||||
void TwoWayCommunication::SetUpAutotest() {
|
||||
CodecInst codecInst_A;
|
||||
CodecInst codecInst_B;
|
||||
CodecInst dummyCodec;
|
||||
|
||||
EXPECT_EQ(0, _acmA->Codec("ISAC", &codecInst_A, 16000, 1));
|
||||
EXPECT_EQ(0, _acmB->Codec("L16", &codecInst_B, 8000, 1));
|
||||
EXPECT_EQ(0, _acmA->Codec(6, &dummyCodec));
|
||||
|
||||
//--- Set A codecs
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(codecInst_A));
|
||||
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(codecInst_B));
|
||||
|
||||
//--- Set ref-A codecs
|
||||
EXPECT_GT(_acmRefA->RegisterSendCodec(codecInst_A), -1);
|
||||
EXPECT_GT(_acmRefA->RegisterReceiveCodec(codecInst_B), -1);
|
||||
|
||||
//--- Set B codecs
|
||||
EXPECT_GT(_acmB->RegisterSendCodec(codecInst_B), -1);
|
||||
EXPECT_GT(_acmB->RegisterReceiveCodec(codecInst_A), -1);
|
||||
|
||||
//--- Set ref-B codecs
|
||||
EXPECT_EQ(0, _acmRefB->RegisterSendCodec(codecInst_B));
|
||||
EXPECT_EQ(0, _acmRefB->RegisterReceiveCodec(codecInst_A));
|
||||
|
||||
uint16_t frequencyHz;
|
||||
|
||||
//--- Input A and B
|
||||
std::string in_file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
frequencyHz = 16000;
|
||||
_inFileA.Open(in_file_name, frequencyHz, "rb");
|
||||
_inFileB.Open(in_file_name, frequencyHz, "rb");
|
||||
|
||||
//--- Output A
|
||||
std::string output_file_a = webrtc::test::OutputPath() + "outAutotestA.pcm";
|
||||
frequencyHz = 16000;
|
||||
_outFileA.Open(output_file_a, frequencyHz, "wb");
|
||||
std::string output_ref_file_a = webrtc::test::OutputPath()
|
||||
+ "ref_outAutotestA.pcm";
|
||||
_outFileRefA.Open(output_ref_file_a, frequencyHz, "wb");
|
||||
|
||||
//--- Output B
|
||||
std::string output_file_b = webrtc::test::OutputPath() + "outAutotestB.pcm";
|
||||
frequencyHz = 16000;
|
||||
_outFileB.Open(output_file_b, frequencyHz, "wb");
|
||||
std::string output_ref_file_b = webrtc::test::OutputPath()
|
||||
+ "ref_outAutotestB.pcm";
|
||||
_outFileRefB.Open(output_ref_file_b, frequencyHz, "wb");
|
||||
|
||||
//--- Set A-to-B channel
|
||||
_channel_A2B = new Channel;
|
||||
_acmA->RegisterTransportCallback(_channel_A2B);
|
||||
_channel_A2B->RegisterReceiverACM(_acmB.get());
|
||||
//--- Do the same for the reference
|
||||
_channelRef_A2B = new Channel;
|
||||
_acmRefA->RegisterTransportCallback(_channelRef_A2B);
|
||||
_channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
|
||||
|
||||
//--- Set B-to-A channel
|
||||
_channel_B2A = new Channel;
|
||||
_acmB->RegisterTransportCallback(_channel_B2A);
|
||||
_channel_B2A->RegisterReceiverACM(_acmA.get());
|
||||
//--- Do the same for reference
|
||||
_channelRef_B2A = new Channel;
|
||||
_acmRefB->RegisterTransportCallback(_channelRef_B2A);
|
||||
_channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
|
||||
}
|
||||
|
||||
void TwoWayCommunication::Perform() {
|
||||
if (_testMode == 0) {
|
||||
SetUpAutotest();
|
||||
} else {
|
||||
SetUp();
|
||||
}
|
||||
unsigned int msecPassed = 0;
|
||||
unsigned int secPassed = 0;
|
||||
|
||||
int32_t outFreqHzA = _outFileA.SamplingFrequency();
|
||||
int32_t outFreqHzB = _outFileB.SamplingFrequency();
|
||||
|
||||
AudioFrame audioFrame;
|
||||
|
||||
auto codecInst_B = _acmB->SendCodec();
|
||||
ASSERT_TRUE(codecInst_B);
|
||||
|
||||
// In the following loop we tests that the code can handle misuse of the APIs.
|
||||
// In the middle of a session with data flowing between two sides, called A
|
||||
// and B, APIs will be called, and the code should continue to run, and be
|
||||
// able to recover.
|
||||
while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
|
||||
msecPassed += 10;
|
||||
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmRefA->Add10MsData(audioFrame), 0);
|
||||
|
||||
EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
|
||||
|
||||
EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
|
||||
EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame));
|
||||
_outFileA.Write10MsData(audioFrame);
|
||||
EXPECT_EQ(0, _acmRefA->PlayoutData10Ms(outFreqHzA, &audioFrame));
|
||||
_outFileRefA.Write10MsData(audioFrame);
|
||||
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
|
||||
_outFileB.Write10MsData(audioFrame);
|
||||
EXPECT_EQ(0, _acmRefB->PlayoutData10Ms(outFreqHzB, &audioFrame));
|
||||
_outFileRefB.Write10MsData(audioFrame);
|
||||
|
||||
// Update time counters each time a second of data has passed.
|
||||
if (msecPassed >= 1000) {
|
||||
msecPassed = 0;
|
||||
secPassed++;
|
||||
}
|
||||
// Re-register send codec on side B.
|
||||
if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(*codecInst_B));
|
||||
EXPECT_TRUE(_acmB->SendCodec());
|
||||
}
|
||||
// Initialize receiver on side A.
|
||||
if (((secPassed % 7) == 6) && (msecPassed == 0))
|
||||
EXPECT_EQ(0, _acmA->InitializeReceiver());
|
||||
// Re-register codec on side A.
|
||||
if (((secPassed % 7) == 6) && (msecPassed >= 990)) {
|
||||
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(*codecInst_B));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
60
webrtc/modules/audio_coding/test/TwoWayCommunication.h
Normal file
60
webrtc/modules/audio_coding/test/TwoWayCommunication.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class TwoWayCommunication : public ACMTest {
|
||||
public:
|
||||
explicit TwoWayCommunication(int testMode);
|
||||
~TwoWayCommunication();
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
void ChooseCodec(uint8_t* codecID_A, uint8_t* codecID_B);
|
||||
void SetUp();
|
||||
void SetUpAutotest();
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmB;
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmRefA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmRefB;
|
||||
|
||||
Channel* _channel_A2B;
|
||||
Channel* _channel_B2A;
|
||||
|
||||
Channel* _channelRef_A2B;
|
||||
Channel* _channelRef_B2A;
|
||||
|
||||
PCMFile _inFileA;
|
||||
PCMFile _inFileB;
|
||||
|
||||
PCMFile _outFileA;
|
||||
PCMFile _outFileB;
|
||||
|
||||
PCMFile _outFileRefA;
|
||||
PCMFile _outFileRefB;
|
||||
|
||||
int _testMode;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
|
||||
265
webrtc/modules/audio_coding/test/delay_test.cc
Normal file
265
webrtc/modules/audio_coding/test/delay_test.cc
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/event_wrapper.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
DEFINE_string(codec, "isac", "Codec Name");
|
||||
DEFINE_int32(sample_rate_hz, 16000, "Sampling rate in Hertz.");
|
||||
DEFINE_int32(num_channels, 1, "Number of Channels.");
|
||||
DEFINE_string(input_file, "", "Input file, PCM16 32 kHz, optional.");
|
||||
DEFINE_int32(delay, 0, "Delay in millisecond.");
|
||||
DEFINE_bool(dtx, false, "Enable DTX at the sender side.");
|
||||
DEFINE_bool(packet_loss, false, "Apply packet loss, c.f. Channel{.cc, .h}.");
|
||||
DEFINE_bool(fec, false, "Use Forward Error Correction (FEC).");
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
struct CodecSettings {
|
||||
char name[50];
|
||||
int sample_rate_hz;
|
||||
int num_channels;
|
||||
};
|
||||
|
||||
struct AcmSettings {
|
||||
bool dtx;
|
||||
bool fec;
|
||||
};
|
||||
|
||||
struct TestSettings {
|
||||
CodecSettings codec;
|
||||
AcmSettings acm;
|
||||
bool packet_loss;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class DelayTest {
|
||||
public:
|
||||
DelayTest()
|
||||
: acm_a_(AudioCodingModule::Create(0)),
|
||||
acm_b_(AudioCodingModule::Create(1)),
|
||||
channel_a2b_(new Channel),
|
||||
test_cntr_(0),
|
||||
encoding_sample_rate_hz_(8000) {}
|
||||
|
||||
~DelayTest() {
|
||||
if (channel_a2b_ != NULL) {
|
||||
delete channel_a2b_;
|
||||
channel_a2b_ = NULL;
|
||||
}
|
||||
in_file_a_.Close();
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
test_cntr_ = 0;
|
||||
std::string file_name = webrtc::test::ResourcePath(
|
||||
"audio_coding/testfile32kHz", "pcm");
|
||||
if (FLAGS_input_file.size() > 0)
|
||||
file_name = FLAGS_input_file;
|
||||
in_file_a_.Open(file_name, 32000, "rb");
|
||||
ASSERT_EQ(0, acm_a_->InitializeReceiver()) <<
|
||||
"Couldn't initialize receiver.\n";
|
||||
ASSERT_EQ(0, acm_b_->InitializeReceiver()) <<
|
||||
"Couldn't initialize receiver.\n";
|
||||
|
||||
if (FLAGS_delay > 0) {
|
||||
ASSERT_EQ(0, acm_b_->SetMinimumPlayoutDelay(FLAGS_delay)) <<
|
||||
"Failed to set minimum delay.\n";
|
||||
}
|
||||
|
||||
int num_encoders = acm_a_->NumberOfCodecs();
|
||||
CodecInst my_codec_param;
|
||||
for (int n = 0; n < num_encoders; n++) {
|
||||
EXPECT_EQ(0, acm_b_->Codec(n, &my_codec_param)) <<
|
||||
"Failed to get codec.";
|
||||
if (STR_CASE_CMP(my_codec_param.plname, "opus") == 0)
|
||||
my_codec_param.channels = 1;
|
||||
else if (my_codec_param.channels > 1)
|
||||
continue;
|
||||
if (STR_CASE_CMP(my_codec_param.plname, "CN") == 0 &&
|
||||
my_codec_param.plfreq == 48000)
|
||||
continue;
|
||||
if (STR_CASE_CMP(my_codec_param.plname, "telephone-event") == 0)
|
||||
continue;
|
||||
ASSERT_EQ(0, acm_b_->RegisterReceiveCodec(my_codec_param)) <<
|
||||
"Couldn't register receive codec.\n";
|
||||
}
|
||||
|
||||
// Create and connect the channel
|
||||
ASSERT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_)) <<
|
||||
"Couldn't register Transport callback.\n";
|
||||
channel_a2b_->RegisterReceiverACM(acm_b_.get());
|
||||
}
|
||||
|
||||
void Perform(const TestSettings* config, size_t num_tests, int duration_sec,
|
||||
const char* output_prefix) {
|
||||
for (size_t n = 0; n < num_tests; ++n) {
|
||||
ApplyConfig(config[n]);
|
||||
Run(duration_sec, output_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void ApplyConfig(const TestSettings& config) {
|
||||
printf("====================================\n");
|
||||
printf("Test %d \n"
|
||||
"Codec: %s, %d kHz, %d channel(s)\n"
|
||||
"ACM: DTX %s, FEC %s\n"
|
||||
"Channel: %s\n",
|
||||
++test_cntr_, config.codec.name, config.codec.sample_rate_hz,
|
||||
config.codec.num_channels, config.acm.dtx ? "on" : "off",
|
||||
config.acm.fec ? "on" : "off",
|
||||
config.packet_loss ? "with packet-loss" : "no packet-loss");
|
||||
SendCodec(config.codec);
|
||||
ConfigAcm(config.acm);
|
||||
ConfigChannel(config.packet_loss);
|
||||
}
|
||||
|
||||
void SendCodec(const CodecSettings& config) {
|
||||
CodecInst my_codec_param;
|
||||
ASSERT_EQ(0, AudioCodingModule::Codec(
|
||||
config.name, &my_codec_param, config.sample_rate_hz,
|
||||
config.num_channels)) << "Specified codec is not supported.\n";
|
||||
|
||||
encoding_sample_rate_hz_ = my_codec_param.plfreq;
|
||||
ASSERT_EQ(0, acm_a_->RegisterSendCodec(my_codec_param)) <<
|
||||
"Failed to register send-codec.\n";
|
||||
}
|
||||
|
||||
void ConfigAcm(const AcmSettings& config) {
|
||||
ASSERT_EQ(0, acm_a_->SetVAD(config.dtx, config.dtx, VADAggr)) <<
|
||||
"Failed to set VAD.\n";
|
||||
ASSERT_EQ(0, acm_a_->SetREDStatus(config.fec)) <<
|
||||
"Failed to set RED.\n";
|
||||
}
|
||||
|
||||
void ConfigChannel(bool packet_loss) {
|
||||
channel_a2b_->SetFECTestWithPacketLoss(packet_loss);
|
||||
}
|
||||
|
||||
void OpenOutFile(const char* output_id) {
|
||||
std::stringstream file_stream;
|
||||
file_stream << "delay_test_" << FLAGS_codec << "_" << FLAGS_sample_rate_hz
|
||||
<< "Hz" << "_" << FLAGS_delay << "ms.pcm";
|
||||
std::cout << "Output file: " << file_stream.str() << std::endl << std::endl;
|
||||
std::string file_name = webrtc::test::OutputPath() + file_stream.str();
|
||||
out_file_b_.Open(file_name.c_str(), 32000, "wb");
|
||||
}
|
||||
|
||||
void Run(int duration_sec, const char* output_prefix) {
|
||||
OpenOutFile(output_prefix);
|
||||
AudioFrame audio_frame;
|
||||
uint32_t out_freq_hz_b = out_file_b_.SamplingFrequency();
|
||||
|
||||
int num_frames = 0;
|
||||
int in_file_frames = 0;
|
||||
uint32_t playout_ts;
|
||||
uint32_t received_ts;
|
||||
double average_delay = 0;
|
||||
double inst_delay_sec = 0;
|
||||
while (num_frames < (duration_sec * 100)) {
|
||||
if (in_file_a_.EndOfFile()) {
|
||||
in_file_a_.Rewind();
|
||||
}
|
||||
|
||||
// Print delay information every 16 frame
|
||||
if ((num_frames & 0x3F) == 0x3F) {
|
||||
NetworkStatistics statistics;
|
||||
acm_b_->GetNetworkStatistics(&statistics);
|
||||
fprintf(stdout, "delay: min=%3d max=%3d mean=%3d median=%3d"
|
||||
" ts-based average = %6.3f, "
|
||||
"curr buff-lev = %4u opt buff-lev = %4u \n",
|
||||
statistics.minWaitingTimeMs, statistics.maxWaitingTimeMs,
|
||||
statistics.meanWaitingTimeMs, statistics.medianWaitingTimeMs,
|
||||
average_delay, statistics.currentBufferSize,
|
||||
statistics.preferredBufferSize);
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
in_file_a_.Read10MsData(audio_frame);
|
||||
ASSERT_GE(acm_a_->Add10MsData(audio_frame), 0);
|
||||
ASSERT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
|
||||
out_file_b_.Write10MsData(
|
||||
audio_frame.data_,
|
||||
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
|
||||
acm_b_->PlayoutTimestamp(&playout_ts);
|
||||
received_ts = channel_a2b_->LastInTimestamp();
|
||||
inst_delay_sec = static_cast<uint32_t>(received_ts - playout_ts)
|
||||
/ static_cast<double>(encoding_sample_rate_hz_);
|
||||
|
||||
if (num_frames > 10)
|
||||
average_delay = 0.95 * average_delay + 0.05 * inst_delay_sec;
|
||||
|
||||
++num_frames;
|
||||
++in_file_frames;
|
||||
}
|
||||
out_file_b_.Close();
|
||||
}
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_a_;
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_b_;
|
||||
|
||||
Channel* channel_a2b_;
|
||||
|
||||
PCMFile in_file_a_;
|
||||
PCMFile out_file_b_;
|
||||
int test_cntr_;
|
||||
int encoding_sample_rate_hz_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
webrtc::TestSettings test_setting;
|
||||
strcpy(test_setting.codec.name, FLAGS_codec.c_str());
|
||||
|
||||
if (FLAGS_sample_rate_hz != 8000 &&
|
||||
FLAGS_sample_rate_hz != 16000 &&
|
||||
FLAGS_sample_rate_hz != 32000 &&
|
||||
FLAGS_sample_rate_hz != 48000) {
|
||||
std::cout << "Invalid sampling rate.\n";
|
||||
return 1;
|
||||
}
|
||||
test_setting.codec.sample_rate_hz = FLAGS_sample_rate_hz;
|
||||
if (FLAGS_num_channels < 1 || FLAGS_num_channels > 2) {
|
||||
std::cout << "Only mono and stereo are supported.\n";
|
||||
return 1;
|
||||
}
|
||||
test_setting.codec.num_channels = FLAGS_num_channels;
|
||||
test_setting.acm.dtx = FLAGS_dtx;
|
||||
test_setting.acm.fec = FLAGS_fec;
|
||||
test_setting.packet_loss = FLAGS_packet_loss;
|
||||
|
||||
webrtc::DelayTest delay_test;
|
||||
delay_test.Initialize();
|
||||
delay_test.Perform(&test_setting, 1, 240, "delay_test");
|
||||
return 0;
|
||||
}
|
||||
339
webrtc/modules/audio_coding/test/iSACTest.cc
Normal file
339
webrtc/modules/audio_coding/test/iSACTest.cc
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* 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/test/iSACTest.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#elif WEBRTC_LINUX
|
||||
#include <time.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/event_wrapper.h"
|
||||
#include "webrtc/system_wrappers/include/tick_util.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void SetISACConfigDefault(ACMTestISACConfig& isacConfig) {
|
||||
isacConfig.currentRateBitPerSec = 0;
|
||||
isacConfig.currentFrameSizeMsec = 0;
|
||||
isacConfig.encodingMode = -1;
|
||||
isacConfig.initRateBitPerSec = 0;
|
||||
isacConfig.initFrameSizeInMsec = 0;
|
||||
isacConfig.enforceFrameSize = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t SetISAConfig(ACMTestISACConfig& isacConfig, AudioCodingModule* acm,
|
||||
int testMode) {
|
||||
|
||||
if ((isacConfig.currentRateBitPerSec != 0)
|
||||
|| (isacConfig.currentFrameSizeMsec != 0)) {
|
||||
auto sendCodec = acm->SendCodec();
|
||||
EXPECT_TRUE(sendCodec);
|
||||
if (isacConfig.currentRateBitPerSec < 0) {
|
||||
// Register iSAC in adaptive (channel-dependent) mode.
|
||||
sendCodec->rate = -1;
|
||||
EXPECT_EQ(0, acm->RegisterSendCodec(*sendCodec));
|
||||
} else {
|
||||
if (isacConfig.currentRateBitPerSec != 0) {
|
||||
sendCodec->rate = isacConfig.currentRateBitPerSec;
|
||||
}
|
||||
if (isacConfig.currentFrameSizeMsec != 0) {
|
||||
sendCodec->pacsize = isacConfig.currentFrameSizeMsec
|
||||
* (sendCodec->plfreq / 1000);
|
||||
}
|
||||
EXPECT_EQ(0, acm->RegisterSendCodec(*sendCodec));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ISACTest::ISACTest(int testMode)
|
||||
: _acmA(AudioCodingModule::Create(1)),
|
||||
_acmB(AudioCodingModule::Create(2)),
|
||||
_testMode(testMode) {}
|
||||
|
||||
ISACTest::~ISACTest() {}
|
||||
|
||||
void ISACTest::Setup() {
|
||||
int codecCntr;
|
||||
CodecInst codecParam;
|
||||
|
||||
for (codecCntr = 0; codecCntr < AudioCodingModule::NumberOfCodecs();
|
||||
codecCntr++) {
|
||||
EXPECT_EQ(0, AudioCodingModule::Codec(codecCntr, &codecParam));
|
||||
if (!STR_CASE_CMP(codecParam.plname, "ISAC")
|
||||
&& codecParam.plfreq == 16000) {
|
||||
memcpy(&_paramISAC16kHz, &codecParam, sizeof(CodecInst));
|
||||
_idISAC16kHz = codecCntr;
|
||||
}
|
||||
if (!STR_CASE_CMP(codecParam.plname, "ISAC")
|
||||
&& codecParam.plfreq == 32000) {
|
||||
memcpy(&_paramISAC32kHz, &codecParam, sizeof(CodecInst));
|
||||
_idISAC32kHz = codecCntr;
|
||||
}
|
||||
}
|
||||
|
||||
// Register both iSAC-wb & iSAC-swb in both sides as receiver codecs.
|
||||
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(_paramISAC16kHz));
|
||||
EXPECT_EQ(0, _acmA->RegisterReceiveCodec(_paramISAC32kHz));
|
||||
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(_paramISAC16kHz));
|
||||
EXPECT_EQ(0, _acmB->RegisterReceiveCodec(_paramISAC32kHz));
|
||||
|
||||
//--- Set A-to-B channel
|
||||
_channel_A2B.reset(new Channel);
|
||||
EXPECT_EQ(0, _acmA->RegisterTransportCallback(_channel_A2B.get()));
|
||||
_channel_A2B->RegisterReceiverACM(_acmB.get());
|
||||
|
||||
//--- Set B-to-A channel
|
||||
_channel_B2A.reset(new Channel);
|
||||
EXPECT_EQ(0, _acmB->RegisterTransportCallback(_channel_B2A.get()));
|
||||
_channel_B2A->RegisterReceiverACM(_acmA.get());
|
||||
|
||||
file_name_swb_ = webrtc::test::ResourcePath("audio_coding/testfile32kHz",
|
||||
"pcm");
|
||||
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
|
||||
|
||||
_inFileA.Open(file_name_swb_, 32000, "rb");
|
||||
std::string fileNameA = webrtc::test::OutputPath() + "testisac_a.pcm";
|
||||
std::string fileNameB = webrtc::test::OutputPath() + "testisac_b.pcm";
|
||||
_outFileA.Open(fileNameA, 32000, "wb");
|
||||
_outFileB.Open(fileNameB, 32000, "wb");
|
||||
|
||||
while (!_inFileA.EndOfFile()) {
|
||||
Run10ms();
|
||||
}
|
||||
CodecInst receiveCodec;
|
||||
EXPECT_EQ(0, _acmA->ReceiveCodec(&receiveCodec));
|
||||
EXPECT_EQ(0, _acmB->ReceiveCodec(&receiveCodec));
|
||||
|
||||
_inFileA.Close();
|
||||
_outFileA.Close();
|
||||
_outFileB.Close();
|
||||
}
|
||||
|
||||
void ISACTest::Perform() {
|
||||
Setup();
|
||||
|
||||
int16_t testNr = 0;
|
||||
ACMTestISACConfig wbISACConfig;
|
||||
ACMTestISACConfig swbISACConfig;
|
||||
|
||||
SetISACConfigDefault(wbISACConfig);
|
||||
SetISACConfigDefault(swbISACConfig);
|
||||
|
||||
wbISACConfig.currentRateBitPerSec = -1;
|
||||
swbISACConfig.currentRateBitPerSec = -1;
|
||||
testNr++;
|
||||
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
|
||||
|
||||
if (_testMode != 0) {
|
||||
SetISACConfigDefault(wbISACConfig);
|
||||
SetISACConfigDefault(swbISACConfig);
|
||||
|
||||
wbISACConfig.currentRateBitPerSec = -1;
|
||||
swbISACConfig.currentRateBitPerSec = -1;
|
||||
wbISACConfig.initRateBitPerSec = 13000;
|
||||
wbISACConfig.initFrameSizeInMsec = 60;
|
||||
swbISACConfig.initRateBitPerSec = 20000;
|
||||
swbISACConfig.initFrameSizeInMsec = 30;
|
||||
testNr++;
|
||||
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
|
||||
|
||||
SetISACConfigDefault(wbISACConfig);
|
||||
SetISACConfigDefault(swbISACConfig);
|
||||
|
||||
wbISACConfig.currentRateBitPerSec = 20000;
|
||||
swbISACConfig.currentRateBitPerSec = 48000;
|
||||
testNr++;
|
||||
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
|
||||
|
||||
wbISACConfig.currentRateBitPerSec = 16000;
|
||||
swbISACConfig.currentRateBitPerSec = 30000;
|
||||
wbISACConfig.currentFrameSizeMsec = 60;
|
||||
testNr++;
|
||||
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
|
||||
}
|
||||
|
||||
SetISACConfigDefault(wbISACConfig);
|
||||
SetISACConfigDefault(swbISACConfig);
|
||||
testNr++;
|
||||
EncodeDecode(testNr, wbISACConfig, swbISACConfig);
|
||||
|
||||
testNr++;
|
||||
if (_testMode == 0) {
|
||||
SwitchingSamplingRate(testNr, 4);
|
||||
} else {
|
||||
SwitchingSamplingRate(testNr, 80);
|
||||
}
|
||||
}
|
||||
|
||||
void ISACTest::Run10ms() {
|
||||
AudioFrame audioFrame;
|
||||
EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
|
||||
EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
|
||||
EXPECT_EQ(0, _acmA->PlayoutData10Ms(32000, &audioFrame));
|
||||
_outFileA.Write10MsData(audioFrame);
|
||||
EXPECT_EQ(0, _acmB->PlayoutData10Ms(32000, &audioFrame));
|
||||
_outFileB.Write10MsData(audioFrame);
|
||||
}
|
||||
|
||||
void ISACTest::EncodeDecode(int testNr, ACMTestISACConfig& wbISACConfig,
|
||||
ACMTestISACConfig& swbISACConfig) {
|
||||
// Files in Side A and B
|
||||
_inFileA.Open(file_name_swb_, 32000, "rb", true);
|
||||
_inFileB.Open(file_name_swb_, 32000, "rb", true);
|
||||
|
||||
std::string file_name_out;
|
||||
std::stringstream file_stream_a;
|
||||
std::stringstream file_stream_b;
|
||||
file_stream_a << webrtc::test::OutputPath();
|
||||
file_stream_b << webrtc::test::OutputPath();
|
||||
file_stream_a << "out_iSACTest_A_" << testNr << ".pcm";
|
||||
file_stream_b << "out_iSACTest_B_" << testNr << ".pcm";
|
||||
file_name_out = file_stream_a.str();
|
||||
_outFileA.Open(file_name_out, 32000, "wb");
|
||||
file_name_out = file_stream_b.str();
|
||||
_outFileB.Open(file_name_out, 32000, "wb");
|
||||
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC16kHz));
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC32kHz));
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
|
||||
|
||||
// Side A is sending super-wideband, and side B is sending wideband.
|
||||
SetISAConfig(swbISACConfig, _acmA.get(), _testMode);
|
||||
SetISAConfig(wbISACConfig, _acmB.get(), _testMode);
|
||||
|
||||
bool adaptiveMode = false;
|
||||
if ((swbISACConfig.currentRateBitPerSec == -1)
|
||||
|| (wbISACConfig.currentRateBitPerSec == -1)) {
|
||||
adaptiveMode = true;
|
||||
}
|
||||
_myTimer.Reset();
|
||||
_channel_A2B->ResetStats();
|
||||
_channel_B2A->ResetStats();
|
||||
|
||||
char currentTime[500];
|
||||
EventTimerWrapper* myEvent = EventTimerWrapper::Create();
|
||||
EXPECT_TRUE(myEvent->StartTimer(true, 10));
|
||||
while (!(_inFileA.EndOfFile() || _inFileA.Rewinded())) {
|
||||
Run10ms();
|
||||
_myTimer.Tick10ms();
|
||||
_myTimer.CurrentTimeHMS(currentTime);
|
||||
|
||||
if ((adaptiveMode) && (_testMode != 0)) {
|
||||
myEvent->Wait(5000);
|
||||
EXPECT_TRUE(_acmA->SendCodec());
|
||||
EXPECT_TRUE(_acmB->SendCodec());
|
||||
}
|
||||
}
|
||||
|
||||
if (_testMode != 0) {
|
||||
printf("\n\nSide A statistics\n\n");
|
||||
_channel_A2B->PrintStats(_paramISAC32kHz);
|
||||
|
||||
printf("\n\nSide B statistics\n\n");
|
||||
_channel_B2A->PrintStats(_paramISAC16kHz);
|
||||
}
|
||||
|
||||
_channel_A2B->ResetStats();
|
||||
_channel_B2A->ResetStats();
|
||||
|
||||
_outFileA.Close();
|
||||
_outFileB.Close();
|
||||
_inFileA.Close();
|
||||
_inFileB.Close();
|
||||
}
|
||||
|
||||
void ISACTest::SwitchingSamplingRate(int testNr, int maxSampRateChange) {
|
||||
// Files in Side A
|
||||
_inFileA.Open(file_name_swb_, 32000, "rb");
|
||||
_inFileB.Open(file_name_swb_, 32000, "rb");
|
||||
|
||||
std::string file_name_out;
|
||||
std::stringstream file_stream_a;
|
||||
std::stringstream file_stream_b;
|
||||
file_stream_a << webrtc::test::OutputPath();
|
||||
file_stream_b << webrtc::test::OutputPath();
|
||||
file_stream_a << "out_iSACTest_A_" << testNr << ".pcm";
|
||||
file_stream_b << "out_iSACTest_B_" << testNr << ".pcm";
|
||||
file_name_out = file_stream_a.str();
|
||||
_outFileA.Open(file_name_out, 32000, "wb");
|
||||
file_name_out = file_stream_b.str();
|
||||
_outFileB.Open(file_name_out, 32000, "wb");
|
||||
|
||||
// Start with side A sending super-wideband and side B seding wideband.
|
||||
// Toggle sending wideband/super-wideband in this test.
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
|
||||
|
||||
int numSendCodecChanged = 0;
|
||||
_myTimer.Reset();
|
||||
char currentTime[50];
|
||||
while (numSendCodecChanged < (maxSampRateChange << 1)) {
|
||||
Run10ms();
|
||||
_myTimer.Tick10ms();
|
||||
_myTimer.CurrentTimeHMS(currentTime);
|
||||
if (_testMode == 2)
|
||||
printf("\r%s", currentTime);
|
||||
if (_inFileA.EndOfFile()) {
|
||||
if (_inFileA.SamplingFrequency() == 16000) {
|
||||
// Switch side A to send super-wideband.
|
||||
_inFileA.Close();
|
||||
_inFileA.Open(file_name_swb_, 32000, "rb");
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC32kHz));
|
||||
} else {
|
||||
// Switch side A to send wideband.
|
||||
_inFileA.Close();
|
||||
_inFileA.Open(file_name_swb_, 32000, "rb");
|
||||
EXPECT_EQ(0, _acmA->RegisterSendCodec(_paramISAC16kHz));
|
||||
}
|
||||
numSendCodecChanged++;
|
||||
}
|
||||
|
||||
if (_inFileB.EndOfFile()) {
|
||||
if (_inFileB.SamplingFrequency() == 16000) {
|
||||
// Switch side B to send super-wideband.
|
||||
_inFileB.Close();
|
||||
_inFileB.Open(file_name_swb_, 32000, "rb");
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC32kHz));
|
||||
} else {
|
||||
// Switch side B to send wideband.
|
||||
_inFileB.Close();
|
||||
_inFileB.Open(file_name_swb_, 32000, "rb");
|
||||
EXPECT_EQ(0, _acmB->RegisterSendCodec(_paramISAC16kHz));
|
||||
}
|
||||
numSendCodecChanged++;
|
||||
}
|
||||
}
|
||||
_outFileA.Close();
|
||||
_outFileB.Close();
|
||||
_inFileA.Close();
|
||||
_inFileB.Close();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
79
webrtc/modules/audio_coding/test/iSACTest.h
Normal file
79
webrtc/modules/audio_coding/test/iSACTest.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
|
||||
#define MAX_FILE_NAME_LENGTH_BYTE 500
|
||||
#define NO_OF_CLIENTS 15
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct ACMTestISACConfig {
|
||||
int32_t currentRateBitPerSec;
|
||||
int16_t currentFrameSizeMsec;
|
||||
int16_t encodingMode;
|
||||
uint32_t initRateBitPerSec;
|
||||
int16_t initFrameSizeInMsec;
|
||||
bool enforceFrameSize;
|
||||
};
|
||||
|
||||
class ISACTest : public ACMTest {
|
||||
public:
|
||||
explicit ISACTest(int testMode);
|
||||
~ISACTest();
|
||||
|
||||
void Perform();
|
||||
private:
|
||||
void Setup();
|
||||
|
||||
void Run10ms();
|
||||
|
||||
void EncodeDecode(int testNr, ACMTestISACConfig& wbISACConfig,
|
||||
ACMTestISACConfig& swbISACConfig);
|
||||
|
||||
void SwitchingSamplingRate(int testNr, int maxSampRateChange);
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmA;
|
||||
rtc::scoped_ptr<AudioCodingModule> _acmB;
|
||||
|
||||
rtc::scoped_ptr<Channel> _channel_A2B;
|
||||
rtc::scoped_ptr<Channel> _channel_B2A;
|
||||
|
||||
PCMFile _inFileA;
|
||||
PCMFile _inFileB;
|
||||
|
||||
PCMFile _outFileA;
|
||||
PCMFile _outFileB;
|
||||
|
||||
uint8_t _idISAC16kHz;
|
||||
uint8_t _idISAC32kHz;
|
||||
CodecInst _paramISAC16kHz;
|
||||
CodecInst _paramISAC32kHz;
|
||||
|
||||
std::string file_name_swb_;
|
||||
|
||||
ACMTestTimer _myTimer;
|
||||
int _testMode;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_ISACTEST_H_
|
||||
307
webrtc/modules/audio_coding/test/insert_packet_with_timing.cc
Normal file
307
webrtc/modules/audio_coding/test/insert_packet_with_timing.cc
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 <stdio.h>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
// Codec.
|
||||
DEFINE_string(codec, "opus", "Codec Name");
|
||||
DEFINE_int32(codec_sample_rate_hz, 48000, "Sampling rate in Hertz.");
|
||||
DEFINE_int32(codec_channels, 1, "Number of channels of the codec.");
|
||||
|
||||
// PCM input/output.
|
||||
DEFINE_string(input, "", "Input PCM file at 16 kHz.");
|
||||
DEFINE_bool(input_stereo, false, "Input is stereo.");
|
||||
DEFINE_int32(input_fs_hz, 32000, "Input sample rate Hz.");
|
||||
DEFINE_string(output, "insert_rtp_with_timing_out.pcm", "OutputFile");
|
||||
DEFINE_int32(output_fs_hz, 32000, "Output sample rate Hz");
|
||||
|
||||
// Timing files
|
||||
DEFINE_string(seq_num, "seq_num", "Sequence number file.");
|
||||
DEFINE_string(send_ts, "send_timestamp", "Send timestamp file.");
|
||||
DEFINE_string(receive_ts, "last_rec_timestamp", "Receive timestamp file");
|
||||
|
||||
// Delay logging
|
||||
DEFINE_string(delay, "", "Log for delay.");
|
||||
|
||||
// Other setups
|
||||
DEFINE_bool(verbose, false, "Verbosity.");
|
||||
DEFINE_double(loss_rate, 0, "Rate of packet loss < 1");
|
||||
|
||||
const int32_t kAudioPlayedOut = 0x00000001;
|
||||
const int32_t kPacketPushedIn = 0x00000001 << 1;
|
||||
const int kPlayoutPeriodMs = 10;
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class InsertPacketWithTiming {
|
||||
public:
|
||||
InsertPacketWithTiming()
|
||||
: sender_clock_(new SimulatedClock(0)),
|
||||
receiver_clock_(new SimulatedClock(0)),
|
||||
send_acm_(AudioCodingModule::Create(0, sender_clock_)),
|
||||
receive_acm_(AudioCodingModule::Create(0, receiver_clock_)),
|
||||
channel_(new Channel),
|
||||
seq_num_fid_(fopen(FLAGS_seq_num.c_str(), "rt")),
|
||||
send_ts_fid_(fopen(FLAGS_send_ts.c_str(), "rt")),
|
||||
receive_ts_fid_(fopen(FLAGS_receive_ts.c_str(), "rt")),
|
||||
pcm_out_fid_(fopen(FLAGS_output.c_str(), "wb")),
|
||||
samples_in_1ms_(48),
|
||||
num_10ms_in_codec_frame_(2), // Typical 20 ms frames.
|
||||
time_to_insert_packet_ms_(3), // An arbitrary offset on pushing packet.
|
||||
next_receive_ts_(0),
|
||||
time_to_playout_audio_ms_(kPlayoutPeriodMs),
|
||||
loss_threshold_(0),
|
||||
playout_timing_fid_(fopen("playout_timing.txt", "wt")) {}
|
||||
|
||||
void SetUp() {
|
||||
ASSERT_TRUE(sender_clock_ != NULL);
|
||||
ASSERT_TRUE(receiver_clock_ != NULL);
|
||||
|
||||
ASSERT_TRUE(send_acm_.get() != NULL);
|
||||
ASSERT_TRUE(receive_acm_.get() != NULL);
|
||||
ASSERT_TRUE(channel_ != NULL);
|
||||
|
||||
ASSERT_TRUE(seq_num_fid_ != NULL);
|
||||
ASSERT_TRUE(send_ts_fid_ != NULL);
|
||||
ASSERT_TRUE(receive_ts_fid_ != NULL);
|
||||
|
||||
ASSERT_TRUE(playout_timing_fid_ != NULL);
|
||||
|
||||
next_receive_ts_ = ReceiveTimestamp();
|
||||
|
||||
CodecInst codec;
|
||||
ASSERT_EQ(0, AudioCodingModule::Codec(FLAGS_codec.c_str(), &codec,
|
||||
FLAGS_codec_sample_rate_hz,
|
||||
FLAGS_codec_channels));
|
||||
ASSERT_EQ(0, receive_acm_->InitializeReceiver());
|
||||
ASSERT_EQ(0, send_acm_->RegisterSendCodec(codec));
|
||||
ASSERT_EQ(0, receive_acm_->RegisterReceiveCodec(codec));
|
||||
|
||||
// Set codec-dependent parameters.
|
||||
samples_in_1ms_ = codec.plfreq / 1000;
|
||||
num_10ms_in_codec_frame_ = codec.pacsize / (codec.plfreq / 100);
|
||||
|
||||
channel_->RegisterReceiverACM(receive_acm_.get());
|
||||
send_acm_->RegisterTransportCallback(channel_);
|
||||
|
||||
if (FLAGS_input.size() == 0) {
|
||||
std::string file_name = test::ResourcePath("audio_coding/testfile32kHz",
|
||||
"pcm");
|
||||
pcm_in_fid_.Open(file_name, 32000, "r", true); // auto-rewind
|
||||
std::cout << "Input file " << file_name << " 32 kHz mono." << std::endl;
|
||||
} else {
|
||||
pcm_in_fid_.Open(FLAGS_input, static_cast<uint16_t>(FLAGS_input_fs_hz),
|
||||
"r", true); // auto-rewind
|
||||
std::cout << "Input file " << FLAGS_input << "at " << FLAGS_input_fs_hz
|
||||
<< " Hz in " << ((FLAGS_input_stereo) ? "stereo." : "mono.")
|
||||
<< std::endl;
|
||||
pcm_in_fid_.ReadStereo(FLAGS_input_stereo);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(pcm_out_fid_ != NULL);
|
||||
std::cout << "Output file " << FLAGS_output << " at " << FLAGS_output_fs_hz
|
||||
<< " Hz." << std::endl;
|
||||
|
||||
// Other setups
|
||||
if (FLAGS_loss_rate > 0)
|
||||
loss_threshold_ = RAND_MAX * FLAGS_loss_rate;
|
||||
else
|
||||
loss_threshold_ = 0;
|
||||
}
|
||||
|
||||
void TickOneMillisecond(uint32_t* action) {
|
||||
// One millisecond passed.
|
||||
time_to_insert_packet_ms_--;
|
||||
time_to_playout_audio_ms_--;
|
||||
sender_clock_->AdvanceTimeMilliseconds(1);
|
||||
receiver_clock_->AdvanceTimeMilliseconds(1);
|
||||
|
||||
// Reset action.
|
||||
*action = 0;
|
||||
|
||||
// Is it time to pull audio?
|
||||
if (time_to_playout_audio_ms_ == 0) {
|
||||
time_to_playout_audio_ms_ = kPlayoutPeriodMs;
|
||||
receive_acm_->PlayoutData10Ms(static_cast<int>(FLAGS_output_fs_hz),
|
||||
&frame_);
|
||||
fwrite(frame_.data_, sizeof(frame_.data_[0]),
|
||||
frame_.samples_per_channel_ * frame_.num_channels_, pcm_out_fid_);
|
||||
*action |= kAudioPlayedOut;
|
||||
}
|
||||
|
||||
// Is it time to push in next packet?
|
||||
if (time_to_insert_packet_ms_ <= .5) {
|
||||
*action |= kPacketPushedIn;
|
||||
|
||||
// Update time-to-insert packet.
|
||||
uint32_t t = next_receive_ts_;
|
||||
next_receive_ts_ = ReceiveTimestamp();
|
||||
time_to_insert_packet_ms_ += static_cast<float>(next_receive_ts_ - t) /
|
||||
samples_in_1ms_;
|
||||
|
||||
// Push in just enough audio.
|
||||
for (int n = 0; n < num_10ms_in_codec_frame_; n++) {
|
||||
pcm_in_fid_.Read10MsData(frame_);
|
||||
EXPECT_GE(send_acm_->Add10MsData(frame_), 0);
|
||||
}
|
||||
|
||||
// Set the parameters for the packet to be pushed in receiver ACM right
|
||||
// now.
|
||||
uint32_t ts = SendTimestamp();
|
||||
int seq_num = SequenceNumber();
|
||||
bool lost = false;
|
||||
channel_->set_send_timestamp(ts);
|
||||
channel_->set_sequence_number(seq_num);
|
||||
if (loss_threshold_ > 0 && rand() < loss_threshold_) {
|
||||
channel_->set_num_packets_to_drop(1);
|
||||
lost = true;
|
||||
}
|
||||
|
||||
if (FLAGS_verbose) {
|
||||
if (!lost) {
|
||||
std::cout << "\nInserting packet number " << seq_num
|
||||
<< " timestamp " << ts << std::endl;
|
||||
} else {
|
||||
std::cout << "\nLost packet number " << seq_num
|
||||
<< " timestamp " << ts << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown() {
|
||||
delete channel_;
|
||||
|
||||
fclose(seq_num_fid_);
|
||||
fclose(send_ts_fid_);
|
||||
fclose(receive_ts_fid_);
|
||||
fclose(pcm_out_fid_);
|
||||
pcm_in_fid_.Close();
|
||||
}
|
||||
|
||||
~InsertPacketWithTiming() {
|
||||
delete sender_clock_;
|
||||
delete receiver_clock_;
|
||||
}
|
||||
|
||||
// Are there more info to simulate.
|
||||
bool HasPackets() {
|
||||
if (feof(seq_num_fid_) || feof(send_ts_fid_) || feof(receive_ts_fid_))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Jitter buffer delay.
|
||||
void Delay(int* optimal_delay, int* current_delay) {
|
||||
NetworkStatistics statistics;
|
||||
receive_acm_->GetNetworkStatistics(&statistics);
|
||||
*optimal_delay = statistics.preferredBufferSize;
|
||||
*current_delay = statistics.currentBufferSize;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t SendTimestamp() {
|
||||
uint32_t t;
|
||||
EXPECT_EQ(1, fscanf(send_ts_fid_, "%u\n", &t));
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32_t ReceiveTimestamp() {
|
||||
uint32_t t;
|
||||
EXPECT_EQ(1, fscanf(receive_ts_fid_, "%u\n", &t));
|
||||
return t;
|
||||
}
|
||||
|
||||
int SequenceNumber() {
|
||||
int n;
|
||||
EXPECT_EQ(1, fscanf(seq_num_fid_, "%d\n", &n));
|
||||
return n;
|
||||
}
|
||||
|
||||
// This class just creates these pointers, not deleting them. They are deleted
|
||||
// by the associated ACM.
|
||||
SimulatedClock* sender_clock_;
|
||||
SimulatedClock* receiver_clock_;
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> send_acm_;
|
||||
rtc::scoped_ptr<AudioCodingModule> receive_acm_;
|
||||
Channel* channel_;
|
||||
|
||||
FILE* seq_num_fid_; // Input (text), one sequence number per line.
|
||||
FILE* send_ts_fid_; // Input (text), one send timestamp per line.
|
||||
FILE* receive_ts_fid_; // Input (text), one receive timestamp per line.
|
||||
FILE* pcm_out_fid_; // Output PCM16.
|
||||
|
||||
PCMFile pcm_in_fid_; // Input PCM16.
|
||||
|
||||
int samples_in_1ms_;
|
||||
|
||||
// TODO(turajs): this can be computed from the send timestamp, but there is
|
||||
// some complication to account for lost and reordered packets.
|
||||
int num_10ms_in_codec_frame_;
|
||||
|
||||
float time_to_insert_packet_ms_;
|
||||
uint32_t next_receive_ts_;
|
||||
uint32_t time_to_playout_audio_ms_;
|
||||
|
||||
AudioFrame frame_;
|
||||
|
||||
double loss_threshold_;
|
||||
|
||||
// Output (text), sequence number, playout timestamp, time (ms) of playout,
|
||||
// per line.
|
||||
FILE* playout_timing_fid_;
|
||||
};
|
||||
|
||||
} // webrtc
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
webrtc::InsertPacketWithTiming test;
|
||||
test.SetUp();
|
||||
|
||||
FILE* delay_log = NULL;
|
||||
if (FLAGS_delay.size() > 0) {
|
||||
delay_log = fopen(FLAGS_delay.c_str(), "wt");
|
||||
if (delay_log == NULL) {
|
||||
std::cout << "Cannot open the file to log delay values." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t action_taken;
|
||||
int optimal_delay_ms;
|
||||
int current_delay_ms;
|
||||
while (test.HasPackets()) {
|
||||
test.TickOneMillisecond(&action_taken);
|
||||
|
||||
if (action_taken != 0) {
|
||||
test.Delay(&optimal_delay_ms, ¤t_delay_ms);
|
||||
if (delay_log != NULL) {
|
||||
fprintf(delay_log, "%3d %3d\n", optimal_delay_ms, current_delay_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
test.TearDown();
|
||||
if (delay_log != NULL)
|
||||
fclose(delay_log);
|
||||
}
|
||||
380
webrtc/modules/audio_coding/test/opus_test.cc
Normal file
380
webrtc/modules/audio_coding/test/opus_test.cc
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/test/opus_test.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/engine_configurations.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestStereo.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/system_wrappers/include/trace.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
OpusTest::OpusTest()
|
||||
: acm_receiver_(AudioCodingModule::Create(0)),
|
||||
channel_a2b_(NULL),
|
||||
counter_(0),
|
||||
payload_type_(255),
|
||||
rtp_timestamp_(0) {}
|
||||
|
||||
OpusTest::~OpusTest() {
|
||||
if (channel_a2b_ != NULL) {
|
||||
delete channel_a2b_;
|
||||
channel_a2b_ = NULL;
|
||||
}
|
||||
if (opus_mono_encoder_ != NULL) {
|
||||
WebRtcOpus_EncoderFree(opus_mono_encoder_);
|
||||
opus_mono_encoder_ = NULL;
|
||||
}
|
||||
if (opus_stereo_encoder_ != NULL) {
|
||||
WebRtcOpus_EncoderFree(opus_stereo_encoder_);
|
||||
opus_stereo_encoder_ = NULL;
|
||||
}
|
||||
if (opus_mono_decoder_ != NULL) {
|
||||
WebRtcOpus_DecoderFree(opus_mono_decoder_);
|
||||
opus_mono_decoder_ = NULL;
|
||||
}
|
||||
if (opus_stereo_decoder_ != NULL) {
|
||||
WebRtcOpus_DecoderFree(opus_stereo_decoder_);
|
||||
opus_stereo_decoder_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void OpusTest::Perform() {
|
||||
#ifndef WEBRTC_CODEC_OPUS
|
||||
// Opus isn't defined, exit.
|
||||
return;
|
||||
#else
|
||||
uint16_t frequency_hz;
|
||||
int audio_channels;
|
||||
int16_t test_cntr = 0;
|
||||
|
||||
// Open both mono and stereo test files in 32 kHz.
|
||||
const std::string file_name_stereo =
|
||||
webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm");
|
||||
const std::string file_name_mono =
|
||||
webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
|
||||
frequency_hz = 32000;
|
||||
in_file_stereo_.Open(file_name_stereo, frequency_hz, "rb");
|
||||
in_file_stereo_.ReadStereo(true);
|
||||
in_file_mono_.Open(file_name_mono, frequency_hz, "rb");
|
||||
in_file_mono_.ReadStereo(false);
|
||||
|
||||
// Create Opus encoders for mono and stereo.
|
||||
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1, 0), -1);
|
||||
ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1), -1);
|
||||
|
||||
// Create Opus decoders for mono and stereo for stand-alone testing of Opus.
|
||||
ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1), -1);
|
||||
ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2), -1);
|
||||
WebRtcOpus_DecoderInit(opus_mono_decoder_);
|
||||
WebRtcOpus_DecoderInit(opus_stereo_decoder_);
|
||||
|
||||
ASSERT_TRUE(acm_receiver_.get() != NULL);
|
||||
EXPECT_EQ(0, acm_receiver_->InitializeReceiver());
|
||||
|
||||
// Register Opus stereo as receiving codec.
|
||||
CodecInst opus_codec_param;
|
||||
int codec_id = acm_receiver_->Codec("opus", 48000, 2);
|
||||
EXPECT_EQ(0, acm_receiver_->Codec(codec_id, &opus_codec_param));
|
||||
payload_type_ = opus_codec_param.pltype;
|
||||
EXPECT_EQ(0, acm_receiver_->RegisterReceiveCodec(opus_codec_param));
|
||||
|
||||
// Create and connect the channel.
|
||||
channel_a2b_ = new TestPackStereo;
|
||||
channel_a2b_->RegisterReceiverACM(acm_receiver_.get());
|
||||
|
||||
//
|
||||
// Test Stereo.
|
||||
//
|
||||
|
||||
channel_a2b_->set_codec_mode(kStereo);
|
||||
audio_channels = 2;
|
||||
test_cntr++;
|
||||
OpenOutFile(test_cntr);
|
||||
|
||||
// Run Opus with 2.5 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 120);
|
||||
|
||||
// Run Opus with 5 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 240);
|
||||
|
||||
// Run Opus with 10 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 480);
|
||||
|
||||
// Run Opus with 20 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960);
|
||||
|
||||
// Run Opus with 40 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 1920);
|
||||
|
||||
// Run Opus with 60 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 64000, 2880);
|
||||
|
||||
out_file_.Close();
|
||||
out_file_standalone_.Close();
|
||||
|
||||
//
|
||||
// Test Opus stereo with packet-losses.
|
||||
//
|
||||
|
||||
test_cntr++;
|
||||
OpenOutFile(test_cntr);
|
||||
|
||||
// Run Opus with 20 ms frame size, 1% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 1);
|
||||
|
||||
// Run Opus with 20 ms frame size, 5% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 5);
|
||||
|
||||
// Run Opus with 20 ms frame size, 10% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 10);
|
||||
|
||||
out_file_.Close();
|
||||
out_file_standalone_.Close();
|
||||
|
||||
//
|
||||
// Test Mono.
|
||||
//
|
||||
channel_a2b_->set_codec_mode(kMono);
|
||||
audio_channels = 1;
|
||||
test_cntr++;
|
||||
OpenOutFile(test_cntr);
|
||||
|
||||
// Register Opus mono as receiving codec.
|
||||
opus_codec_param.channels = 1;
|
||||
EXPECT_EQ(0, acm_receiver_->RegisterReceiveCodec(opus_codec_param));
|
||||
|
||||
// Run Opus with 2.5 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 120);
|
||||
|
||||
// Run Opus with 5 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 240);
|
||||
|
||||
// Run Opus with 10 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 480);
|
||||
|
||||
// Run Opus with 20 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 960);
|
||||
|
||||
// Run Opus with 40 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 1920);
|
||||
|
||||
// Run Opus with 60 ms frame size.
|
||||
Run(channel_a2b_, audio_channels, 32000, 2880);
|
||||
|
||||
out_file_.Close();
|
||||
out_file_standalone_.Close();
|
||||
|
||||
//
|
||||
// Test Opus mono with packet-losses.
|
||||
//
|
||||
test_cntr++;
|
||||
OpenOutFile(test_cntr);
|
||||
|
||||
// Run Opus with 20 ms frame size, 1% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 1);
|
||||
|
||||
// Run Opus with 20 ms frame size, 5% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 5);
|
||||
|
||||
// Run Opus with 20 ms frame size, 10% packet loss.
|
||||
Run(channel_a2b_, audio_channels, 64000, 960, 10);
|
||||
|
||||
// Close the files.
|
||||
in_file_stereo_.Close();
|
||||
in_file_mono_.Close();
|
||||
out_file_.Close();
|
||||
out_file_standalone_.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpusTest::Run(TestPackStereo* channel, int channels, int bitrate,
|
||||
int frame_length, int percent_loss) {
|
||||
AudioFrame audio_frame;
|
||||
int32_t out_freq_hz_b = out_file_.SamplingFrequency();
|
||||
const int kBufferSizeSamples = 480 * 12 * 2; // Can hold 120 ms stereo audio.
|
||||
int16_t audio[kBufferSizeSamples];
|
||||
int16_t out_audio[kBufferSizeSamples];
|
||||
int16_t audio_type;
|
||||
int written_samples = 0;
|
||||
int read_samples = 0;
|
||||
int decoded_samples = 0;
|
||||
bool first_packet = true;
|
||||
uint32_t start_time_stamp = 0;
|
||||
|
||||
channel->reset_payload_size();
|
||||
counter_ = 0;
|
||||
|
||||
// Set encoder rate.
|
||||
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_mono_encoder_, bitrate));
|
||||
EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_stereo_encoder_, bitrate));
|
||||
|
||||
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
|
||||
// If we are on Android, iOS and/or ARM, use a lower complexity setting as
|
||||
// default.
|
||||
const int kOpusComplexity5 = 5;
|
||||
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_mono_encoder_, kOpusComplexity5));
|
||||
EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_stereo_encoder_,
|
||||
kOpusComplexity5));
|
||||
#endif
|
||||
|
||||
// Make sure the runtime is less than 60 seconds to pass Android test.
|
||||
for (size_t audio_length = 0; audio_length < 10000; audio_length += 10) {
|
||||
bool lost_packet = false;
|
||||
|
||||
// Get 10 msec of audio.
|
||||
if (channels == 1) {
|
||||
if (in_file_mono_.EndOfFile()) {
|
||||
break;
|
||||
}
|
||||
in_file_mono_.Read10MsData(audio_frame);
|
||||
} else {
|
||||
if (in_file_stereo_.EndOfFile()) {
|
||||
break;
|
||||
}
|
||||
in_file_stereo_.Read10MsData(audio_frame);
|
||||
}
|
||||
|
||||
// If input audio is sampled at 32 kHz, resampling to 48 kHz is required.
|
||||
EXPECT_EQ(480,
|
||||
resampler_.Resample10Msec(audio_frame.data_,
|
||||
audio_frame.sample_rate_hz_,
|
||||
48000,
|
||||
channels,
|
||||
kBufferSizeSamples - written_samples,
|
||||
&audio[written_samples]));
|
||||
written_samples += 480 * channels;
|
||||
|
||||
// Sometimes we need to loop over the audio vector to produce the right
|
||||
// number of packets.
|
||||
int loop_encode = (written_samples - read_samples) /
|
||||
(channels * frame_length);
|
||||
|
||||
if (loop_encode > 0) {
|
||||
const int kMaxBytes = 1000; // Maximum number of bytes for one packet.
|
||||
size_t bitstream_len_byte;
|
||||
uint8_t bitstream[kMaxBytes];
|
||||
for (int i = 0; i < loop_encode; i++) {
|
||||
int bitstream_len_byte_int = WebRtcOpus_Encode(
|
||||
(channels == 1) ? opus_mono_encoder_ : opus_stereo_encoder_,
|
||||
&audio[read_samples], frame_length, kMaxBytes, bitstream);
|
||||
ASSERT_GE(bitstream_len_byte_int, 0);
|
||||
bitstream_len_byte = static_cast<size_t>(bitstream_len_byte_int);
|
||||
|
||||
// Simulate packet loss by setting |packet_loss_| to "true" in
|
||||
// |percent_loss| percent of the loops.
|
||||
// TODO(tlegrand): Move handling of loss simulation to TestPackStereo.
|
||||
if (percent_loss > 0) {
|
||||
if (counter_ == floor((100 / percent_loss) + 0.5)) {
|
||||
counter_ = 0;
|
||||
lost_packet = true;
|
||||
channel->set_lost_packet(true);
|
||||
} else {
|
||||
lost_packet = false;
|
||||
channel->set_lost_packet(false);
|
||||
}
|
||||
counter_++;
|
||||
}
|
||||
|
||||
// Run stand-alone Opus decoder, or decode PLC.
|
||||
if (channels == 1) {
|
||||
if (!lost_packet) {
|
||||
decoded_samples += WebRtcOpus_Decode(
|
||||
opus_mono_decoder_, bitstream, bitstream_len_byte,
|
||||
&out_audio[decoded_samples * channels], &audio_type);
|
||||
} else {
|
||||
decoded_samples += WebRtcOpus_DecodePlc(
|
||||
opus_mono_decoder_, &out_audio[decoded_samples * channels], 1);
|
||||
}
|
||||
} else {
|
||||
if (!lost_packet) {
|
||||
decoded_samples += WebRtcOpus_Decode(
|
||||
opus_stereo_decoder_, bitstream, bitstream_len_byte,
|
||||
&out_audio[decoded_samples * channels], &audio_type);
|
||||
} else {
|
||||
decoded_samples += WebRtcOpus_DecodePlc(
|
||||
opus_stereo_decoder_, &out_audio[decoded_samples * channels],
|
||||
1);
|
||||
}
|
||||
}
|
||||
|
||||
// Send data to the channel. "channel" will handle the loss simulation.
|
||||
channel->SendData(kAudioFrameSpeech, payload_type_, rtp_timestamp_,
|
||||
bitstream, bitstream_len_byte, NULL);
|
||||
if (first_packet) {
|
||||
first_packet = false;
|
||||
start_time_stamp = rtp_timestamp_;
|
||||
}
|
||||
rtp_timestamp_ += frame_length;
|
||||
read_samples += frame_length * channels;
|
||||
}
|
||||
if (read_samples == written_samples) {
|
||||
read_samples = 0;
|
||||
written_samples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Run received side of ACM.
|
||||
ASSERT_EQ(0, acm_receiver_->PlayoutData10Ms(out_freq_hz_b, &audio_frame));
|
||||
|
||||
// Write output speech to file.
|
||||
out_file_.Write10MsData(
|
||||
audio_frame.data_,
|
||||
audio_frame.samples_per_channel_ * audio_frame.num_channels_);
|
||||
|
||||
// Write stand-alone speech to file.
|
||||
out_file_standalone_.Write10MsData(
|
||||
out_audio, static_cast<size_t>(decoded_samples) * channels);
|
||||
|
||||
if (audio_frame.timestamp_ > start_time_stamp) {
|
||||
// Number of channels should be the same for both stand-alone and
|
||||
// ACM-decoding.
|
||||
EXPECT_EQ(audio_frame.num_channels_, channels);
|
||||
}
|
||||
|
||||
decoded_samples = 0;
|
||||
}
|
||||
|
||||
if (in_file_mono_.EndOfFile()) {
|
||||
in_file_mono_.Rewind();
|
||||
}
|
||||
if (in_file_stereo_.EndOfFile()) {
|
||||
in_file_stereo_.Rewind();
|
||||
}
|
||||
// Reset in case we ended with a lost packet.
|
||||
channel->set_lost_packet(false);
|
||||
}
|
||||
|
||||
void OpusTest::OpenOutFile(int test_number) {
|
||||
std::string file_name;
|
||||
std::stringstream file_stream;
|
||||
file_stream << webrtc::test::OutputPath() << "opustest_out_"
|
||||
<< test_number << ".pcm";
|
||||
file_name = file_stream.str();
|
||||
out_file_.Open(file_name, 48000, "wb");
|
||||
file_stream.str("");
|
||||
file_name = file_stream.str();
|
||||
file_stream << webrtc::test::OutputPath() << "opusstandalone_out_"
|
||||
<< test_number << ".pcm";
|
||||
file_name = file_stream.str();
|
||||
out_file_standalone_.Open(file_name, 48000, "wb");
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
57
webrtc/modules/audio_coding/test/opus_test.h
Normal file
57
webrtc/modules/audio_coding/test/opus_test.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/acm_resampler.h"
|
||||
#include "webrtc/modules/audio_coding/test/ACMTest.h"
|
||||
#include "webrtc/modules/audio_coding/test/Channel.h"
|
||||
#include "webrtc/modules/audio_coding/test/PCMFile.h"
|
||||
#include "webrtc/modules/audio_coding/test/TestStereo.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class OpusTest : public ACMTest {
|
||||
public:
|
||||
OpusTest();
|
||||
~OpusTest();
|
||||
|
||||
void Perform();
|
||||
|
||||
private:
|
||||
void Run(TestPackStereo* channel, int channels, int bitrate, int frame_length,
|
||||
int percent_loss = 0);
|
||||
|
||||
void OpenOutFile(int test_number);
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_receiver_;
|
||||
TestPackStereo* channel_a2b_;
|
||||
PCMFile in_file_stereo_;
|
||||
PCMFile in_file_mono_;
|
||||
PCMFile out_file_;
|
||||
PCMFile out_file_standalone_;
|
||||
int counter_;
|
||||
uint8_t payload_type_;
|
||||
int rtp_timestamp_;
|
||||
acm2::ACMResampler resampler_;
|
||||
WebRtcOpusEncInst* opus_mono_encoder_;
|
||||
WebRtcOpusEncInst* opus_stereo_encoder_;
|
||||
WebRtcOpusDecInst* opus_mono_decoder_;
|
||||
WebRtcOpusDecInst* opus_stereo_decoder_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
|
||||
223
webrtc/modules/audio_coding/test/target_delay_unittest.cc
Normal file
223
webrtc/modules/audio_coding/test/target_delay_unittest.cc
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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 "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/test/utility.h"
|
||||
#include "webrtc/modules/include/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/include/sleep.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
#include "webrtc/test/testsupport/gtest_disable.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class TargetDelayTest : public ::testing::Test {
|
||||
protected:
|
||||
TargetDelayTest() : acm_(AudioCodingModule::Create(0)) {}
|
||||
|
||||
~TargetDelayTest() {}
|
||||
|
||||
void SetUp() {
|
||||
EXPECT_TRUE(acm_.get() != NULL);
|
||||
|
||||
CodecInst codec;
|
||||
ASSERT_EQ(0, AudioCodingModule::Codec("L16", &codec, kSampleRateHz, 1));
|
||||
ASSERT_EQ(0, acm_->InitializeReceiver());
|
||||
ASSERT_EQ(0, acm_->RegisterReceiveCodec(codec));
|
||||
|
||||
rtp_info_.header.payloadType = codec.pltype;
|
||||
rtp_info_.header.timestamp = 0;
|
||||
rtp_info_.header.ssrc = 0x12345678;
|
||||
rtp_info_.header.markerBit = false;
|
||||
rtp_info_.header.sequenceNumber = 0;
|
||||
rtp_info_.type.Audio.channel = 1;
|
||||
rtp_info_.type.Audio.isCNG = false;
|
||||
rtp_info_.frameType = kAudioFrameSpeech;
|
||||
|
||||
int16_t audio[kFrameSizeSamples];
|
||||
const int kRange = 0x7FF; // 2047, easy for masking.
|
||||
for (size_t n = 0; n < kFrameSizeSamples; ++n)
|
||||
audio[n] = (rand() & kRange) - kRange / 2;
|
||||
WebRtcPcm16b_Encode(audio, kFrameSizeSamples, payload_);
|
||||
}
|
||||
|
||||
void OutOfRangeInput() {
|
||||
EXPECT_EQ(-1, SetMinimumDelay(-1));
|
||||
EXPECT_EQ(-1, SetMinimumDelay(10001));
|
||||
}
|
||||
|
||||
void NoTargetDelayBufferSizeChanges() {
|
||||
for (int n = 0; n < 30; ++n) // Run enough iterations.
|
||||
Run(true);
|
||||
int clean_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
Run(false); // Run with jitter.
|
||||
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_GT(jittery_optimal_delay, clean_optimal_delay);
|
||||
int required_delay = RequiredDelay();
|
||||
EXPECT_GT(required_delay, 0);
|
||||
EXPECT_NEAR(required_delay, jittery_optimal_delay, 1);
|
||||
}
|
||||
|
||||
void WithTargetDelayBufferNotChanging() {
|
||||
// A target delay that is one packet larger than jitter.
|
||||
const int kTargetDelayMs = (kInterarrivalJitterPacket + 1) *
|
||||
kNum10msPerFrame * 10;
|
||||
ASSERT_EQ(0, SetMinimumDelay(kTargetDelayMs));
|
||||
for (int n = 0; n < 30; ++n) // Run enough iterations to fill the buffer.
|
||||
Run(true);
|
||||
int clean_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_EQ(kTargetDelayMs, clean_optimal_delay);
|
||||
Run(false); // Run with jitter.
|
||||
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_EQ(jittery_optimal_delay, clean_optimal_delay);
|
||||
}
|
||||
|
||||
void RequiredDelayAtCorrectRange() {
|
||||
for (int n = 0; n < 30; ++n) // Run clean and store delay.
|
||||
Run(true);
|
||||
int clean_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
|
||||
// A relatively large delay.
|
||||
const int kTargetDelayMs = (kInterarrivalJitterPacket + 10) *
|
||||
kNum10msPerFrame * 10;
|
||||
ASSERT_EQ(0, SetMinimumDelay(kTargetDelayMs));
|
||||
for (int n = 0; n < 300; ++n) // Run enough iterations to fill the buffer.
|
||||
Run(true);
|
||||
Run(false); // Run with jitter.
|
||||
|
||||
int jittery_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_EQ(kTargetDelayMs, jittery_optimal_delay);
|
||||
|
||||
int required_delay = RequiredDelay();
|
||||
|
||||
// Checking |required_delay| is in correct range.
|
||||
EXPECT_GT(required_delay, 0);
|
||||
EXPECT_GT(jittery_optimal_delay, required_delay);
|
||||
EXPECT_GT(required_delay, clean_optimal_delay);
|
||||
|
||||
// A tighter check for the value of |required_delay|.
|
||||
// The jitter forces a delay of
|
||||
// |kInterarrivalJitterPacket * kNum10msPerFrame * 10| milliseconds. So we
|
||||
// expect |required_delay| be close to that.
|
||||
EXPECT_NEAR(kInterarrivalJitterPacket * kNum10msPerFrame * 10,
|
||||
required_delay, 1);
|
||||
}
|
||||
|
||||
void TargetDelayBufferMinMax() {
|
||||
const int kTargetMinDelayMs = kNum10msPerFrame * 10;
|
||||
ASSERT_EQ(0, SetMinimumDelay(kTargetMinDelayMs));
|
||||
for (int m = 0; m < 30; ++m) // Run enough iterations to fill the buffer.
|
||||
Run(true);
|
||||
int clean_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_EQ(kTargetMinDelayMs, clean_optimal_delay);
|
||||
|
||||
const int kTargetMaxDelayMs = 2 * (kNum10msPerFrame * 10);
|
||||
ASSERT_EQ(0, SetMaximumDelay(kTargetMaxDelayMs));
|
||||
for (int n = 0; n < 30; ++n) // Run enough iterations to fill the buffer.
|
||||
Run(false);
|
||||
|
||||
int capped_optimal_delay = GetCurrentOptimalDelayMs();
|
||||
EXPECT_EQ(kTargetMaxDelayMs, capped_optimal_delay);
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kSampleRateHz = 16000;
|
||||
static const int kNum10msPerFrame = 2;
|
||||
static const size_t kFrameSizeSamples = 320; // 20 ms @ 16 kHz.
|
||||
// payload-len = frame-samples * 2 bytes/sample.
|
||||
static const int kPayloadLenBytes = 320 * 2;
|
||||
// Inter-arrival time in number of packets in a jittery channel. One is no
|
||||
// jitter.
|
||||
static const int kInterarrivalJitterPacket = 2;
|
||||
|
||||
void Push() {
|
||||
rtp_info_.header.timestamp += kFrameSizeSamples;
|
||||
rtp_info_.header.sequenceNumber++;
|
||||
ASSERT_EQ(0, acm_->IncomingPacket(payload_, kFrameSizeSamples * 2,
|
||||
rtp_info_));
|
||||
}
|
||||
|
||||
// Pull audio equivalent to the amount of audio in one RTP packet.
|
||||
void Pull() {
|
||||
AudioFrame frame;
|
||||
for (int k = 0; k < kNum10msPerFrame; ++k) { // Pull one frame.
|
||||
ASSERT_EQ(0, acm_->PlayoutData10Ms(-1, &frame));
|
||||
// Had to use ASSERT_TRUE, ASSERT_EQ generated error.
|
||||
ASSERT_TRUE(kSampleRateHz == frame.sample_rate_hz_);
|
||||
ASSERT_EQ(1, frame.num_channels_);
|
||||
ASSERT_TRUE(kSampleRateHz / 100 == frame.samples_per_channel_);
|
||||
}
|
||||
}
|
||||
|
||||
void Run(bool clean) {
|
||||
for (int n = 0; n < 10; ++n) {
|
||||
for (int m = 0; m < 5; ++m) {
|
||||
Push();
|
||||
Pull();
|
||||
}
|
||||
|
||||
if (!clean) {
|
||||
for (int m = 0; m < 10; ++m) { // Long enough to trigger delay change.
|
||||
Push();
|
||||
for (int n = 0; n < kInterarrivalJitterPacket; ++n)
|
||||
Pull();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SetMinimumDelay(int delay_ms) {
|
||||
return acm_->SetMinimumPlayoutDelay(delay_ms);
|
||||
}
|
||||
|
||||
int SetMaximumDelay(int delay_ms) {
|
||||
return acm_->SetMaximumPlayoutDelay(delay_ms);
|
||||
}
|
||||
|
||||
int GetCurrentOptimalDelayMs() {
|
||||
NetworkStatistics stats;
|
||||
acm_->GetNetworkStatistics(&stats);
|
||||
return stats.preferredBufferSize;
|
||||
}
|
||||
|
||||
int RequiredDelay() {
|
||||
return acm_->LeastRequiredDelayMs();
|
||||
}
|
||||
|
||||
rtc::scoped_ptr<AudioCodingModule> acm_;
|
||||
WebRtcRTPHeader rtp_info_;
|
||||
uint8_t payload_[kPayloadLenBytes];
|
||||
};
|
||||
|
||||
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(OutOfRangeInput)) {
|
||||
OutOfRangeInput();
|
||||
}
|
||||
|
||||
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(NoTargetDelayBufferSizeChanges)) {
|
||||
NoTargetDelayBufferSizeChanges();
|
||||
}
|
||||
|
||||
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(WithTargetDelayBufferNotChanging)) {
|
||||
WithTargetDelayBufferNotChanging();
|
||||
}
|
||||
|
||||
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(RequiredDelayAtCorrectRange)) {
|
||||
RequiredDelayAtCorrectRange();
|
||||
}
|
||||
|
||||
TEST_F(TargetDelayTest, DISABLED_ON_ANDROID(TargetDelayBufferMinMax)) {
|
||||
TargetDelayBufferMinMax();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
303
webrtc/modules/audio_coding/test/utility.cc
Normal file
303
webrtc/modules/audio_coding/test/utility.cc
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* 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 "utility.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/common.h"
|
||||
#include "webrtc/common_types.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
#include "webrtc/modules/audio_coding/acm2/acm_common_defs.h"
|
||||
|
||||
#define NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE 13
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
ACMTestTimer::ACMTestTimer()
|
||||
: _msec(0),
|
||||
_sec(0),
|
||||
_min(0),
|
||||
_hour(0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ACMTestTimer::~ACMTestTimer() {
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::Reset() {
|
||||
_msec = 0;
|
||||
_sec = 0;
|
||||
_min = 0;
|
||||
_hour = 0;
|
||||
return;
|
||||
}
|
||||
void ACMTestTimer::Tick10ms() {
|
||||
_msec += 10;
|
||||
Adjust();
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::Tick1ms() {
|
||||
_msec++;
|
||||
Adjust();
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::Tick100ms() {
|
||||
_msec += 100;
|
||||
Adjust();
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::Tick1sec() {
|
||||
_sec++;
|
||||
Adjust();
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::CurrentTimeHMS(char* currTime) {
|
||||
sprintf(currTime, "%4lu:%02u:%06.3f", _hour, _min,
|
||||
(double) _sec + (double) _msec / 1000.);
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::CurrentTime(unsigned long& h, unsigned char& m,
|
||||
unsigned char& s, unsigned short& ms) {
|
||||
h = _hour;
|
||||
m = _min;
|
||||
s = _sec;
|
||||
ms = _msec;
|
||||
return;
|
||||
}
|
||||
|
||||
void ACMTestTimer::Adjust() {
|
||||
unsigned int n;
|
||||
if (_msec >= 1000) {
|
||||
n = _msec / 1000;
|
||||
_msec -= (1000 * n);
|
||||
_sec += n;
|
||||
}
|
||||
if (_sec >= 60) {
|
||||
n = _sec / 60;
|
||||
_sec -= (n * 60);
|
||||
_min += n;
|
||||
}
|
||||
if (_min >= 60) {
|
||||
n = _min / 60;
|
||||
_min -= (n * 60);
|
||||
_hour += n;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t ChooseCodec(CodecInst& codecInst) {
|
||||
|
||||
PrintCodecs();
|
||||
//AudioCodingModule* tmpACM = AudioCodingModule::Create(0);
|
||||
uint8_t noCodec = AudioCodingModule::NumberOfCodecs();
|
||||
int8_t codecID;
|
||||
bool outOfRange = false;
|
||||
char myStr[15] = "";
|
||||
do {
|
||||
printf("\nChoose a codec [0]: ");
|
||||
EXPECT_TRUE(fgets(myStr, 10, stdin) != NULL);
|
||||
codecID = atoi(myStr);
|
||||
if ((codecID < 0) || (codecID >= noCodec)) {
|
||||
printf("\nOut of range.\n");
|
||||
outOfRange = true;
|
||||
}
|
||||
} while (outOfRange);
|
||||
|
||||
CHECK_ERROR(AudioCodingModule::Codec((uint8_t )codecID, &codecInst));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PrintCodecs() {
|
||||
uint8_t noCodec = AudioCodingModule::NumberOfCodecs();
|
||||
|
||||
CodecInst codecInst;
|
||||
printf("No Name [Hz] [bps]\n");
|
||||
for (uint8_t codecCntr = 0; codecCntr < noCodec; codecCntr++) {
|
||||
AudioCodingModule::Codec(codecCntr, &codecInst);
|
||||
printf("%2d- %-18s %5d %6d\n", codecCntr, codecInst.plname,
|
||||
codecInst.plfreq, codecInst.rate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CircularBuffer::CircularBuffer(uint32_t len)
|
||||
: _buff(NULL),
|
||||
_idx(0),
|
||||
_buffIsFull(false),
|
||||
_calcAvg(false),
|
||||
_calcVar(false),
|
||||
_sum(0),
|
||||
_sumSqr(0) {
|
||||
_buff = new double[len];
|
||||
if (_buff == NULL) {
|
||||
_buffLen = 0;
|
||||
} else {
|
||||
for (uint32_t n = 0; n < len; n++) {
|
||||
_buff[n] = 0;
|
||||
}
|
||||
_buffLen = len;
|
||||
}
|
||||
}
|
||||
|
||||
CircularBuffer::~CircularBuffer() {
|
||||
if (_buff != NULL) {
|
||||
delete[] _buff;
|
||||
_buff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CircularBuffer::Update(const double newVal) {
|
||||
assert(_buffLen > 0);
|
||||
|
||||
// store the value that is going to be overwritten
|
||||
double oldVal = _buff[_idx];
|
||||
// record the new value
|
||||
_buff[_idx] = newVal;
|
||||
// increment the index, to point to where we would
|
||||
// write next
|
||||
_idx++;
|
||||
// it is a circular buffer, if we are at the end
|
||||
// we have to cycle to the beginning
|
||||
if (_idx >= _buffLen) {
|
||||
// flag that the buffer is filled up.
|
||||
_buffIsFull = true;
|
||||
_idx = 0;
|
||||
}
|
||||
|
||||
// Update
|
||||
|
||||
if (_calcAvg) {
|
||||
// for the average we have to update
|
||||
// the sum
|
||||
_sum += (newVal - oldVal);
|
||||
}
|
||||
|
||||
if (_calcVar) {
|
||||
// to calculate variance we have to update
|
||||
// the sum of squares
|
||||
_sumSqr += (double) (newVal - oldVal) * (double) (newVal + oldVal);
|
||||
}
|
||||
}
|
||||
|
||||
void CircularBuffer::SetArithMean(bool enable) {
|
||||
assert(_buffLen > 0);
|
||||
|
||||
if (enable && !_calcAvg) {
|
||||
uint32_t lim;
|
||||
if (_buffIsFull) {
|
||||
lim = _buffLen;
|
||||
} else {
|
||||
lim = _idx;
|
||||
}
|
||||
_sum = 0;
|
||||
for (uint32_t n = 0; n < lim; n++) {
|
||||
_sum += _buff[n];
|
||||
}
|
||||
}
|
||||
_calcAvg = enable;
|
||||
}
|
||||
|
||||
void CircularBuffer::SetVariance(bool enable) {
|
||||
assert(_buffLen > 0);
|
||||
|
||||
if (enable && !_calcVar) {
|
||||
uint32_t lim;
|
||||
if (_buffIsFull) {
|
||||
lim = _buffLen;
|
||||
} else {
|
||||
lim = _idx;
|
||||
}
|
||||
_sumSqr = 0;
|
||||
for (uint32_t n = 0; n < lim; n++) {
|
||||
_sumSqr += _buff[n] * _buff[n];
|
||||
}
|
||||
}
|
||||
_calcAvg = enable;
|
||||
}
|
||||
|
||||
int16_t CircularBuffer::ArithMean(double& mean) {
|
||||
assert(_buffLen > 0);
|
||||
|
||||
if (_buffIsFull) {
|
||||
|
||||
mean = _sum / (double) _buffLen;
|
||||
return 0;
|
||||
} else {
|
||||
if (_idx > 0) {
|
||||
mean = _sum / (double) _idx;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CircularBuffer::Variance(double& var) {
|
||||
assert(_buffLen > 0);
|
||||
|
||||
if (_buffIsFull) {
|
||||
var = _sumSqr / (double) _buffLen;
|
||||
return 0;
|
||||
} else {
|
||||
if (_idx > 0) {
|
||||
var = _sumSqr / (double) _idx;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FixedPayloadTypeCodec(const char* payloadName) {
|
||||
char fixPayloadTypeCodecs[NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE][32] = { "PCMU",
|
||||
"PCMA", "GSM", "G723", "DVI4", "LPC", "PCMA", "G722", "QCELP", "CN",
|
||||
"MPA", "G728", "G729" };
|
||||
|
||||
for (int n = 0; n < NUM_CODECS_WITH_FIXED_PAYLOAD_TYPE; n++) {
|
||||
if (!STR_CASE_CMP(payloadName, fixPayloadTypeCodecs[n])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VADCallback::Reset() {
|
||||
memset(_numFrameTypes, 0, sizeof(_numFrameTypes));
|
||||
}
|
||||
|
||||
VADCallback::VADCallback() {
|
||||
memset(_numFrameTypes, 0, sizeof(_numFrameTypes));
|
||||
}
|
||||
|
||||
void VADCallback::PrintFrameTypes() {
|
||||
printf("kEmptyFrame......... %d\n", _numFrameTypes[kEmptyFrame]);
|
||||
printf("kAudioFrameSpeech... %d\n", _numFrameTypes[kAudioFrameSpeech]);
|
||||
printf("kAudioFrameCN....... %d\n", _numFrameTypes[kAudioFrameCN]);
|
||||
printf("kVideoFrameKey...... %d\n", _numFrameTypes[kVideoFrameKey]);
|
||||
printf("kVideoFrameDelta.... %d\n", _numFrameTypes[kVideoFrameDelta]);
|
||||
}
|
||||
|
||||
int32_t VADCallback::InFrameType(FrameType frame_type) {
|
||||
_numFrameTypes[frame_type]++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
139
webrtc/modules/audio_coding/test/utility.h
Normal file
139
webrtc/modules/audio_coding/test/utility.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
//-----------------------------
|
||||
#define CHECK_ERROR(f) \
|
||||
do { \
|
||||
EXPECT_GE(f, 0) << "Error Calling API"; \
|
||||
} while(0)
|
||||
|
||||
//-----------------------------
|
||||
#define CHECK_PROTECTED(f) \
|
||||
do { \
|
||||
if (f >= 0) { \
|
||||
ADD_FAILURE() << "Error Calling API"; \
|
||||
} else { \
|
||||
printf("An expected error is caught.\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
//----------------------------
|
||||
#define CHECK_ERROR_MT(f) \
|
||||
do { \
|
||||
if (f < 0) { \
|
||||
fprintf(stderr, "Error Calling API in file %s at line %d \n", \
|
||||
__FILE__, __LINE__); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
//----------------------------
|
||||
#define CHECK_PROTECTED_MT(f) \
|
||||
do { \
|
||||
if (f >= 0) { \
|
||||
fprintf(stderr, "Error Calling API in file %s at line %d \n", \
|
||||
__FILE__, __LINE__); \
|
||||
} else { \
|
||||
printf("An expected error is caught.\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define DELETE_POINTER(p) \
|
||||
do { \
|
||||
if (p != NULL) { \
|
||||
delete p; \
|
||||
p = NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
class ACMTestTimer {
|
||||
public:
|
||||
ACMTestTimer();
|
||||
~ACMTestTimer();
|
||||
|
||||
void Reset();
|
||||
void Tick10ms();
|
||||
void Tick1ms();
|
||||
void Tick100ms();
|
||||
void Tick1sec();
|
||||
void CurrentTimeHMS(char* currTime);
|
||||
void CurrentTime(unsigned long& h, unsigned char& m, unsigned char& s,
|
||||
unsigned short& ms);
|
||||
|
||||
private:
|
||||
void Adjust();
|
||||
|
||||
unsigned short _msec;
|
||||
unsigned char _sec;
|
||||
unsigned char _min;
|
||||
unsigned long _hour;
|
||||
};
|
||||
|
||||
class CircularBuffer {
|
||||
public:
|
||||
CircularBuffer(uint32_t len);
|
||||
~CircularBuffer();
|
||||
|
||||
void SetArithMean(bool enable);
|
||||
void SetVariance(bool enable);
|
||||
|
||||
void Update(const double newVal);
|
||||
void IsBufferFull();
|
||||
|
||||
int16_t Variance(double& var);
|
||||
int16_t ArithMean(double& mean);
|
||||
|
||||
protected:
|
||||
double* _buff;
|
||||
uint32_t _idx;
|
||||
uint32_t _buffLen;
|
||||
|
||||
bool _buffIsFull;
|
||||
bool _calcAvg;
|
||||
bool _calcVar;
|
||||
double _sum;
|
||||
double _sumSqr;
|
||||
};
|
||||
|
||||
int16_t ChooseCodec(CodecInst& codecInst);
|
||||
|
||||
void PrintCodecs();
|
||||
|
||||
bool FixedPayloadTypeCodec(const char* payloadName);
|
||||
|
||||
class VADCallback : public ACMVADCallback {
|
||||
public:
|
||||
VADCallback();
|
||||
~VADCallback() {
|
||||
}
|
||||
|
||||
int32_t InFrameType(FrameType frame_type);
|
||||
|
||||
void PrintFrameTypes();
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
uint32_t _numFrameTypes[5];
|
||||
};
|
||||
|
||||
void UseLegacyAcm(webrtc::Config* config);
|
||||
|
||||
void UseNewAcm(webrtc::Config* config);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_TEST_UTILITY_H_
|
||||
Reference in New Issue
Block a user