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
This commit is contained in:
minyue@webrtc.org 2014-05-23 15:16:51 +00:00
parent 706152dcc9
commit aa5ea1c0f9
17 changed files with 708 additions and 159 deletions

View File

@ -59,6 +59,7 @@ ACMGenericCodec::ACMGenericCodec()
num_lpc_params_(kNewCNGNumPLCParams),
sent_cn_previous_(false),
prev_frame_cng_(0),
has_internal_fec_(false),
neteq_decode_lock_(NULL),
codec_wrapper_lock_(*RWLockWrapper::CreateRWLock()),
last_timestamp_(0xD87F3F9F),

View File

@ -560,6 +560,46 @@ class ACMGenericCodec {
//
virtual AudioDecoder* Decoder(int /* codec_id */) { return NULL; }
///////////////////////////////////////////////////////////////////////////
// bool HasInternalFEC()
// Used to check if the codec has internal FEC.
//
// Return value:
// true if the codec has an internal FEC, e.g. Opus.
// false otherwise.
//
bool HasInternalFEC() const { return has_internal_fec_; }
///////////////////////////////////////////////////////////////////////////
// int SetFEC();
// Sets the codec internal FEC. No effects on codecs that do not provide
// internal FEC.
//
// Input:
// -enable_fec : if true FEC will be enabled otherwise the FEC is
// disabled.
//
// Return value:
// -1 if failed, or the codec does not support FEC
// 0 if succeeded.
//
virtual int SetFEC(bool /* enable_fec */) { return -1; }
///////////////////////////////////////////////////////////////////////////
// int SetPacketLossRate()
// Sets expected packet loss rate for encoding. Some encoders provide packet
// loss gnostic encoding to make stream less sensitive to packet losses,
// through e.g., FEC. No effects on codecs that do not provide such encoding.
//
// Input:
// -loss_rate : expected packet loss rate (0 -- 100 inclusive).
//
// Return value:
// -1 if failed, or codec does not support packet loss gnostic encoding,
// 0 if succeeded.
//
virtual int SetPacketLossRate(int /* loss_rate */) { return -1; }
protected:
///////////////////////////////////////////////////////////////////////////
// All the functions with FunctionNameSafe(...) contain the actual
@ -899,6 +939,9 @@ class ACMGenericCodec {
bool sent_cn_previous_;
int16_t prev_frame_cng_;
// FEC.
bool has_internal_fec_;
WebRtcACMCodecParams encoder_params_;
// Used as a global lock for all available decoders

View File

@ -75,6 +75,8 @@ ACMOpus::ACMOpus(int16_t codec_id)
// Opus has internal DTX, but we dont use it for now.
has_internal_dtx_ = false;
has_internal_fec_ = true;
if (codec_id_ != ACMCodecDB::kOpus) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, unique_id_,
"Wrong codec id for Opus.");
@ -198,6 +200,31 @@ int16_t ACMOpus::SetBitRateSafe(const int32_t rate) {
return -1;
}
int ACMOpus::SetFEC(bool enable_fec) {
// Ask the encoder to enable FEC.
if (enable_fec) {
if (WebRtcOpus_EnableFec(encoder_inst_ptr_) == 0) {
fec_enabled_ = true;
return 0;
}
} else {
if (WebRtcOpus_DisableFec(encoder_inst_ptr_) == 0) {
fec_enabled_ = false;
return 0;
}
}
return -1;
}
int ACMOpus::SetPacketLossRate(int loss_rate) {
// Ask the encoder to change the target packet loss rate.
if (WebRtcOpus_SetPacketLossRate(encoder_inst_ptr_, loss_rate) == 0) {
packet_loss_rate_ = loss_rate;
return 0;
}
return -1;
}
#endif // WEBRTC_CODEC_OPUS
} // namespace acm2

View File

@ -32,6 +32,10 @@ class ACMOpus : public ACMGenericCodec {
int16_t InternalInitEncoder(WebRtcACMCodecParams *codec_params);
virtual int SetFEC(bool enable_fec) OVERRIDE;
virtual int SetPacketLossRate(int loss_rate) OVERRIDE;
protected:
void DestructEncoderSafe();
@ -45,6 +49,9 @@ class ACMOpus : public ACMGenericCodec {
uint16_t sample_freq_;
uint16_t bitrate_;
int channels_;
bool fec_enabled_;
int packet_loss_rate_;
};
} // namespace acm2

View File

