Files
platform-external-webrtc/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc
minyue@webrtc.org aa5ea1c0f9 1. Make a clear distinction between codec internal FEC and RED, confusing mentioning of FEC in the old codes is replaced by RED
2. Add two new APIs to configure codec internal FEC

3. Add a test and listened to results. This is based modifying EncodeDecodeTest and deriving a new class from it.

New ACM gives good result.
Old ACM does not use NetEq 4, so FEC won't be decoded.

BUG=
R=tina.legrand@webrtc.org, turaj@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/11759004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6233 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-05-23 15:16:51 +00:00

354 lines
9.7 KiB
C++

/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h"
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
#include "webrtc/modules/audio_coding/main/test/utility.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/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 uint16_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) {
acm->InitializeSender();
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_EQ(0, ok);
if (ok != 0) {
return false;
}
return true;
}
return false;
}
void Sender::Run() {
while (true) {
if (!Add10MsData()) {
break;
}
EXPECT_GT(_acm->Process(), -1);
}
}
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;
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;
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.
EncodeToFile(1, codeId, codePars, _testMode);
RTPFile rtpFile;
std::string fileName = webrtc::test::OutputPath() + "outFile.rtp";
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();
}
}
void EncodeDecodeTest::EncodeToFile(int fileType, int codeId, int* codePars,
int testMode) {
scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(1));
RTPFile rtpFile;
std::string fileName = webrtc::test::OutputPath() + "outFile.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);
struct CodecInst sendCodecInst;
if (acm->SendCodec(&sendCodecInst) >= 0) {
_sender.Run();
}
_sender.Teardown();
rtpFile.Close();
}
} // namespace webrtc