diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc index aa8e8be063..5043717ced 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc @@ -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), diff --git a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h index d41580fff5..1ea61d0e7d 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h @@ -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 diff --git a/webrtc/modules/audio_coding/main/acm2/acm_opus.cc b/webrtc/modules/audio_coding/main/acm2/acm_opus.cc index 5830f6b40d..544c932f39 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_opus.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_opus.cc @@ -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 diff --git a/webrtc/modules/audio_coding/main/acm2/acm_opus.h b/webrtc/modules/audio_coding/main/acm2/acm_opus.h index a346e3c8ff..7963ee9bb1 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_opus.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_opus.h @@ -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 diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc index 51aaeb8eed..ed4b086949 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc @@ -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(current_timestamp - last_fec_timestamp_); + static_cast(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( - 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 // diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h index 157fc01ee4..247aee7f6b 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h @@ -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_; diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h index 9c7e5629de..1bfc0d3544 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h @@ -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 diff --git a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc index 1ee6abc30c..d06cc0709c 100644 --- a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc +++ b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc @@ -10,12 +10,9 @@ #include "webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h" +#include #include #include -#include - -#include -#include #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(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(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(); diff --git a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h index 4fdd943cf4..dbe3f0cb35 100644 --- a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h +++ b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.h @@ -12,6 +12,7 @@ #define WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_ENCODEDECODETEST_H_ #include +#include #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; }; diff --git a/webrtc/modules/audio_coding/main/test/PacketLossTest.cc b/webrtc/modules/audio_coding/main/test/PacketLossTest.cc new file mode 100644 index 0000000000..e6ef39277d --- /dev/null +++ b/webrtc/modules/audio_coding/main/test/PacketLossTest.cc @@ -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 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 diff --git a/webrtc/modules/audio_coding/main/test/PacketLossTest.h b/webrtc/modules/audio_coding/main/test/PacketLossTest.h new file mode 100644 index 0000000000..e34da8c7ae --- /dev/null +++ b/webrtc/modules/audio_coding/main/test/PacketLossTest.h @@ -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 +#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 sender_; + scoped_ptr receiver_; + int expected_loss_rate_; + int actual_loss_rate_; + int burst_length_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_TEST_PACKETLOSSTEST_H_ diff --git a/webrtc/modules/audio_coding/main/test/TestFEC.cc b/webrtc/modules/audio_coding/main/test/TestRedFec.cc similarity index 59% rename from webrtc/modules/audio_coding/main/test/TestFEC.cc rename to webrtc/modules/audio_coding/main/test/TestRedFec.cc index 76b6d4bf39..10498d8c57 100644 --- a/webrtc/modules/audio_coding/main/test/TestFEC.cc +++ b/webrtc/modules/audio_coding/main/test/TestRedFec.cc @@ -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 -#include +#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"); diff --git a/webrtc/modules/audio_coding/main/test/TestFEC.h b/webrtc/modules/audio_coding/main/test/TestRedFec.h similarity index 82% rename from webrtc/modules/audio_coding/main/test/TestFEC.h rename to webrtc/modules/audio_coding/main/test/TestRedFec.h index d7a62234de..30ced1e041 100644 --- a/webrtc/modules/audio_coding/main/test/TestFEC.h +++ b/webrtc/modules/audio_coding/main/test/TestRedFec.h @@ -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 #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_ diff --git a/webrtc/modules/audio_coding/main/test/Tester.cc b/webrtc/modules/audio_coding/main/test/Tester.cc index a89c9cd404..b6a554b9f0 100644 --- a/webrtc/modules/audio_coding/main/test/Tester.cc +++ b/webrtc/modules/audio_coding/main/test/Tester.cc @@ -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 diff --git a/webrtc/modules/audio_coding/main/test/delay_test.cc b/webrtc/modules/audio_coding/main/test/delay_test.cc index ba81507dd1..2e75472126 100644 --- a/webrtc/modules/audio_coding/main/test/delay_test.cc +++ b/webrtc/modules/audio_coding/main/test/delay_test.cc @@ -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) { diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index ff9761d555..47e0a74b1b 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -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', diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index 700f5d668b..37ec4d707a 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -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);