@ -39,11 +39,11 @@ enum {
kMaxPacketSize = 2560
};
// Maximum number of payloads that can be packed in one RED payload. For
// regular FEC, we only pack two payloads. In case of dual-streaming, in worst
// case we might pack 3 payloads in one RED payload.
// Maximum number of payloads that can be packed in one RED packet. For
// regular RED, we only pack two payloads. In case of dual-streaming, in worst
// case we might pack 3 payloads in one RED packet.
enum {
kNumFecFragmentationVectors = 2,
kNumRedFragmentationVectors = 2,
kMaxNumFragmentationVectors = 3
};
@ -136,8 +136,9 @@ AudioCodingModuleImpl::AudioCodingModuleImpl(
acm_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
vad_callback_(NULL),
is_first_red_(true),
fec_enabled_(false),
last_fec_timestamp_(0),
red_enabled_(false),
last_red_timestamp_(0),
codec_fec_enabled_(false),
previous_pltype_(255),
aux_rtp_header_(NULL),
receiver_initialized_(false),
@ -349,7 +350,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
int16_t len_bytes = MAX_PAYLOAD_SIZE_BYTE;
WebRtcACMEncodingType encoding_type;
if (secondary_encoder_->Encode(red_buffer_, &len_bytes,
&last_fec_timestamp_,
&last_red_timestamp_,
&encoding_type) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"ProcessDual(): Encoding of secondary encoder Failed");
@ -372,7 +373,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
index_primary = secondary_ready_to_encode ?
TimestampLessThan(primary_timestamp, secondary_timestamp) : 0;
index_primary += has_previous_payload ?
TimestampLessThan(primary_timestamp, last_fec_timestamp_) : 0;
TimestampLessThan(primary_timestamp, last_red_timestamp_) : 0;
}
if (secondary_ready_to_encode) {
@ -384,7 +385,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
if (has_previous_payload) {
index_previous_secondary = primary_ready_to_encode ?
(1 - TimestampLessThan(primary_timestamp, last_fec_timestamp_)) : 0;
(1 - TimestampLessThan(primary_timestamp, last_red_timestamp_)) : 0;
// If secondary is ready it always have a timestamp larger than previous
// secondary. So the index is either 0 or 1.
index_previous_secondary += secondary_ready_to_encode ? 1 : 0;
@ -405,7 +406,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
} else if (index_secondary == 0) {
current_timestamp = secondary_timestamp;
} else {
current_timestamp = last_fec_timestamp_;
current_timestamp = last_red_timestamp_;
}
fragmentation_.fragmentationVectorSize = 0;
@ -420,7 +421,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
fragmentation_.fragmentationPlType[index_previous_secondary] =
secondary_send_codec_inst_.pltype;
fragmentation_.fragmentationTimeDiff[index_previous_secondary] =
static_cast<uint16_t>(current_timestamp - last_fec_timestamp_);
static_cast<uint16_t>(current_timestamp - last_red_timestamp_);
fragmentation_.fragmentationVectorSize++;
}
@ -462,7 +463,7 @@ int AudioCodingModuleImpl::ProcessDualStream() {
{
CriticalSectionScoped lock(callback_crit_sect_);
if (packetization_callback_ != NULL) {
// Callback with payload data, including redundant data (FEC/RED).
// Callback with payload data, including redundant data (RED).
if (packetization_callback_->SendData(kAudioFrameSpeech,
my_red_payload_type,
current_timestamp, stream,
@ -495,7 +496,7 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
FrameType frame_type = kAudioFrameSpeech;
uint8_t current_payload_type = 0;
bool has_data_to_send = false;
bool fec_active = false;
bool red_active = false;
RTPFragmentationHeader my_fragmentation;
// Keep the scope of the ACM critical section limited.
@ -562,15 +563,15 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
// Redundancy encode is done here. The two bitstreams packetized into
// one RTP packet and the fragmentation points are set.
// Only apply RED on speech data.
if ((fec_enabled_) &&
if ((red_enabled_) &&
((encoding_type == kActiveNormalEncoded) ||
(encoding_type == kPassiveNormalEncoded))) {
// FEC is enabled within this scope.
// RED is enabled within this scope.
//
// Note that, a special solution exists for iSAC since it is the only
// codec for which GetRedPayload has a non-empty implementation.
//
// Summary of the FEC scheme below (use iSAC as example):
// Summary of the RED scheme below (use iSAC as example):
//
// 1st (is_first_red_ is true) encoded iSAC frame (primary #1) =>
// - call GetRedPayload() and store redundancy for packet #1 in
@ -581,7 +582,7 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
// - store primary #2 in 1st fragment of RED buffer and send the
// combined packet
// - the transmitted packet contains primary #2 (new) and
// reduncancy for packet #1 (old)
// redundancy for packet #1 (old)
// - call GetRed_Payload() and store redundancy for packet #2 in
// second fragment of RED buffer
//
@ -604,19 +605,19 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
//
// Hence, even if every second packet is dropped, perfect
// reconstruction is possible.
fec_active = true;
red_active = true;
has_data_to_send = false;
// Skip the following part for the first packet in a RED session.
if (!is_first_red_) {
// Rearrange stream such that FEC packets are included.
// Rearrange stream such that RED packets are included.
// Replace stream now that we have stored current stream.
memcpy(stream + fragmentation_.fragmentationOffset[1], red_buffer_,
fragmentation_.fragmentationLength[1]);
// Update the fragmentation time difference vector, in number of
// timestamps.
uint16_t time_since_last = static_cast<uint16_t>(
rtp_timestamp - last_fec_timestamp_);
rtp_timestamp - last_red_timestamp_);
// Update fragmentation vectors.
fragmentation_.fragmentationPlType[1] =
@ -630,7 +631,7 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
// Insert new packet payload type.
fragmentation_.fragmentationPlType[0] = current_payload_type;
last_fec_timestamp_ = rtp_timestamp;
last_red_timestamp_ = rtp_timestamp;
// Can be modified by the GetRedPayload() call if iSAC is utilized.
red_length_bytes = length_bytes;
@ -650,7 +651,7 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
if (codecs_[current_send_codec_idx_]->GetRedPayload(
red_buffer_, &red_length_bytes) == -1) {
// The codec was not iSAC => use current encoder output as redundant
// data instead (trivial FEC scheme).
// data instead (trivial RED scheme).
memcpy(red_buffer_, stream, red_length_bytes);
}
@ -658,7 +659,7 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
// Update payload type with RED payload type.
current_payload_type = red_pltype_;
// We have packed 2 payloads.
fragmentation_.fragmentationVectorSize = kNumFecFragmentationVectors;
fragmentation_.fragmentationVectorSize = kNumRedFragmentationVectors;
// Copy to local variable, as it will be used outside ACM lock.
my_fragmentation.CopyFrom(fragmentation_);
@ -672,8 +673,8 @@ int AudioCodingModuleImpl::ProcessSingleStream() {
CriticalSectionScoped lock(callback_crit_sect_);
if (packetization_callback_ != NULL) {
if (fec_active) {
// Callback with payload data, including redundant data (FEC/RED).
if (red_active) {
// Callback with payload data, including redundant data (RED).
packetization_callback_->SendData(frame_type, current_payload_type,
rtp_timestamp, stream, length_bytes,
&my_fragmentation);
@ -713,14 +714,14 @@ int AudioCodingModuleImpl::InitializeSender() {
}
}
// Initialize FEC/RED.
// Initialize RED.
is_first_red_ = true;
if (fec_enabled_ || secondary_encoder_.get() != NULL) {
if (red_enabled_ || secondary_encoder_.get() != NULL) {
if (red_buffer_ != NULL) {
memset(red_buffer_, 0, MAX_PAYLOAD_SIZE_BYTE);
}
if (fec_enabled_) {
ResetFragmentation(kNumFecFragmentationVectors);
if (red_enabled_) {
ResetFragmentation(kNumRedFragmentationVectors);
} else {
ResetFragmentation(0);
}
@ -1031,10 +1032,20 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
// Everything is fine so we can replace the previous codec with this one.
if (send_codec_registered_) {
// If we change codec we start fresh with FEC.
// If we change codec we start fresh with RED.
// This is not strictly required by the standard.
is_first_red_ = true;
codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_);
if (!codec_ptr->HasInternalFEC()) {
codec_fec_enabled_ = false;
} else {
if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"Cannot set codec FEC");
return -1;
}
}
}
current_send_codec_idx_ = codec_id;
@ -1120,8 +1131,18 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) {
}
send_codec_inst_.rate = send_codec.rate;
}
previous_pltype_ = send_codec_inst_.pltype;
if (!codecs_[codec_id]->HasInternalFEC()) {
codec_fec_enabled_ = false;
} else {
if (codecs_[codec_id]->SetFEC(codec_fec_enabled_) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"Cannot set codec FEC");
return -1;
}
}
previous_pltype_ = send_codec_inst_.pltype;
return 0;
}
}
@ -1384,41 +1405,86 @@ int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame,
}
/////////////////////////////////////////
// (FEC) Forward Error Correction
// (RED) Redundant Coding
//
bool AudioCodingModuleImpl::FECStatus() const {
bool AudioCodingModuleImpl::REDStatus() const {
CriticalSectionScoped lock(acm_crit_sect_);
return fec_enabled_;
return red_enabled_;
}
// Configure FEC status i.e on/off.
int AudioCodingModuleImpl::SetFECStatus(
// Configure RED status i.e on/off.
int AudioCodingModuleImpl::SetREDStatus(
#ifdef WEBRTC_CODEC_RED
bool enable_fec) {
bool enable_red) {
CriticalSectionScoped lock(acm_crit_sect_);
if (fec_enabled_ != enable_fec) {
if (enable_red == true && codec_fec_enabled_ == true) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
"Codec internal FEC and RED cannot be co-enabled.");
return -1;
}
if (red_enabled_ != enable_red) {
// Reset the RED buffer.
memset(red_buffer_, 0, MAX_PAYLOAD_SIZE_BYTE);
// Reset fragmentation buffers.
ResetFragmentation(kNumFecFragmentationVectors);
// Set fec_enabled_.
fec_enabled_ = enable_fec;
ResetFragmentation(kNumRedFragmentationVectors);
// Set red_enabled_.
red_enabled_ = enable_red;
}
is_first_red_ = true; // Make sure we restart FEC.
is_first_red_ = true; // Make sure we restart RED.
return 0;
#else
bool /* enable_fec */) {
fec_enabled_ = false;
bool /* enable_red */) {
red_enabled_ = false;
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
" WEBRTC_CODEC_RED is undefined => fec_enabled_ = %d",
fec_enabled_);
" WEBRTC_CODEC_RED is undefined => red_enabled_ = %d",
red_enabled_);
return -1;
#endif
}
/////////////////////////////////////////
// (FEC) Forward Error Correction (codec internal)
//
bool AudioCodingModuleImpl::CodecFEC() const {
return codec_fec_enabled_;
}
int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) {
CriticalSectionScoped lock(acm_crit_sect_);
if (enable_codec_fec == true && red_enabled_ == true) {
WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
"Codec internal FEC and RED cannot be co-enabled.");
return -1;
}
// Set codec FEC.
if (HaveValidEncoder("SetCodecFEC") &&
codecs_[current_send_codec_idx_]->SetFEC(enable_codec_fec) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"Set codec internal FEC failed.");
return -1;
}
codec_fec_enabled_ = enable_codec_fec;
return 0;
}
int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) {
if (HaveValidEncoder("SetPacketLossRate") &&
codecs_[current_send_codec_idx_]->SetPacketLossRate(loss_rate) < 0) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
"Set packet loss rate failed.");
return -1;
}
return 0;
}
/////////////////////////////////////////
// (VAD) Voice Activity Detection
//

