Limit RED audio payload to narrow band.

In SDP, RED audio codec has its own sample rate. Currently, we offer RED/8000 (8 kHz). But the actual send codec can violate this sample rate. The way to solve it is to introduce more RED payload types, e.g., RED/16000, RED/32000.

As a first step towards that, we, in this CL, limit the current RED (RED/8000) to work only with 8 kHz codecs.

BUG=3619
R=henrik.lundin@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#8830}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8830 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
minyue@webrtc.org 2015-03-23 12:57:45 +00:00
parent 1596a4f88b
commit 41d2befe9f
6 changed files with 265 additions and 92 deletions

View File

@ -45,19 +45,19 @@ std::map<int, int>::iterator FindSampleRateInMap(std::map<int, int>* cng_pt_map,
});
}
void SetCngPtInMap(std::map<int, int>* cng_pt_map,
int sample_rate_hz,
int payload_type) {
void SetPtInMap(std::map<int, int>* pt_map,
int sample_rate_hz,
int payload_type) {
if (payload_type == kInvalidPayloadType)
return;
CHECK_GE(payload_type, 0);
CHECK_LT(payload_type, 128);
auto pt_iter = FindSampleRateInMap(cng_pt_map, sample_rate_hz);
if (pt_iter != cng_pt_map->end()) {
auto pt_iter = FindSampleRateInMap(pt_map, sample_rate_hz);
if (pt_iter != pt_map->end()) {
// Remove item in map with sample_rate_hz.
cng_pt_map->erase(pt_iter);
pt_map->erase(pt_iter);
}
(*cng_pt_map)[payload_type] = sample_rate_hz;
(*pt_map)[payload_type] = sample_rate_hz;
}
} // namespace
@ -83,7 +83,7 @@ ACMGenericCodec::ACMGenericCodec(const CodecInst& codec_inst,
int cng_pt_swb,
int cng_pt_fb,
bool enable_red,
int red_payload_type)
int red_pt_nb)
: has_internal_fec_(false),
copy_red_enabled_(enable_red),
encoder_(NULL),
@ -96,16 +96,16 @@ ACMGenericCodec::ACMGenericCodec(const CodecInst& codec_inst,
opus_dtx_enabled_(false),
is_opus_(false),
is_isac_(false),
red_payload_type_(red_payload_type),
opus_application_set_(false) {
acm_codec_params_.codec_inst = codec_inst;
acm_codec_params_.enable_dtx = false;
acm_codec_params_.enable_vad = false;
acm_codec_params_.vad_mode = VADNormal;
SetCngPtInMap(&cng_pt_, 8000, cng_pt_nb);
SetCngPtInMap(&cng_pt_, 16000, cng_pt_wb);
SetCngPtInMap(&cng_pt_, 32000, cng_pt_swb);
SetCngPtInMap(&cng_pt_, 48000, cng_pt_fb);
SetPtInMap(&red_pt_, 8000, red_pt_nb);
SetPtInMap(&cng_pt_, 8000, cng_pt_nb);
SetPtInMap(&cng_pt_, 16000, cng_pt_wb);
SetPtInMap(&cng_pt_, 32000, cng_pt_swb);
SetPtInMap(&cng_pt_, 48000, cng_pt_fb);
ResetAudioEncoder();
CHECK(encoder_);
}
@ -348,20 +348,23 @@ void ACMGenericCodec::ResetAudioEncoder() {
encoder_ = audio_encoder_.get();
// Attach RED if needed.
if (copy_red_enabled_) {
CHECK_NE(red_payload_type_, kInvalidPayloadType);
auto pt_iter =
FindSampleRateInMap(&red_pt_, audio_encoder_->SampleRateHz());
if (copy_red_enabled_ && pt_iter != red_pt_.end()) {
CHECK_NE(pt_iter->first, kInvalidPayloadType);
AudioEncoderCopyRed::Config config;
config.payload_type = red_payload_type_;
config.payload_type = pt_iter->first;
config.speech_encoder = encoder_;
red_encoder_.reset(new AudioEncoderCopyRed(config));
encoder_ = red_encoder_.get();
} else {
red_encoder_.reset();
copy_red_enabled_ = false;
}
// Attach CNG if needed.
// Reverse-lookup from sample rate to complete key-value pair.
auto pt_iter =
pt_iter =
FindSampleRateInMap(&cng_pt_, audio_encoder_->SampleRateHz());
if (acm_codec_params_.enable_dtx && pt_iter != cng_pt_.end()) {
AudioEncoderCng::Config config;
@ -434,7 +437,12 @@ int16_t ACMGenericCodec::SetVAD(bool* enable_dtx,
}
void ACMGenericCodec::SetCngPt(int sample_rate_hz, int payload_type) {
SetCngPtInMap(&cng_pt_, sample_rate_hz, payload_type);
SetPtInMap(&cng_pt_, sample_rate_hz, payload_type);
ResetAudioEncoder();
}
void ACMGenericCodec::SetRedPt(int sample_rate_hz, int payload_type) {
SetPtInMap(&red_pt_, sample_rate_hz, payload_type);
ResetAudioEncoder();
}
@ -522,10 +530,10 @@ int ACMGenericCodec::SetPacketLossRate(int loss_rate) {
return 0;
}
void ACMGenericCodec::EnableCopyRed(bool enable, int red_payload_type) {
int ACMGenericCodec::SetCopyRed(bool enable) {
copy_red_enabled_ = enable;
red_payload_type_ = red_payload_type;
ResetAudioEncoder();
return copy_red_enabled_ == enable ? 0 : -1;
}
AudioEncoder* ACMGenericCodec::GetAudioEncoder() {

View File

@ -88,7 +88,7 @@ class ACMGenericCodec {
int cng_pt_swb,
int cng_pt_fb,
bool enable_red,
int red_payload_type);
int red_pt_nb);
~ACMGenericCodec();
///////////////////////////////////////////////////////////////////////////
@ -216,6 +216,9 @@ class ACMGenericCodec {
// Registers comfort noise at |sample_rate_hz| to use |payload_type|.
void SetCngPt(int sample_rate_hz, int payload_type);
// Registers RED at |sample_rate_hz| to use |payload_type|.
void SetRedPt(int sample_rate_hz, int payload_type);
///////////////////////////////////////////////////////////////////////////
// UpdateEncoderSampFreq()
// Call this function to update the encoder sampling frequency. This
@ -395,8 +398,15 @@ class ACMGenericCodec {
//
int SetPacketLossRate(int /* loss_rate */);
// Sets if CopyRed should be enabled.
void EnableCopyRed(bool enable, int red_payload_type);
///////////////////////////////////////////////////////////////////////////
// int SetCopyRed()
// Enable or disable copy RED. It fails if there is no RED payload that
// matches the codec, e.g., sample rate differs.
//
// Return value:
// -1 if failed,
// 0 if succeeded.
int SetCopyRed(bool enable);
AudioEncoder* GetAudioEncoder();
@ -427,7 +437,8 @@ class ACMGenericCodec {
bool is_isac_;
// Map from payload type to CNG sample rate (Hz).
std::map<int, int> cng_pt_;
int red_payload_type_;
// Map from payload type to RED sample rate (Hz).
std::map<int, int> red_pt_;
OpusApplicationMode opus_application_;
bool opus_application_set_;
};

View File

@ -131,7 +131,7 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
cng_wb_pltype_(255),
cng_swb_pltype_(255),
cng_fb_pltype_(255),
red_pltype_(255),
red_nb_pltype_(255),
vad_enabled_(false),
dtx_enabled_(false),
vad_mode_(VADNormal),
@ -163,8 +163,8 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
// Register the default payload type for RED and for CNG at sampling rates of
// 8, 16, 32 and 48 kHz.
for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) {
if (IsCodecRED(i)) {
red_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) {
red_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
} else if (IsCodecCN(i)) {
if (ACMCodecDB::database_[i].plfreq == 8000) {
cng_nb_pltype_ = static_cast<uint8_t>(ACMCodecDB::database_[i].pltype);
@ -319,7 +319,7 @@ ACMGenericCodec* AudioCodingModuleImpl::CreateCodec(const CodecInst& codec) {
CriticalSectionScoped lock(acm_crit_sect_);
my_codec = ACMCodecDB::CreateCodecInstance(
codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, cng_fb_pltype_,
red_enabled_, red_pltype_);
red_enabled_, red_nb_pltype_);
if (my_codec == NULL) {
// Error, could not create the codec.
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
@ -426,7 +426,15 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
return -1;
}
// Set RED payload type.
red_pltype_ = static_cast<uint8_t>(send_codec.pltype);
if (send_codec.plfreq == 8000) {
red_nb_pltype_ = static_cast<uint8_t>(send_codec.pltype);
} else {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"RegisterSendCodec() failed, invalid frequency for RED "
"registration");
return -1;
}
SetRedPayloadType(send_codec.plfreq, send_codec.pltype);
return 0;
}
@ -539,6 +547,13 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
if (send_codec_registered_) {
// If we change codec we start fresh with RED.
// This is not strictly required by the standard.
if(codec_ptr->SetCopyRed(red_enabled_) < 0) {
// We tried to preserve the old red status, if failed, it means the
// red status has to be flipped.
red_enabled_ = !red_enabled_;
}
codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
if (!codec_ptr->HasInternalFEC()) {
@ -906,7 +921,14 @@ int AudioCodingModuleImpl::SetREDStatus(
return -1;
}
EnableCopyRedForAllCodecs(enable_red);
// If a send codec is registered, set RED for the codec. We now only support
// copy red.
if (HaveValidEncoder("SetCopyRed") &&
codecs_[current_send_codec_idx_]->SetCopyRed(enable_red) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"SetREDStatus failed");
return -1;
}
red_enabled_ = enable_red;
return 0;
#else
@ -1461,10 +1483,11 @@ void AudioCodingModuleImpl::SetCngPayloadType(int sample_rate_hz,
}
}
void AudioCodingModuleImpl::EnableCopyRedForAllCodecs(bool enable) {
void AudioCodingModuleImpl::SetRedPayloadType(int sample_rate_hz,
int payload_type) {
for (auto* codec : codecs_) {
if (codec) {
codec->EnableCopyRed(enable, red_pltype_);
codec->SetRedPt(sample_rate_hz, payload_type);
}
}
}

View File

@ -297,7 +297,7 @@ class AudioCodingModuleImpl : public AudioCodingModule {
void SetCngPayloadType(int sample_rate_hz, int payload_type)
EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
void EnableCopyRedForAllCodecs(bool enable)
void SetRedPayloadType(int sample_rate_hz, int payload_type)
EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_);
CriticalSectionWrapper* acm_crit_sect_;
@ -311,7 +311,7 @@ class AudioCodingModuleImpl : public AudioCodingModule {
uint8_t cng_swb_pltype_ GUARDED_BY(acm_crit_sect_);
uint8_t cng_fb_pltype_ GUARDED_BY(acm_crit_sect_);
uint8_t red_pltype_ GUARDED_BY(acm_crit_sect_);
uint8_t red_nb_pltype_ GUARDED_BY(acm_crit_sect_);
bool vad_enabled_ GUARDED_BY(acm_crit_sect_);
bool dtx_enabled_ GUARDED_BY(acm_crit_sect_);
ACMVADMode vad_mode_ GUARDED_BY(acm_crit_sect_);

View File

@ -20,8 +20,30 @@
#include "webrtc/system_wrappers/interface/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 kNameISAC[] = "ISAC";
const char kNameG722[] = "G722";
const char kNameOPUS[] = "opus";
const char kNameCN[] = "CN";
const char kNameRED[] = "RED";
}
TestRedFec::TestRedFec()
: _acmA(AudioCodingModule::Create(0)),
_acmB(AudioCodingModule::Create(1)),
@ -60,32 +82,68 @@ void TestRedFec::Perform() {
_acmA->RegisterTransportCallback(_channelA2B);
_channelA2B->RegisterReceiverACM(_acmB.get());
#ifndef WEBRTC_CODEC_PCM16
EXPECT_TRUE(false) << "PCM16 needs to be activated to run this test\n");
return;
#endif
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;
#endif
char nameG722[] = "G722";
EXPECT_EQ(0, RegisterSendCodec('A', nameG722, 16000));
char nameCN[] = "CN";
EXPECT_EQ(0, RegisterSendCodec('A', nameCN, 16000));
char nameRED[] = "RED";
EXPECT_EQ(0, RegisterSendCodec('A', nameRED));
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();
_outFileB.Close();
#ifdef SUPPORT_RED_WB
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
#else
EXPECT_EQ(-1, _acmA->SetREDStatus(true));
EXPECT_FALSE(_acmA->REDStatus());
#endif
Run();
_outFileB.Close();
char nameISAC[] = "iSAC";
RegisterSendCodec('A', nameISAC, 16000);
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));
@ -93,13 +151,27 @@ void TestRedFec::Perform() {
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', nameISAC, 32000);
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));
@ -107,36 +179,57 @@ void TestRedFec::Perform() {
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', nameISAC, 32000);
OpenOutFile(_testCntr);
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', nameISAC, 16000);
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 32000);
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
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
EXPECT_EQ(0, RegisterSendCodec('A', nameG722));
EXPECT_EQ(0, RegisterSendCodec('A', nameCN, 16000));
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
@ -144,59 +237,93 @@ void TestRedFec::Perform() {
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', nameISAC, 16000);
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', nameISAC, 32000);
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', nameISAC, 32000);
OpenOutFile(_testCntr);
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', nameISAC, 16000);
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 32000);
RegisterSendCodec('A', kNameISAC, 32000);
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
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);
@ -204,14 +331,22 @@ void TestRedFec::Perform() {
return;
#endif
char nameOpus[] = "opus";
RegisterSendCodec('A', nameOpus, 48000);
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));
@ -220,16 +355,21 @@ void TestRedFec::Perform() {
// 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 ISAC with RED.
RegisterSendCodec('A', nameISAC, 32000);
// Switch to L16 with RED.
RegisterSendCodec('A', kNameL16, 8000);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
// ISAC does not support FEC, so FEC should be turned off automatically.
// L16 does not support FEC, so FEC should be turned off automatically.
EXPECT_FALSE(_acmA->CodecFEC());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
@ -237,32 +377,38 @@ void TestRedFec::Perform() {
Run();
// Switch to Opus again.
RegisterSendCodec('A', nameOpus, 48000);
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
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', nameG722, 16000);
RegisterSendCodec('A', kNameG722, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_FALSE(_acmA->CodecFEC());
RegisterSendCodec('A', nameISAC, 16000);
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', nameG722, 16000);
RegisterSendCodec('A', kNameG722, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
EXPECT_FALSE(_acmA->CodecFEC());
RegisterSendCodec('A', nameISAC, 16000);
RegisterSendCodec('A', kNameISAC, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
EXPECT_FALSE(_acmA->CodecFEC());
@ -272,7 +418,7 @@ int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
return _acmA->SetVAD(enableDTX, enableVAD, vadMode);
}
int16_t TestRedFec::RegisterSendCodec(char side, char* codecName,
int16_t TestRedFec::RegisterSendCodec(char side, const char* codecName,
int32_t samplingFreqHz) {
std::cout << std::flush;
AudioCodingModule* myACM;
@ -304,9 +450,6 @@ int16_t TestRedFec::RegisterSendCodec(char side, char* codecName,
void TestRedFec::Run() {
AudioFrame audioFrame;
uint16_t msecPassed = 0;
uint32_t secPassed = 0;
int32_t outFreqHzB = _outFileB.SamplingFrequency();
while (!_inFileA.EndOfFile()) {
@ -314,18 +457,6 @@ void TestRedFec::Run() {
EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame));
_outFileB.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
msecPassed += 10;
if (msecPassed >= 1000) {
msecPassed = 0;
secPassed++;
}
// Test that toggling RED on and off works.
if (((secPassed % 5) == 4) && (msecPassed == 0) && (_testCntr > 14)) {
EXPECT_EQ(0, _acmA->SetREDStatus(false));
}
if (((secPassed % 5) == 4) && (msecPassed >= 990) && (_testCntr > 14)) {
EXPECT_EQ(0, _acmA->SetREDStatus(true));
}
}
_inFileA.Rewind();
}

View File

@ -31,7 +31,7 @@ class TestRedFec : public ACMTest {
// 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, char* codecName,
int16_t RegisterSendCodec(char side, const char* codecName,
int32_t sampFreqHz = -1);
void Run();
void OpenOutFile(int16_t testNumber);