Adding regression test to NetEQ
The test inputs RTP packets from an RTPdump file into NetEQ and compares the output to the corresponding reference file. Test files are included. The change also includes a new method in NETEQTEST_RTPpacket class, which reads past the initial file header in an RTPdump file. Finally, a few warnings are removed. Review URL: http://webrtc-codereview.appspot.com/138012 git-svn-id: http://webrtc.googlecode.com/svn/trunk@568 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
c273019768
commit
35dcc23110
152
src/modules/audio_coding/NetEQ/main/source/neteq_api_unittest.cc
Normal file
152
src/modules/audio_coding/NetEQ/main/source/neteq_api_unittest.cc
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file includes unit tests for NetEQ.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // memset
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "modules/audio_coding/NetEQ/main/test/NETEQTEST_CodecClass.h"
|
||||
#include "modules/audio_coding/NetEQ/main/test/NETEQTEST_NetEQClass.h"
|
||||
#include "modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.h"
|
||||
#include "typedefs.h" // NOLINT(build/include)
|
||||
#include "modules/audio_coding/NetEQ/main/interface/webrtc_neteq.h"
|
||||
#include "modules/audio_coding/NetEQ/main/interface/webrtc_neteq_help_macros.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class NetEqDecodingTest : public ::testing::Test {
|
||||
protected:
|
||||
NetEqDecodingTest();
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
void SelectDecoders(WebRtcNetEQDecoder* used_codec);
|
||||
void LoadDecoders();
|
||||
void DecodeAndCompare(const char* rtp_file, const char* ref_file);
|
||||
|
||||
NETEQTEST_NetEQClass* neteq_inst_;
|
||||
std::vector<NETEQTEST_Decoder*> dec_;
|
||||
};
|
||||
|
||||
NetEqDecodingTest::NetEqDecodingTest() : neteq_inst_(NULL) {}
|
||||
|
||||
void NetEqDecodingTest::SetUp() {
|
||||
WebRtcNetEQDecoder usedCodec[kDecoderReservedEnd - 1];
|
||||
|
||||
SelectDecoders(usedCodec);
|
||||
neteq_inst_ = new NETEQTEST_NetEQClass(usedCodec, dec_.size(), 8000,
|
||||
kTCPLargeJitter);
|
||||
ASSERT_TRUE(neteq_inst_);
|
||||
LoadDecoders();
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::TearDown() {
|
||||
if (neteq_inst_)
|
||||
delete neteq_inst_;
|
||||
for (size_t i = 0; i < dec_.size(); ++i) {
|
||||
if (dec_[i])
|
||||
delete dec_[i];
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::SelectDecoders(WebRtcNetEQDecoder* used_codec) {
|
||||
*used_codec++ = kDecoderPCMu;
|
||||
dec_.push_back(new decoder_PCMU(0));
|
||||
*used_codec++ = kDecoderPCMa;
|
||||
dec_.push_back(new decoder_PCMA(8));
|
||||
*used_codec++ = kDecoderILBC;
|
||||
dec_.push_back(new decoder_ILBC(102));
|
||||
*used_codec++ = kDecoderISAC;
|
||||
dec_.push_back(new decoder_iSAC(103));
|
||||
*used_codec++ = kDecoderISACswb;
|
||||
dec_.push_back(new decoder_iSACSWB(104));
|
||||
*used_codec++ = kDecoderPCM16B;
|
||||
dec_.push_back(new decoder_PCM16B_NB(93));
|
||||
*used_codec++ = kDecoderPCM16Bwb;
|
||||
dec_.push_back(new decoder_PCM16B_WB(94));
|
||||
*used_codec++ = kDecoderPCM16Bswb32kHz;
|
||||
dec_.push_back(new decoder_PCM16B_SWB32(95));
|
||||
*used_codec++ = kDecoderCNG;
|
||||
dec_.push_back(new decoder_CNG(13));
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::LoadDecoders() {
|
||||
for (size_t i = 0; i < dec_.size(); ++i) {
|
||||
ASSERT_EQ(0, dec_[i]->loadToNetEQ(*neteq_inst_));
|
||||
}
|
||||
}
|
||||
|
||||
void NetEqDecodingTest::DecodeAndCompare(const char* rtp_file,
|
||||
const char* ref_file) {
|
||||
NETEQTEST_RTPpacket rtp;
|
||||
FILE* rtp_fp = fopen(rtp_file, "rb");
|
||||
ASSERT_TRUE(rtp_fp != NULL);
|
||||
ASSERT_EQ(0, NETEQTEST_RTPpacket::skipFileHeader(rtp_fp));
|
||||
ASSERT_GT(rtp.readFromFile(rtp_fp), 0);
|
||||
|
||||
FILE* ref_fp = fopen(ref_file, "rb");
|
||||
ASSERT_TRUE(ref_fp != NULL);
|
||||
|
||||
unsigned int sim_clock = 0;
|
||||
const int kTimeStep = 10;
|
||||
while (rtp.dataLen() >= 0) {
|
||||
// Check if time to receive.
|
||||
while ((sim_clock >= rtp.time()) &&
|
||||
(rtp.dataLen() >= 0)) {
|
||||
if (rtp.dataLen() > 0) {
|
||||
ASSERT_EQ(0, neteq_inst_->recIn(rtp));
|
||||
}
|
||||
// Get next packet.
|
||||
ASSERT_NE(-1, rtp.readFromFile(rtp_fp));
|
||||
}
|
||||
|
||||
// RecOut
|
||||
WebRtc_Word16 out_data[10 * 32]; // 10 ms at 32 kHz
|
||||
WebRtc_Word16 out_len = neteq_inst_->recOut(out_data);
|
||||
ASSERT_TRUE((out_len == 80) || (out_len == 160) || (out_len == 320));
|
||||
|
||||
// Read from ref file
|
||||
WebRtc_Word16 ref_data[10 * 32]; // 10 ms at 32 kHz
|
||||
if (static_cast<size_t>(out_len) !=
|
||||
fread(ref_data, sizeof(WebRtc_Word16), out_len, ref_fp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Compare
|
||||
EXPECT_EQ(0, memcmp(out_data, ref_data, sizeof(WebRtc_Word16) * out_len));
|
||||
|
||||
// Increase time
|
||||
sim_clock += kTimeStep;
|
||||
}
|
||||
ASSERT_NE(0, feof(ref_fp)); // Make sure that we reached the end.
|
||||
fclose(rtp_fp);
|
||||
fclose(ref_fp);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTest, TestBitExactness) {
|
||||
DecodeAndCompare("test/data/audio_coding/universal.rtp",
|
||||
"test/data/audio_coding/universal_ref.pcm");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
33
src/modules/audio_coding/NetEQ/main/source/neteq_tests.gyp
Normal file
33
src/modules/audio_coding/NetEQ/main/source/neteq_tests.gyp
Normal file
@ -0,0 +1,33 @@
|
||||
# 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.
|
||||
|
||||
{
|
||||
'includes': [
|
||||
'../../../../../common_settings.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'neteq_unittest',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'neteq.gyp:NetEq',
|
||||
'neteq.gyp:NetEqTestTools',
|
||||
'../../../../../../testing/gtest.gyp:gtest',
|
||||
],
|
||||
'sources': [
|
||||
'neteq_api_unittest.cc',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:2
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
@ -210,7 +210,7 @@ void NETEQTEST_NetEQClass::printError(NETEQTEST_RTPpacket &rtp)
|
||||
printError();
|
||||
|
||||
// print extra info from packet
|
||||
printf("\tRTP: TS=%lu, SN=%u, PT=%u, M=%i, len=%i\n",
|
||||
printf("\tRTP: TS=%u, SN=%u, PT=%u, M=%i, len=%i\n",
|
||||
rtp.timeStamp(), rtp.sequenceNumber(), rtp.payloadType(),
|
||||
rtp.markerBit(), rtp.payloadLen());
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "NETEQTEST_RTPpacket.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WIN32
|
||||
@ -72,7 +73,7 @@ NETEQTEST_RTPpacket & NETEQTEST_RTPpacket::operator = (const NETEQTEST_RTPpacket
|
||||
// deallocate datagram memory if allocated
|
||||
if(_datagram)
|
||||
{
|
||||
delete[] _datagram;
|
||||
delete [] _datagram;
|
||||
}
|
||||
|
||||
// do shallow copy
|
||||
@ -113,7 +114,7 @@ NETEQTEST_RTPpacket::~NETEQTEST_RTPpacket()
|
||||
{
|
||||
if(_datagram)
|
||||
{
|
||||
delete _datagram;
|
||||
delete [] _datagram;
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +122,7 @@ NETEQTEST_RTPpacket::~NETEQTEST_RTPpacket()
|
||||
void NETEQTEST_RTPpacket::reset()
|
||||
{
|
||||
if(_datagram) {
|
||||
delete _datagram;
|
||||
delete [] _datagram;
|
||||
}
|
||||
_datagram = NULL;
|
||||
_memSize = 0;
|
||||
@ -134,6 +135,37 @@ void NETEQTEST_RTPpacket::reset()
|
||||
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::skipFileHeader(FILE *fp)
|
||||
{
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int kFirstLineLength = 40;
|
||||
char firstline[kFirstLineLength];
|
||||
fgets(firstline, kFirstLineLength, fp);
|
||||
if (strncmp(firstline, "#!rtpplay", 9) == 0) {
|
||||
if (strncmp(firstline, "#!rtpplay1.0", 12) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strncmp(firstline, "#!RTPencode", 11) == 0) {
|
||||
if (strncmp(firstline, "#!RTPencode1.0", 14) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2;
|
||||
if (fseek(fp, kRtpDumpHeaderSize, SEEK_CUR) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NETEQTEST_RTPpacket::readFromFile(FILE *fp)
|
||||
{
|
||||
@ -201,15 +233,15 @@ int NETEQTEST_RTPpacket::readFromFile(FILE *fp)
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, int length)
|
||||
int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, size_t length)
|
||||
{
|
||||
if(!fp)
|
||||
if (!fp)
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check buffer size
|
||||
if (_datagram && _memSize < length)
|
||||
if (_datagram && _memSize < static_cast<int>(length))
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@ -220,10 +252,10 @@ int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, int length)
|
||||
_memSize = length;
|
||||
}
|
||||
|
||||
if (fread((unsigned short *) _datagram,1,length,fp) != length)
|
||||
if (fread(_datagram, 1, length, fp) != length)
|
||||
{
|
||||
reset();
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_datagramLen = length;
|
||||
@ -232,53 +264,54 @@ int NETEQTEST_RTPpacket::readFixedFromFile(FILE *fp, int length)
|
||||
if (!_blockList.empty() && _blockList.count(payloadType()) > 0)
|
||||
{
|
||||
// discard this payload
|
||||
return(readFromFile(fp));
|
||||
return readFromFile(fp);
|
||||
}
|
||||
|
||||
return(length);
|
||||
return length;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int NETEQTEST_RTPpacket::writeToFile(FILE *fp)
|
||||
{
|
||||
if(!fp)
|
||||
if (!fp)
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_UWord16 length, plen;
|
||||
WebRtc_UWord16 length, plen;
|
||||
WebRtc_UWord32 offset;
|
||||
|
||||
// length including RTPplay header
|
||||
length = htons(_datagramLen + HDR_SIZE);
|
||||
if (fwrite(&length, 2, 1, fp) != 1)
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// payload length
|
||||
plen = htons(_datagramLen);
|
||||
if (fwrite(&plen, 2, 1, fp) != 1)
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// offset (=receive time)
|
||||
offset = htonl(_receiveTime);
|
||||
if (fwrite(&offset, 4, 1, fp) != 1)
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// write packet data
|
||||
if (fwrite((unsigned short *) _datagram, 1, _datagramLen, fp) != _datagramLen)
|
||||
if (fwrite(_datagram, 1, _datagramLen, fp) !=
|
||||
static_cast<size_t>(_datagramLen))
|
||||
{
|
||||
return(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return(_datagramLen + HDR_SIZE); // total number of bytes written
|
||||
return _datagramLen + HDR_SIZE; // total number of bytes written
|
||||
|
||||
}
|
||||
|
||||
@ -634,6 +667,11 @@ int NETEQTEST_RTPpacket::splitStereo(NETEQTEST_RTPpacket& slaveRtp, enum stereoM
|
||||
splitStereoFrame(slaveRtp);
|
||||
break;
|
||||
}
|
||||
case stereoModeMono:
|
||||
{
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -32,8 +32,9 @@ public:
|
||||
bool operator !() const { return (dataLen() < 0); };
|
||||
~NETEQTEST_RTPpacket();
|
||||
void reset();
|
||||
static int skipFileHeader(FILE *fp);
|
||||
int readFromFile(FILE *fp);
|
||||
int readFixedFromFile(FILE *fp, int len);
|
||||
int readFixedFromFile(FILE *fp, size_t len);
|
||||
int writeToFile(FILE *fp);
|
||||
void blockPT(WebRtc_UWord8 pt);
|
||||
//WebRtc_Word16 payloadType();
|
||||
|
@ -150,7 +150,6 @@ int main(int argc, char* argv[])
|
||||
std::vector<NETEQTEST_NetEQClass *> NetEQvector;
|
||||
NETEQTEST_RTPpacket rtp;
|
||||
char version[20];
|
||||
char firstline[FIRSTLINELEN];
|
||||
|
||||
NETEQTEST_RTPpacket slaveRtp;
|
||||
//bool switchMS = false;
|
||||
@ -359,40 +358,11 @@ int main(int argc, char* argv[])
|
||||
/* read RTP file header */
|
||||
if (!rtpOnly)
|
||||
{
|
||||
fgets(firstline, FIRSTLINELEN, in_file);
|
||||
if(strncmp(firstline,"#!rtpplay",9) == 0) {
|
||||
if(strncmp(firstline,"#!rtpplay1.0",12) != 0){
|
||||
printf("ERROR: wrong rtpplay version, must be 1.0\n");
|
||||
exit(0);
|
||||
}
|
||||
if (NETEQTEST_RTPpacket::skipFileHeader(in_file) != 0)
|
||||
{
|
||||
fprintf(stderr, "Wrong format in RTP file.\n");
|
||||
return -1;
|
||||
}
|
||||
else if (strncmp(firstline,"#!RTPencode",11) == 0) {
|
||||
if(strncmp(firstline,"#!RTPencode1.0",14) != 0){
|
||||
printf("ERROR: wrong RTPencode version, must be 1.0\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("ERROR: wrong file format of input file\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
WebRtc_UWord32 start_sec;
|
||||
WebRtc_UWord32 start_usec;
|
||||
WebRtc_UWord32 source;
|
||||
WebRtc_UWord16 port;
|
||||
WebRtc_UWord16 padding;
|
||||
|
||||
fread(&start_sec, 4, 1, in_file);
|
||||
start_sec=ntohl(start_sec);
|
||||
fread(&start_usec, 4, 1, in_file);
|
||||
start_usec=ntohl(start_usec);
|
||||
fread(&source, 4, 1, in_file);
|
||||
source=ntohl(source);
|
||||
fread(&port, 2, 1, in_file);
|
||||
port=ntohs(port);
|
||||
fread(&padding, 2, 1, in_file);
|
||||
padding=ntohs(padding);
|
||||
}
|
||||
|
||||
/* check payload type for first speech packet */
|
||||
@ -683,14 +653,14 @@ int main(int argc, char* argv[])
|
||||
WebRtcNetEQ_GetJitterStatistics(NetEQvector[0]->instance(), &jitterStats);
|
||||
|
||||
printf("\nPost-call statistics:\n");
|
||||
printf(" Call duration ms : %lu\n", simClock-start_clock);
|
||||
printf(" Expand (voice) ms : %lu \t(%.2f%%)\n", jitterStats.interpolatedVoiceMs, (float) 100.0 * jitterStats.interpolatedVoiceMs/(simClock-start_clock));
|
||||
printf(" Expand (silence) ms : %lu \t(%.2f%%)\n", jitterStats.interpolatedSilentMs, (float) 100.0 * jitterStats.interpolatedSilentMs/(simClock-start_clock));
|
||||
printf(" Accelerate ms : %lu \t(%.2f%%)\n", jitterStats.accelerateMs, (float) 100.0 * jitterStats.accelerateMs/(simClock-start_clock));
|
||||
printf(" Flushed ms : %lu \t(%.2f%%)\n", jitterStats.flushedMs, (float) 100.0 * jitterStats.flushedMs/(simClock-start_clock));
|
||||
printf(" JB avg size ms : %lu\n", jitterStats.jbAvgSize);
|
||||
printf(" JB max size ms : %lu\n", jitterStats.jbMaxSize);
|
||||
printf(" Max inter-arrival ms: %lu\n", jitterStats.longestIATms);
|
||||
printf(" Call duration ms : %u\n", simClock-start_clock);
|
||||
printf(" Expand (voice) ms : %u \t(%.2f%%)\n", jitterStats.interpolatedVoiceMs, (float) 100.0 * jitterStats.interpolatedVoiceMs/(simClock-start_clock));
|
||||
printf(" Expand (silence) ms : %u \t(%.2f%%)\n", jitterStats.interpolatedSilentMs, (float) 100.0 * jitterStats.interpolatedSilentMs/(simClock-start_clock));
|
||||
printf(" Accelerate ms : %u \t(%.2f%%)\n", jitterStats.accelerateMs, (float) 100.0 * jitterStats.accelerateMs/(simClock-start_clock));
|
||||
printf(" Flushed ms : %u \t(%.2f%%)\n", jitterStats.flushedMs, (float) 100.0 * jitterStats.flushedMs/(simClock-start_clock));
|
||||
printf(" JB avg size ms : %u\n", jitterStats.jbAvgSize);
|
||||
printf(" JB max size ms : %u\n", jitterStats.jbMaxSize);
|
||||
printf(" Max inter-arrival ms: %u\n", jitterStats.longestIATms);
|
||||
|
||||
printf("\nComplexity estimates (including sub-components):\n");
|
||||
printf(" RecIn complexity : %.2f MCPS\n", NetEQvector[0]->getRecInTime() / ((float) 1000*(simClock-start_clock)));
|
||||
|
BIN
test/data/audio_coding/universal.rtp
Normal file
BIN
test/data/audio_coding/universal.rtp
Normal file
Binary file not shown.
BIN
test/data/audio_coding/universal_ref.pcm
Normal file
BIN
test/data/audio_coding/universal_ref.pcm
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user