View File

@ -92,14 +92,27 @@ class AudioCodingModuleImpl : public AudioCodingModule {
int Add10MsData(const AudioFrame& audio_frame);
/////////////////////////////////////////
// (FEC) Forward Error Correction
// (RED) Redundant Coding
//
// Configure FEC status i.e on/off.
int SetFECStatus(bool enable_fec);
// Configure RED status i.e. on/off.
int SetREDStatus(bool enable_red);
// Get RED status.
bool REDStatus() const;
/////////////////////////////////////////
// (FEC) Forward Error Correction (codec internal)
//
// Configure FEC status i.e. on/off.
int SetCodecFEC(bool enabled_codec_fec);
// Get FEC status.
bool FECStatus() const;
bool CodecFEC() const;
// Set target packet loss rate
int SetPacketLossRate(int loss_rate);
/////////////////////////////////////////
// (VAD) Voice Activity Detection
@ -313,21 +326,24 @@ class AudioCodingModuleImpl : public AudioCodingModule {
CriticalSectionWrapper* acm_crit_sect_;
ACMVADCallback* vad_callback_;
// RED/FEC.
// RED.
bool is_first_red_;
bool fec_enabled_;
bool red_enabled_;
// TODO(turajs): |red_buffer_| is allocated in constructor, why having them
// as pointers and not an array. If concerned about the memory, then make a
// set-up function to allocate them only when they are going to be used, i.e.
// FEC or Dual-streaming is enabled.
// RED or Dual-streaming is enabled.
uint8_t* red_buffer_;
// TODO(turajs): we actually don't need |fragmentation_| as a member variable.
// It is sufficient to keep the length & payload type of previous payload in
// member variables.
RTPFragmentationHeader fragmentation_;
uint32_t last_fec_timestamp_;
uint32_t last_red_timestamp_;
// Codec internal FEC
bool codec_fec_enabled_;
// This is to keep track of CN instances where we can send DTMFs.
uint8_t previous_pltype_;

View File

@ -373,12 +373,12 @@ class AudioCodingModule: public Module {
virtual int32_t Add10MsData(const AudioFrame& audio_frame) = 0;
///////////////////////////////////////////////////////////////////////////
// (FEC) Forward Error Correction
// (RED) Redundant Coding
//
///////////////////////////////////////////////////////////////////////////
// int32_t SetFECStatus(const bool enable)
// configure FEC status i.e. on/off.
// int32_t SetREDStatus()
// configure RED status i.e. on/off.
//
// RFC 2198 describes a solution which has a single payload type which
// signifies a packet with redundancy. That packet then becomes a container,
@ -388,27 +388,69 @@ class AudioCodingModule: public Module {
// since each encapsulated payload must be preceded by a header indicating
// the type of data enclosed.
//
// This means that FEC is actually a RED scheme.
//
// Input:
// -enable_fec : if true FEC is enabled, otherwise FEC is
// -enable_red : if true RED is enabled, otherwise RED is
// disabled.
//
// Return value:
// -1 if failed to set FEC status,
// -1 if failed to set RED status,
// 0 if succeeded.
//
virtual int32_t SetFECStatus(const bool enable_fec) = 0;
virtual int32_t SetREDStatus(bool enable_red) = 0;
///////////////////////////////////////////////////////////////////////////
// bool FECStatus()
// Get FEC status
// bool REDStatus()
// Get RED status
//
// Return value
// Return value:
// true if RED is enabled,
// false if RED is disabled.
//
virtual bool REDStatus() const = 0;
///////////////////////////////////////////////////////////////////////////
// (FEC) Forward Error Correction (codec internal)
//
///////////////////////////////////////////////////////////////////////////
// int32_t SetCodecFEC()
// Configures codec internal FEC status i.e. on/off. No effects on codecs that
// do not provide internal FEC.
//
// Input:
// -enable_fec : if true FEC will be enabled otherwise the FEC is
// disabled.
//
// Return value:
// -1 if failed, or the codec does not support FEC
// 0 if succeeded.
//
virtual int SetCodecFEC(bool enable_codec_fec) = 0;
///////////////////////////////////////////////////////////////////////////
// bool CodecFEC()
// Gets status of codec internal FEC.
//
// Return value:
// true if FEC is enabled,
// false if FEC is disabled.
//
virtual bool FECStatus() const = 0;
virtual bool CodecFEC() const = 0;
///////////////////////////////////////////////////////////////////////////
// int SetPacketLossRate()
// Sets expected packet loss rate for encoding. Some encoders provide packet
// loss gnostic encoding to make stream less sensitive to packet losses,
// through e.g., FEC. No effects on codecs that do not provide such encoding.
//
// Input:
// -packet_loss_rate : expected packet loss rate (0 -- 100 inclusive).
//
// Return value
// -1 if failed to set packet loss rate,
// 0 if succeeded.
//
virtual int SetPacketLossRate(int packet_loss_rate) = 0;
///////////////////////////////////////////////////////////////////////////
// (VAD) Voice Activity Detection

View File

@ -10,12 +10,9 @@
#include "webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h"
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common_types.h"
@ -54,16 +51,19 @@ Sender::Sender()
_packetization(NULL) {
}
void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream) {
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(
"audio_coding/testfile32kHz", "pcm");
_pcmFile.Open(file_name, 32000, "rb");
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)) {
@ -81,10 +81,8 @@ void Sender::Setup(AudioCodingModule *acm, RTPStream *rtpStream) {
}
EXPECT_EQ(0, acm->Codec(codecNo, &sendCodec));
// Default number of channels is 2 for CELT, so we change to 1 in this test.
if (!strcmp(sendCodec.plname, "CELT")) {
sendCodec.channels = 1;
}
sendCodec.channels = channels;
EXPECT_EQ(0, acm->RegisterSendCodec(sendCodec));
_packetization = new TestPacketization(rtpStream, sendCodec.plfreq);
@ -125,21 +123,28 @@ Receiver::Receiver()
_payloadSizeBytes(MAX_INCOMING_PAYLOAD) {
}
void Receiver::Setup(AudioCodingModule *acm, RTPStream *rtpStream) {
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(static_cast<uint8_t>(i), &recvCodec));
EXPECT_EQ(0, acm->RegisterReceiveCodec(recvCodec));
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() << "encodeDecode_out"
file_stream << webrtc::test::OutputPath() << out_file_name
<< static_cast<int>(codeId) << ".pcm";
file_name = file_stream.str();
_rtpStream = rtpStream;
@ -156,7 +161,7 @@ void Receiver::Setup(AudioCodingModule *acm, RTPStream *rtpStream) {
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() + "encodeDecode_out.pcm";
file_name = webrtc::test::OutputPath() + out_file_name + ".pcm";
_pcmFile.Open(file_name, playSampFreq, "wb+");
}
@ -213,7 +218,8 @@ bool Receiver::PlayoutData() {
if (_playoutLengthSmpls == 0) {
return false;
}
_pcmFile.Write10MsData(audioFrame.data_, audioFrame.samples_per_channel_);
_pcmFile.Write10MsData(audioFrame.data_,
audioFrame.samples_per_channel_ * audioFrame.num_channels_);
return true;
}
@ -310,7 +316,7 @@ void EncodeDecodeTest::Perform() {
_receiver.codeId = codeId;
rtpFile.ReadHeader();
_receiver.Setup(acm.get(), &rtpFile);
_receiver.Setup(acm.get(), &rtpFile, "encodeDecode_out", 1);
_receiver.Run();
_receiver.Teardown();
rtpFile.Close();
@ -335,7 +341,7 @@ void EncodeDecodeTest::EncodeToFile(int fileType, int codeId, int* codePars,
_sender.testMode = testMode;
_sender.codeId = codeId;
_sender.Setup(acm.get(), &rtpFile);
_sender.Setup(acm.get(), &rtpFile, "audio_coding/testfile32kHz", 32000, 1);
struct CodecInst sendCodecInst;
if (acm->SendCodec(&sendCodecInst) >= 0) {
_sender.Run();

View File

@ -12,6 +12,7 @@
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_ENCODEDECODETEST_H_
#include <stdio.h>
#include <string.h>
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
#include "webrtc/modules/audio_coding/main/test/ACMTest.h"
@ -44,7 +45,8 @@ class TestPacketization : public AudioPacketizationCallback {
class Sender {
public:
Sender();
void Setup(AudioCodingModule *acm, RTPStream *rtpStream);
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string in_file_name, int sample_rate, int channels);
void Teardown();
void Run();
bool Add10MsData();
@ -53,8 +55,10 @@ class Sender {
uint8_t testMode;
uint8_t codeId;
private:
protected:
AudioCodingModule* _acm;
private:
PCMFile _pcmFile;
AudioFrame _audioFrame;
TestPacketization* _packetization;
@ -63,10 +67,12 @@ class Sender {
class Receiver {
public:
Receiver();
void Setup(AudioCodingModule *acm, RTPStream *rtpStream);
virtual ~Receiver() {};
void Setup(AudioCodingModule *acm, RTPStream *rtpStream,
std::string out_file_name, int channels);
void Teardown();
void Run();
bool IncomingPacket();
virtual bool IncomingPacket();
bool PlayoutData();
//for auto_test and logging
@ -74,17 +80,19 @@ class Receiver {
uint8_t testMode;
private:
AudioCodingModule* _acm;
RTPStream* _rtpStream;
PCMFile _pcmFile;
int16_t* _playoutBuffer;
uint16_t _playoutLengthSmpls;
uint8_t _incomingPayload[MAX_INCOMING_PAYLOAD];
uint16_t _payloadSizeBytes;
uint16_t _realPayloadSizeBytes;
int32_t _frequency;
bool _firstTime;
protected:
AudioCodingModule* _acm;
uint8_t _incomingPayload[MAX_INCOMING_PAYLOAD];
RTPStream* _rtpStream;
WebRtcRTPHeader _rtpInfo;
uint16_t _realPayloadSizeBytes;
uint16_t _payloadSizeBytes;
uint32_t _nextTime;
};

View 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/main/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
scoped_ptr<AudioCodingModule> acm(AudioCodingModule::Create(0));
int codec_id = acm->Codec("opus", 48000, channels_);
RTPFile rtpFile;
std::string fileName = webrtc::test::OutputPath() + "outFile.rtp";
// 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_);
struct CodecInst sendCodecInst;
if (acm->SendCodec(&sendCodecInst) >= 0) {
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

View File

@ -0,0 +1,66 @@
/*
* 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_MAIN_TEST_PACKETLOSSTEST_H_
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_PACKETLOSSTEST_H_
#include <string>
#include "webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.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_;
scoped_ptr<SenderWithFEC> sender_;
scoped_ptr<ReceiverWithPacketLoss> receiver_;
int expected_loss_rate_;
int actual_loss_rate_;
int burst_length_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_PACKETLOSSTEST_H_

View File

@ -8,11 +8,11 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/main/test/TestFEC.h"
#include "webrtc/modules/audio_coding/main/test/TestRedFec.h"
#include <assert.h>
#include <iostream>
#include "webrtc/common.h"
#include "webrtc/common_types.h"
#include "webrtc/engine_configurations.h"
#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
@ -22,20 +22,21 @@
namespace webrtc {
TestFEC::TestFEC()
TestRedFec::TestRedFec()
: _acmA(AudioCodingModule::Create(0)),
_acmB(AudioCodingModule::Create(1)),
_channelA2B(NULL),
_testCntr(0) {}
_testCntr(0) {
}
TestFEC::~TestFEC() {
TestRedFec::~TestRedFec() {
if (_channelA2B != NULL) {
delete _channelA2B;
_channelA2B = NULL;
}
}
void TestFEC::Perform() {
void TestRedFec::Perform() {
const std::string file_name = webrtc::test::ResourcePath(
"audio_coding/testfile32kHz", "pcm");
_inFileA.Open(file_name, 32000, "rb");
@ -47,6 +48,10 @@ void TestFEC::Perform() {
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));
}
@ -68,13 +73,13 @@ void TestFEC::Perform() {
EXPECT_EQ(0, RegisterSendCodec('A', nameRED));
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -83,13 +88,13 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 16000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -97,13 +102,13 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 32000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -111,20 +116,20 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 32000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 32000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
_outFileB.Close();
@ -134,13 +139,13 @@ void TestFEC::Perform() {
EXPECT_EQ(0, RegisterSendCodec('A', nameCN, 16000));
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -148,13 +153,13 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 16000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -162,13 +167,13 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 32000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(true, true, VADVeryAggr));
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_FALSE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(false));
EXPECT_FALSE(_acmA->REDStatus());
Run();
_outFileB.Close();
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
OpenOutFile(_testCntr);
Run();
_outFileB.Close();
@ -176,30 +181,88 @@ void TestFEC::Perform() {
RegisterSendCodec('A', nameISAC, 32000);
OpenOutFile(_testCntr);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_EQ(0, _acmA->SetREDStatus(true));
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 32000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
RegisterSendCodec('A', nameISAC, 16000);
EXPECT_TRUE(_acmA->FECStatus());
EXPECT_TRUE(_acmA->REDStatus());
Run();
_outFileB.Close();
#ifndef WEBRTC_CODEC_OPUS
EXPECT_TRUE(false);
printf("Opus needs to be activated to run this test\n");
return;
#endif
char nameOpus[] = "opus";
RegisterSendCodec('A', nameOpus, 48000);
EXPECT_TRUE(_acmA->REDStatus());
// _channelA2B imposes 25% packet loss rate.
EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
// 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));
EXPECT_TRUE(_acmA->CodecFEC());
OpenOutFile(_testCntr);
Run();
// Switch to ISAC with RED.
RegisterSendCodec('A', nameISAC, 32000);
EXPECT_EQ(0, SetVAD(false, false, VADNormal));
// ISAC 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', nameOpus, 48000);
EXPECT_EQ(0, _acmA->SetCodecFEC(false));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
Run();
EXPECT_EQ(0, _acmA->SetCodecFEC(true));
_outFileB.Close();
// Codecs does not support internal FEC.
RegisterSendCodec('A', nameG722, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_FALSE(_acmA->CodecFEC());
RegisterSendCodec('A', nameISAC, 16000);
EXPECT_FALSE(_acmA->REDStatus());
EXPECT_EQ(-1, _acmA->SetCodecFEC(true));
EXPECT_FALSE(_acmA->CodecFEC());
}
int32_t TestFEC::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
int32_t TestRedFec::SetVAD(bool enableDTX, bool enableVAD, ACMVADMode vadMode) {
return _acmA->SetVAD(enableDTX, enableVAD, vadMode);
}
int16_t TestFEC::RegisterSendCodec(char side, char* codecName,
int32_t samplingFreqHz) {
int16_t TestRedFec::RegisterSendCodec(char side, char* codecName,
int32_t samplingFreqHz) {
std::cout << std::flush;
AudioCodingModule* myACM;
switch (side) {
@ -228,7 +291,7 @@ int16_t TestFEC::RegisterSendCodec(char side, char* codecName,
return 0;
}
void TestFEC::Run() {
void TestRedFec::Run() {
AudioFrame audioFrame;
uint16_t msecPassed = 0;
@ -246,22 +309,22 @@ void TestFEC::Run() {
msecPassed = 0;
secPassed++;
}
// Test that toggling FEC on and off works.
// Test that toggling RED on and off works.
if (((secPassed % 5) == 4) && (msecPassed == 0) && (_testCntr > 14)) {
EXPECT_EQ(0, _acmA->SetFECStatus(false));
EXPECT_EQ(0, _acmA->SetREDStatus(false));
}
if (((secPassed % 5) == 4) && (msecPassed >= 990) && (_testCntr > 14)) {
EXPECT_EQ(0, _acmA->SetFECStatus(true));
EXPECT_EQ(0, _acmA->SetREDStatus(true));
}
}
_inFileA.Rewind();
}
void TestFEC::OpenOutFile(int16_t test_number) {
void TestRedFec::OpenOutFile(int16_t test_number) {
std::string file_name;
std::stringstream file_stream;
file_stream << webrtc::test::OutputPath();
file_stream << "TestFEC_outFile_";
file_stream << "TestRedFec_outFile_";
file_stream << test_number << ".pcm";
file_name = file_stream.str();
_outFileB.Open(file_name, 16000, "wb");

View File

@ -8,9 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTFEC_H_
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTFEC_H_
#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTREDFEC_H_
#define WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTREDFEC_H_
#include <string>
#include "webrtc/modules/audio_coding/main/test/ACMTest.h"
#include "webrtc/modules/audio_coding/main/test/Channel.h"
#include "webrtc/modules/audio_coding/main/test/PCMFile.h"
@ -18,10 +19,12 @@
namespace webrtc {
class TestFEC : public ACMTest {
class Config;
class TestRedFec : public ACMTest {
public:
TestFEC();
~TestFEC();
explicit TestRedFec();
~TestRedFec();
void Perform();
private:
@ -45,4 +48,4 @@ class TestFEC : public ACMTest {
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTFEC_H_
#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_TESTREDFEC_H_

View File

@ -18,8 +18,9 @@
#include "webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h"
#include "webrtc/modules/audio_coding/main/test/iSACTest.h"
#include "webrtc/modules/audio_coding/main/test/opus_test.h"
#include "webrtc/modules/audio_coding/main/test/PacketLossTest.h"
#include "webrtc/modules/audio_coding/main/test/TestAllCodecs.h"
#include "webrtc/modules/audio_coding/main/test/TestFEC.h"
#include "webrtc/modules/audio_coding/main/test/TestRedFec.h"
#include "webrtc/modules/audio_coding/main/test/TestStereo.h"
#include "webrtc/modules/audio_coding/main/test/TestVADDTX.h"
#include "webrtc/modules/audio_coding/main/test/TwoWayCommunication.h"
@ -49,11 +50,11 @@ TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestEncodeDecode)) {
Trace::ReturnTrace();
}
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestFEC)) {
TEST(AudioCodingModuleTest, DISABLED_ON_ANDROID(TestRedFec)) {
Trace::CreateTrace();
Trace::SetTraceFile((webrtc::test::OutputPath() +
"acm_fec_trace.txt").c_str());
webrtc::TestFEC().Perform();
webrtc::TestRedFec().Perform();
Trace::ReturnTrace();
}
@ -97,6 +98,38 @@ TEST(AudioCodingModuleTest, TestOpus) {
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

View File

@ -161,8 +161,8 @@ class DelayTest {
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_->SetFECStatus(config.fec)) <<
"Failed to set FEC.\n";
ASSERT_EQ(0, acm_a_->SetREDStatus(config.fec)) <<
"Failed to set RED.\n";
}
void ConfigChannel(bool packet_loss) {

View File

@ -336,13 +336,14 @@
'audio_coding/main/test/EncodeDecodeTest.cc',
'audio_coding/main/test/iSACTest.cc',
'audio_coding/main/test/opus_test.cc',
'audio_coding/main/test/PacketLossTest.cc',
'audio_coding/main/test/PCMFile.cc',
'audio_coding/main/test/RTPFile.cc',
'audio_coding/main/test/SpatialAudio.cc',
'audio_coding/main/test/TestAllCodecs.cc',
'audio_coding/main/test/target_delay_unittest.cc',
'audio_coding/main/test/Tester.cc',
'audio_coding/main/test/TestFEC.cc',
'audio_coding/main/test/TestRedFec.cc',
'audio_coding/main/test/TestStereo.cc',
'audio_coding/main/test/TestVADDTX.cc',
'audio_coding/main/test/TimedTrace.cc',

View File

@ -3528,10 +3528,10 @@ int Channel::SetFECStatus(bool enable, int redPayloadtype) {
}
}
if (audio_coding_->SetFECStatus(enable) != 0) {
if (audio_coding_->SetREDStatus(enable) != 0) {
_engineStatisticsPtr->SetLastError(
VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
"SetFECStatus() failed to set FEC state in the ACM");
"SetREDStatus() failed to set RED state in the ACM");
return -1;
}
return 0;
@ -3540,7 +3540,7 @@ int Channel::SetFECStatus(bool enable, int redPayloadtype) {
int
Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
{
enabled = audio_coding_->FECStatus();
enabled = audio_coding_->REDStatus();
if (enabled)
{
int8_t payloadType(0);