diff --git a/src/modules/audio_coding/NetEQ/main/source/neteq_api_unittest.cc b/src/modules/audio_coding/NetEQ/main/source/neteq_api_unittest.cc new file mode 100644 index 0000000000..62e4271470 --- /dev/null +++ b/src/modules/audio_coding/NetEQ/main/source/neteq_api_unittest.cc @@ -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 +#include +#include // memset + +#include + +#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 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(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(); +} + diff --git a/src/modules/audio_coding/NetEQ/main/source/neteq_tests.gyp b/src/modules/audio_coding/NetEQ/main/source/neteq_tests.gyp new file mode 100644 index 0000000000..87b238caa3 --- /dev/null +++ b/src/modules/audio_coding/NetEQ/main/source/neteq_tests.gyp @@ -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: diff --git a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_NetEQClass.cc b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_NetEQClass.cc index e85819331c..d9cb7a12c3 100644 --- a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_NetEQClass.cc +++ b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_NetEQClass.cc @@ -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()); diff --git a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.cc b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.cc index 6d57f3f7cd..86263af365 100644 --- a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.cc +++ b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.cc @@ -10,6 +10,7 @@ #include "NETEQTEST_RTPpacket.h" +#include #include #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(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(_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; diff --git a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.h b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.h index d5efb74f96..829eccdf96 100644 --- a/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.h +++ b/src/modules/audio_coding/NetEQ/main/test/NETEQTEST_RTPpacket.h @@ -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(); diff --git a/src/modules/audio_coding/NetEQ/main/test/NetEqRTPplay.cc b/src/modules/audio_coding/NetEQ/main/test/NetEqRTPplay.cc index 748380a029..8f1d631621 100644 --- a/src/modules/audio_coding/NetEQ/main/test/NetEqRTPplay.cc +++ b/src/modules/audio_coding/NetEQ/main/test/NetEqRTPplay.cc @@ -150,7 +150,6 @@ int main(int argc, char* argv[]) std::vector 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))); diff --git a/test/data/audio_coding/universal.rtp b/test/data/audio_coding/universal.rtp new file mode 100644 index 0000000000..fd2038fb8a Binary files /dev/null and b/test/data/audio_coding/universal.rtp differ diff --git a/test/data/audio_coding/universal_ref.pcm b/test/data/audio_coding/universal_ref.pcm new file mode 100644 index 0000000000..da4a93033c Binary files /dev/null and b/test/data/audio_coding/universal_ref.pcm differ