From 45c6449114ab69cab755410f69567fa7e20f8106 Mon Sep 17 00:00:00 2001 From: Henrik Lundin Date: Mon, 30 Mar 2015 19:00:44 +0200 Subject: [PATCH] Introduce CodecManager and move code from AudioCodingModuleImpl This change essentially divides AudioCodingModuleImpl into two parts: one is the code related to managing codecs, now moved into CodecManager, and the other is what remains in AudioCodingModuleImpl. This change also removes AudioCodingModuleImpl::InitializeSender. The function was essentially no-op, since it was always called immediately after construction. COAUTHOR=kwiberg@webrtc.org BUG=4228 R=minyue@webrtc.org, tina.legrand@webrtc.org Review URL: https://webrtc-codereview.appspot.com/51469004 Cr-Commit-Position: refs/heads/master@{#8893} --- webrtc/modules/audio_coding/BUILD.gn | 2 + .../main/acm2/acm_generic_codec.cc | 6 +- .../main/acm2/acm_generic_codec.h | 4 +- .../main/acm2/acm_receiver_unittest_oldapi.cc | 1 - .../main/acm2/audio_coding_module.gypi | 2 + .../main/acm2/audio_coding_module_impl.cc | 699 ++---------------- .../main/acm2/audio_coding_module_impl.h | 59 +- .../audio_coding/main/acm2/codec_manager.cc | 612 +++++++++++++++ .../audio_coding/main/acm2/codec_manager.h | 101 +++ .../main/interface/audio_coding_module.h | 14 - .../modules/audio_coding/main/test/APITest.cc | 3 - .../main/test/EncodeDecodeTest.cc | 1 - .../main/test/TwoWayCommunication.cc | 11 +- webrtc/modules/utility/source/coder.cc | 1 - webrtc/voice_engine/channel.cc | 6 +- 15 files changed, 800 insertions(+), 722 deletions(-) create mode 100644 webrtc/modules/audio_coding/main/acm2/codec_manager.cc create mode 100644 webrtc/modules/audio_coding/main/acm2/codec_manager.h diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index c88653ed4d..d18ed66777 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -32,6 +32,8 @@ source_set("audio_coding") { "main/acm2/audio_coding_module_impl.h", "main/acm2/call_statistics.cc", "main/acm2/call_statistics.h", + "main/acm2/codec_manager.cc", + "main/acm2/codec_manager.h", "main/acm2/initial_delay_manager.cc", "main/acm2/initial_delay_manager.h", "main/acm2/nack.cc", 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 c472a4a116..6d7b09528b 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.cc @@ -209,7 +209,7 @@ size_t AudioDecoderProxy::Channels() const { return decoder_->Channels(); } -int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) { +int16_t ACMGenericCodec::EncoderParams(WebRtcACMCodecParams* enc_params) const { *enc_params = acm_codec_params_; return 0; } @@ -540,6 +540,10 @@ AudioEncoder* ACMGenericCodec::GetAudioEncoder() { return encoder_; } +const AudioEncoder* ACMGenericCodec::GetAudioEncoder() const { + return encoder_; +} + } // namespace acm2 } // namespace webrtc 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 6a5a04a07a..d491dfd40a 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h @@ -120,7 +120,7 @@ class ACMGenericCodec { // -1 if the encoder is not initialized, // 0 otherwise. // - int16_t EncoderParams(WebRtcACMCodecParams* enc_params); + int16_t EncoderParams(WebRtcACMCodecParams* enc_params) const; /////////////////////////////////////////////////////////////////////////// // int16_t InitEncoder(...) @@ -410,6 +410,8 @@ class ACMGenericCodec { AudioEncoder* GetAudioEncoder(); + const AudioEncoder* GetAudioEncoder() const; + private: bool has_internal_fec_; diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc index d2b7746854..269d19c81d 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc @@ -62,7 +62,6 @@ class AcmReceiverTestOldApi : public AudioPacketizationCallback, } acm_->InitializeReceiver(); - acm_->InitializeSender(); acm_->RegisterTransportCallback(this); rtp_header_.header.sequenceNumber = 0; diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi index edbcaa93b6..6b938b6bed 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module.gypi @@ -70,6 +70,8 @@ 'audio_coding_module_impl.h', 'call_statistics.cc', 'call_statistics.h', + 'codec_manager.cc', + 'codec_manager.h', 'initial_delay_manager.cc', 'initial_delay_manager.h', 'nack.cc', 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 c4ab6a945f..d78af65a6a 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 @@ -18,7 +18,6 @@ #include "webrtc/base/safe_conversions.h" #include "webrtc/engine_configurations.h" #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h" -#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" #include "webrtc/modules/audio_coding/main/acm2/acm_generic_codec.h" #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h" @@ -126,20 +125,8 @@ AudioCodingModuleImpl::AudioCodingModuleImpl( id_(config.id), expected_codec_ts_(0xD87F3F9F), expected_in_ts_(0xD87F3F9F), - send_codec_inst_(), - cng_nb_pltype_(255), - cng_wb_pltype_(255), - cng_swb_pltype_(255), - cng_fb_pltype_(255), - red_nb_pltype_(255), - vad_enabled_(false), - dtx_enabled_(false), - vad_mode_(VADNormal), - current_encoder_(nullptr), - stereo_send_(false), receiver_(config), - red_enabled_(false), - codec_fec_enabled_(false), + codec_manager_(this), previous_pltype_(255), aux_rtp_header_(NULL), receiver_initialized_(false), @@ -148,35 +135,6 @@ AudioCodingModuleImpl::AudioCodingModuleImpl( callback_crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), packetization_callback_(NULL), vad_callback_(NULL) { - // Nullify send codec memory, set payload type and set codec name to - // invalid values. - const char no_name[] = "noCodecRegistered"; - strncpy(send_codec_inst_.plname, no_name, RTP_PAYLOAD_NAME_SIZE - 1); - send_codec_inst_.pltype = -1; - - for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { - codecs_[i] = NULL; - mirror_codec_idx_[i] = -1; - } - - // Register the default payload type for RED and for CNG at sampling rates of - // 8, 16, 32 and 48 kHz. - for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { - if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) { - red_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (IsCodecCN(i)) { - if (ACMCodecDB::database_[i].plfreq == 8000) { - cng_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 16000) { - cng_wb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 32000) { - cng_swb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } else if (ACMCodecDB::database_[i].plfreq == 48000) { - cng_fb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); - } - } - } - if (InitializeReceiverSafe() < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, "Cannot initialize receiver"); @@ -185,23 +143,6 @@ AudioCodingModuleImpl::AudioCodingModuleImpl( } AudioCodingModuleImpl::~AudioCodingModuleImpl() { - { - CriticalSectionScoped lock(acm_crit_sect_); - - for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { - if (codecs_[i] != NULL) { - // Mirror index holds the address of the codec memory. - assert(mirror_codec_idx_[i] > -1); - if (codecs_[mirror_codec_idx_[i]] != NULL) { - delete codecs_[mirror_codec_idx_[i]]; - codecs_[mirror_codec_idx_[i]] = NULL; - } - - codecs_[i] = NULL; - } - } - } - if (aux_rtp_header_ != NULL) { delete aux_rtp_header_; aux_rtp_header_ = NULL; @@ -229,7 +170,8 @@ int32_t AudioCodingModuleImpl::Encode(const InputData& input_data) { return -1; } - AudioEncoder* audio_encoder = current_encoder_->GetAudioEncoder(); + AudioEncoder* audio_encoder = + codec_manager_.current_encoder()->GetAudioEncoder(); // Scale the timestamp to the codec's RTP timestamp rate. uint32_t rtp_timestamp = first_frame_ ? input_data.input_timestamp @@ -271,7 +213,7 @@ int32_t AudioCodingModuleImpl::Encode(const InputData& input_data) { frame_type, encoded_info.payload_type, encoded_info.encoded_timestamp, stream, encoded_info.encoded_bytes, my_fragmentation.fragmentationVectorSize > 0 ? &my_fragmentation - : nullptr); + : nullptr); } if (vad_callback_) { @@ -290,17 +232,6 @@ int32_t AudioCodingModuleImpl::Encode(const InputData& input_data) { // Sender // -// Initialize send codec. -int AudioCodingModuleImpl::InitializeSender() { - CriticalSectionScoped lock(acm_crit_sect_); - - // Start with invalid values. - current_encoder_ = nullptr; - send_codec_inst_.plname[0] = '\0'; - - return 0; -} - // TODO(henrik.lundin): Remove this method; only used in tests. int AudioCodingModuleImpl::ResetEncoder() { CriticalSectionScoped lock(acm_crit_sect_); @@ -310,365 +241,16 @@ int AudioCodingModuleImpl::ResetEncoder() { return 0; } -ACMGenericCodec* AudioCodingModuleImpl::CreateCodec(const CodecInst& codec) { - ACMGenericCodec* my_codec = NULL; - CriticalSectionScoped lock(acm_crit_sect_); - my_codec = ACMCodecDB::CreateCodecInstance( - codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, cng_fb_pltype_, - red_enabled_, red_nb_pltype_); - if (my_codec == NULL) { - // Error, could not create the codec. - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "ACMCodecDB::CreateCodecInstance() failed in CreateCodec()"); - return my_codec; - } - - return my_codec; -} - -// Check if the given codec is a valid to be registered as send codec. -static int IsValidSendCodec(const CodecInst& send_codec, - bool is_primary_encoder, - int acm_id, - int* mirror_id) { - if ((send_codec.channels != 1) && (send_codec.channels != 2)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "Wrong number of channels (%d, only mono and stereo are " - "supported) for %s encoder", send_codec.channels, - is_primary_encoder ? "primary" : "secondary"); - return -1; - } - - int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id); - if (codec_id < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "Invalid codec setting for the send codec."); - return -1; - } - - // TODO(tlegrand): Remove this check. Already taken care of in - // ACMCodecDB::CodecNumber(). - // Check if the payload-type is valid - if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "Invalid payload-type %d for %s.", send_codec.pltype, - send_codec.plname); - return -1; - } - - // Telephone-event cannot be a send codec. - if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "telephone-event cannot be a send codec"); - *mirror_id = -1; - return -1; - } - - if (ACMCodecDB::codec_settings_[codec_id].channel_support - < send_codec.channels) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "%d number of channels not supportedn for %s.", - send_codec.channels, send_codec.plname); - *mirror_id = -1; - return -1; - } - - if (!is_primary_encoder) { - // If registering the secondary encoder, then RED and CN are not valid - // choices as encoder. - if (IsCodecRED(&send_codec)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "RED cannot be secondary codec"); - *mirror_id = -1; - return -1; - } - - if (IsCodecCN(&send_codec)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, acm_id, - "DTX cannot be secondary codec"); - *mirror_id = -1; - return -1; - } - } - return codec_id; -} - // Can be called multiple times for Codec, CNG, RED. int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) { - int mirror_id; - int codec_id = IsValidSendCodec(send_codec, true, id_, &mirror_id); - CriticalSectionScoped lock(acm_crit_sect_); - - // Check for reported errors from function IsValidSendCodec(). - if (codec_id < 0) { - return -1; - } - - // RED can be registered with other payload type. If not registered a default - // payload type is used. - if (IsCodecRED(&send_codec)) { - // TODO(tlegrand): Remove this check. Already taken care of in - // ACMCodecDB::CodecNumber(). - // Check if the payload-type is valid - if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Invalid payload-type %d for %s.", send_codec.pltype, - send_codec.plname); - return -1; - } - // Set RED payload type. - if (send_codec.plfreq == 8000) { - red_nb_pltype_ = static_cast(send_codec.pltype); - } else { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "RegisterSendCodec() failed, invalid frequency for RED " - "registration"); - return -1; - } - SetRedPayloadType(send_codec.plfreq, send_codec.pltype); - return 0; - } - - // CNG can be registered with other payload type. If not registered the - // default payload types from codec database will be used. - if (IsCodecCN(&send_codec)) { - // CNG is registered. - switch (send_codec.plfreq) { - case 8000: { - cng_nb_pltype_ = static_cast(send_codec.pltype); - break; - } - case 16000: { - cng_wb_pltype_ = static_cast(send_codec.pltype); - break; - } - case 32000: { - cng_swb_pltype_ = static_cast(send_codec.pltype); - break; - } - case 48000: { - cng_fb_pltype_ = static_cast(send_codec.pltype); - break; - } - default: { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "RegisterSendCodec() failed, invalid frequency for CNG " - "registration"); - return -1; - } - } - SetCngPayloadType(send_codec.plfreq, send_codec.pltype); - return 0; - } - - // Set Stereo, and make sure VAD and DTX is turned off. - if (send_codec.channels == 2) { - stereo_send_ = true; - if (vad_enabled_ || dtx_enabled_) { - WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_, - "VAD/DTX is turned off, not supported when sending stereo."); - } - vad_enabled_ = false; - dtx_enabled_ = false; - } else { - stereo_send_ = false; - } - - // Check if the codec is already registered as send codec. - bool is_send_codec; - if (current_encoder_) { - int send_codec_mirror_id; - int send_codec_id = ACMCodecDB::CodecNumber(send_codec_inst_, - &send_codec_mirror_id); - assert(send_codec_id >= 0); - is_send_codec = (send_codec_id == codec_id) || - (mirror_id == send_codec_mirror_id); - } else { - is_send_codec = false; - } - - // If new codec, or new settings, register. - if (!is_send_codec) { - if (codecs_[mirror_id] == NULL) { - codecs_[mirror_id] = CreateCodec(send_codec); - if (codecs_[mirror_id] == NULL) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot Create the codec"); - return -1; - } - mirror_codec_idx_[mirror_id] = mirror_id; - } - - if (mirror_id != codec_id) { - codecs_[codec_id] = codecs_[mirror_id]; - mirror_codec_idx_[codec_id] = mirror_id; - } - - ACMGenericCodec* codec_ptr = codecs_[codec_id]; - WebRtcACMCodecParams codec_params; - - memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst)); - codec_params.enable_vad = vad_enabled_; - codec_params.enable_dtx = dtx_enabled_; - codec_params.vad_mode = vad_mode_; - // Force initialization. - if (codec_ptr->InitEncoder(&codec_params, true) < 0) { - // Could not initialize the encoder. - - // Check if already have a registered codec. - // Depending on that different messages are logged. - if (!current_encoder_) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot Initialize the encoder No Encoder is registered"); - } else { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot Initialize the encoder, continue encoding with " - "the previously registered codec"); - } - return -1; - } - - // Update states. - dtx_enabled_ = codec_params.enable_dtx; - vad_enabled_ = codec_params.enable_vad; - vad_mode_ = codec_params.vad_mode; - - // Everything is fine so we can replace the previous codec with this one. - if (current_encoder_) { - // If we change codec we start fresh with RED. - // This is not strictly required by the standard. - - if(codec_ptr->SetCopyRed(red_enabled_) < 0) { - // We tried to preserve the old red status, if failed, it means the - // red status has to be flipped. - red_enabled_ = !red_enabled_; - } - - codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_); - - if (!codec_ptr->HasInternalFEC()) { - 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_encoder_ = codecs_[codec_id]; - DCHECK(current_encoder_); - memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst)); - return 0; - } else { - // If codec is the same as already registered check if any parameters - // has changed compared to the current values. - // If any parameter is valid then apply it and record. - bool force_init = false; - - if (mirror_id != codec_id) { - codecs_[codec_id] = codecs_[mirror_id]; - mirror_codec_idx_[codec_id] = mirror_id; - } - - // Check the payload type. - if (send_codec.pltype != send_codec_inst_.pltype) { - // At this point check if the given payload type is valid. - // Record it later when the sampling frequency is changed - // successfully. - if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Out of range payload type"); - return -1; - } - } - - // If there is a codec that ONE instance of codec supports multiple - // sampling frequencies, then we need to take care of it here. - // one such a codec is iSAC. Both WB and SWB are encoded and decoded - // with one iSAC instance. Therefore, we need to update the encoder - // frequency if required. - if (send_codec_inst_.plfreq != send_codec.plfreq) { - force_init = true; - } - - // If packet size or number of channels has changed, we need to - // re-initialize the encoder. - if (send_codec_inst_.pacsize != send_codec.pacsize) { - force_init = true; - } - if (send_codec_inst_.channels != send_codec.channels) { - force_init = true; - } - - if (force_init) { - WebRtcACMCodecParams codec_params; - - memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst)); - codec_params.enable_vad = vad_enabled_; - codec_params.enable_dtx = dtx_enabled_; - codec_params.vad_mode = vad_mode_; - - // Force initialization. - if (current_encoder_->InitEncoder(&codec_params, true) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Could not change the codec packet-size."); - return -1; - } - - send_codec_inst_.plfreq = send_codec.plfreq; - send_codec_inst_.pacsize = send_codec.pacsize; - send_codec_inst_.channels = send_codec.channels; - } - - // If the change of sampling frequency has been successful then - // we store the payload-type. - send_codec_inst_.pltype = send_codec.pltype; - - // Check if a change in Rate is required. - if (send_codec.rate != send_codec_inst_.rate) { - if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Could not change the codec rate."); - return -1; - } - send_codec_inst_.rate = send_codec.rate; - } - - 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; - } - } - - return 0; - } + return codec_manager_.RegisterSendCodec(send_codec); } // Get current send codec. -int AudioCodingModuleImpl::SendCodec( - CodecInst* current_codec) const { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, - "SendCodec()"); +int AudioCodingModuleImpl::SendCodec(CodecInst* current_codec) const { CriticalSectionScoped lock(acm_crit_sect_); - - if (!current_encoder_) { - WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, - "SendCodec Failed, no codec is registered"); - return -1; - } - WebRtcACMCodecParams encoder_param; - current_encoder_->EncoderParams(&encoder_param); - encoder_param.codec_inst.pltype = send_codec_inst_.pltype; - memcpy(current_codec, &(encoder_param.codec_inst), sizeof(CodecInst)); - - return 0; + return codec_manager_.SendCodec(current_codec); } // Get current send frequency. @@ -677,13 +259,13 @@ int AudioCodingModuleImpl::SendFrequency() const { "SendFrequency()"); CriticalSectionScoped lock(acm_crit_sect_); - if (!current_encoder_) { + if (!codec_manager_.current_encoder()) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, "SendFrequency Failed, no codec is registered"); return -1; } - return send_codec_inst_.plfreq; + return codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz(); } // Get encode bitrate. @@ -693,14 +275,14 @@ int AudioCodingModuleImpl::SendFrequency() const { int AudioCodingModuleImpl::SendBitrate() const { CriticalSectionScoped lock(acm_crit_sect_); - if (!current_encoder_) { + if (!codec_manager_.current_encoder()) { WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_, "SendBitrate Failed, no codec is registered"); return -1; } WebRtcACMCodecParams encoder_param; - current_encoder_->EncoderParams(&encoder_param); + codec_manager_.current_encoder()->EncoderParams(&encoder_param); return encoder_param.codec_inst.rate; } @@ -779,7 +361,9 @@ int AudioCodingModuleImpl::Add10MsDataInternal(const AudioFrame& audio_frame, } // Check whether we need an up-mix or down-mix? - bool remix = ptr_frame->num_channels_ != send_codec_inst_.channels; + bool remix = + ptr_frame->num_channels_ != + codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels(); if (remix) { if (ptr_frame->num_channels_ == 1) { @@ -796,13 +380,15 @@ int AudioCodingModuleImpl::Add10MsDataInternal(const AudioFrame& audio_frame, const int16_t* ptr_audio = ptr_frame->data_; // For pushing data to primary, point the |ptr_audio| to correct buffer. - if (send_codec_inst_.channels != ptr_frame->num_channels_) + if (codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels() != + ptr_frame->num_channels_) ptr_audio = input_data->buffer; input_data->input_timestamp = ptr_frame->timestamp_; input_data->audio = ptr_audio; input_data->length_per_channel = ptr_frame->samples_per_channel_; - input_data->audio_channel = send_codec_inst_.channels; + input_data->audio_channel = + codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels(); return 0; } @@ -814,12 +400,15 @@ int AudioCodingModuleImpl::Add10MsDataInternal(const AudioFrame& audio_frame, // is required, |*ptr_out| points to |in_frame|. int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame, const AudioFrame** ptr_out) { - bool resample = (in_frame.sample_rate_hz_ != send_codec_inst_.plfreq); + bool resample = + (in_frame.sample_rate_hz_ != + codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz()); // This variable is true if primary codec and secondary codec (if exists) // are both mono and input is stereo. bool down_mix = - (in_frame.num_channels_ == 2) && (send_codec_inst_.channels == 1); + (in_frame.num_channels_ == 2) && + (codec_manager_.current_encoder()->GetAudioEncoder()->NumChannels() == 1); if (!first_10ms_data_) { expected_in_ts_ = in_frame.timestamp_; @@ -827,9 +416,13 @@ int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame, first_10ms_data_ = true; } else if (in_frame.timestamp_ != expected_in_ts_) { // TODO(turajs): Do we need a warning here. - expected_codec_ts_ += (in_frame.timestamp_ - expected_in_ts_) * - static_cast((static_cast(send_codec_inst_.plfreq) / - static_cast(in_frame.sample_rate_hz_))); + expected_codec_ts_ += + (in_frame.timestamp_ - expected_in_ts_) * + static_cast( + (static_cast(codec_manager_.current_encoder() + ->GetAudioEncoder() + ->SampleRateHz()) / + static_cast(in_frame.sample_rate_hz_))); expected_in_ts_ = in_frame.timestamp_; } @@ -867,20 +460,19 @@ int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame, // The result of the resampler is written to output frame. dest_ptr_audio = preprocess_frame_.data_; - preprocess_frame_.samples_per_channel_ = - resampler_.Resample10Msec(src_ptr_audio, - in_frame.sample_rate_hz_, - send_codec_inst_.plfreq, - preprocess_frame_.num_channels_, - AudioFrame::kMaxDataSizeSamples, - dest_ptr_audio); + preprocess_frame_.samples_per_channel_ = resampler_.Resample10Msec( + src_ptr_audio, in_frame.sample_rate_hz_, + codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz(), + preprocess_frame_.num_channels_, AudioFrame::kMaxDataSizeSamples, + dest_ptr_audio); if (preprocess_frame_.samples_per_channel_ < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, "Cannot add 10 ms audio, resampling failed"); return -1; } - preprocess_frame_.sample_rate_hz_ = send_codec_inst_.plfreq; + preprocess_frame_.sample_rate_hz_ = + codec_manager_.current_encoder()->GetAudioEncoder()->SampleRateHz(); } expected_codec_ts_ += preprocess_frame_.samples_per_channel_; @@ -895,8 +487,7 @@ int AudioCodingModuleImpl::PreprocessToAddData(const AudioFrame& in_frame, bool AudioCodingModuleImpl::REDStatus() const { CriticalSectionScoped lock(acm_crit_sect_); - - return red_enabled_; + return codec_manager_.red_enabled(); } // Configure RED status i.e on/off. @@ -904,23 +495,7 @@ int AudioCodingModuleImpl::SetREDStatus( #ifdef WEBRTC_CODEC_RED bool enable_red) { CriticalSectionScoped lock(acm_crit_sect_); - - 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 a send codec is registered, set RED for the codec. We now only support - // copy red. - if (HaveValidEncoder("SetCopyRed") && - current_encoder_->SetCopyRed(enable_red) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "SetREDStatus failed"); - return -1; - } - red_enabled_ = enable_red; - return 0; + return codec_manager_.SetCopyRed(enable_red) ? 0 : -1; #else bool /* enable_red */) { WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_, @@ -935,33 +510,18 @@ int AudioCodingModuleImpl::SetREDStatus( bool AudioCodingModuleImpl::CodecFEC() const { CriticalSectionScoped lock(acm_crit_sect_); - return codec_fec_enabled_; + return codec_manager_.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") && - current_encoder_->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; + return codec_manager_.SetCodecFEC(enable_codec_fec); } int AudioCodingModuleImpl::SetPacketLossRate(int loss_rate) { CriticalSectionScoped lock(acm_crit_sect_); if (HaveValidEncoder("SetPacketLossRate") && - current_encoder_->SetPacketLossRate(loss_rate) < 0) { + codec_manager_.current_encoder()->SetPacketLossRate(loss_rate) < 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, "Set packet loss rate failed."); return -1; @@ -976,60 +536,14 @@ int AudioCodingModuleImpl::SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode mode) { CriticalSectionScoped lock(acm_crit_sect_); - return SetVADSafe(enable_dtx, enable_vad, mode); -} - -int AudioCodingModuleImpl::SetVADSafe(bool enable_dtx, - bool enable_vad, - ACMVADMode mode) { - // Sanity check of the mode. - if ((mode != VADNormal) && (mode != VADLowBitrate) - && (mode != VADAggr) && (mode != VADVeryAggr)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Invalid VAD Mode %d, no change is made to VAD/DTX status", - mode); - return -1; - } - - // Check that the send codec is mono. We don't support VAD/DTX for stereo - // sending. - if ((enable_dtx || enable_vad) && stereo_send_) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "VAD/DTX not supported for stereo sending"); - dtx_enabled_ = false; - vad_enabled_ = false; - vad_mode_ = mode; - return -1; - } - - // Store VAD/DTX settings. Values can be changed in the call to "SetVAD" - // below. - dtx_enabled_ = enable_dtx; - vad_enabled_ = enable_vad; - vad_mode_ = mode; - - // If a send codec is registered, set VAD/DTX for the codec. - if (HaveValidEncoder("SetVAD") && - current_encoder_->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_) < 0) { - // SetVAD failed. - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "SetVAD failed"); - vad_enabled_ = false; - dtx_enabled_ = false; - return -1; - } - return 0; + return codec_manager_.SetVAD(enable_dtx, enable_vad, mode); } // Get VAD/DTX settings. int AudioCodingModuleImpl::VAD(bool* dtx_enabled, bool* vad_enabled, ACMVADMode* mode) const { CriticalSectionScoped lock(acm_crit_sect_); - - *dtx_enabled = dtx_enabled_; - *vad_enabled = vad_enabled_; - *mode = vad_mode_; - + codec_manager_.VAD(dtx_enabled, vad_enabled, mode); return 0; } @@ -1108,56 +622,24 @@ int AudioCodingModuleImpl::PlayoutFrequency() const { // for codecs, CNG (NB, WB and SWB), DTMF, RED. int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { CriticalSectionScoped lock(acm_crit_sect_); - - if (codec.channels > 2 || codec.channels < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Unsupported number of channels, %d.", codec.channels); - return -1; - } - - // TODO(turajs) do we need this for NetEq 4? - if (!receiver_initialized_) { - if (InitializeReceiverSafe() < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot initialize receiver, failed registering codec."); - return -1; - } - } - - int mirror_id; - int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id); - - if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Wrong codec params to be registered as receive codec"); - return -1; - } - - // Check if the payload-type is valid. - if (!ACMCodecDB::ValidPayloadType(codec.pltype)) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Invalid payload-type %d for %s.", codec.pltype, - codec.plname); - return -1; - } - - AudioDecoder* decoder = NULL; - // Get |decoder| associated with |codec|. |decoder| can be NULL if |codec| - // does not own its decoder. - if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Wrong codec params to be registered as receive codec"); - return -1; - } - uint8_t payload_type = static_cast(codec.pltype); - return receiver_.AddCodec(codec_id, payload_type, codec.channels, decoder); + DCHECK(receiver_initialized_); + return codec_manager_.RegisterReceiveCodec(codec); } // Get current received codec. int AudioCodingModuleImpl::ReceiveCodec(CodecInst* current_codec) const { + CriticalSectionScoped lock(acm_crit_sect_); return receiver_.LastAudioCodec(current_codec); } +int AudioCodingModuleImpl::RegisterDecoder(int acm_codec_id, + uint8_t payload_type, + int channels, + AudioDecoder* audio_decoder) { + return receiver_.AddCodec(acm_codec_id, payload_type, channels, + audio_decoder); +} + // Incoming packet from network parsed and ready for decode. int AudioCodingModuleImpl::IncomingPacket(const uint8_t* incoming_payload, const size_t payload_length, @@ -1312,7 +794,7 @@ int AudioCodingModuleImpl::SetISACMaxRate(int max_bit_per_sec) { return -1; } - return current_encoder_->SetISACMaxRate(max_bit_per_sec); + return codec_manager_.current_encoder()->SetISACMaxRate(max_bit_per_sec); } // TODO(henrik.lundin): Remove? Only used in tests. Deprecated in VoiceEngine. @@ -1323,7 +805,8 @@ int AudioCodingModuleImpl::SetISACMaxPayloadSize(int max_size_bytes) { return -1; } - return current_encoder_->SetISACMaxPayloadSize(max_size_bytes); + return codec_manager_.current_encoder()->SetISACMaxPayloadSize( + max_size_bytes); } // TODO(henrik.lundin): Remove? Only used in tests. @@ -1349,8 +832,8 @@ int AudioCodingModuleImpl::SetOpusApplication(OpusApplicationMode application, if (!HaveValidEncoder("SetOpusApplication")) { return -1; } - return current_encoder_->SetOpusApplication(application, - disable_dtx_if_needed); + return codec_manager_.current_encoder()->SetOpusApplication( + application, disable_dtx_if_needed); } // Informs Opus encoder of the maximum playback rate the receiver will render. @@ -1359,7 +842,7 @@ int AudioCodingModuleImpl::SetOpusMaxPlaybackRate(int frequency_hz) { if (!HaveValidEncoder("SetOpusMaxPlaybackRate")) { return -1; } - return current_encoder_->SetOpusMaxPlaybackRate(frequency_hz); + return codec_manager_.current_encoder()->SetOpusMaxPlaybackRate(frequency_hz); } int AudioCodingModuleImpl::EnableOpusDtx(bool force_voip) { @@ -1367,7 +850,7 @@ int AudioCodingModuleImpl::EnableOpusDtx(bool force_voip) { if (!HaveValidEncoder("EnableOpusDtx")) { return -1; } - return current_encoder_->EnableOpusDtx(force_voip); + return codec_manager_.current_encoder()->EnableOpusDtx(force_voip); } int AudioCodingModuleImpl::DisableOpusDtx() { @@ -1375,7 +858,7 @@ int AudioCodingModuleImpl::DisableOpusDtx() { if (!HaveValidEncoder("DisableOpusDtx")) { return -1; } - return current_encoder_->DisableOpusDtx(); + return codec_manager_.current_encoder()->DisableOpusDtx(); } int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) { @@ -1383,7 +866,7 @@ int AudioCodingModuleImpl::PlayoutTimestamp(uint32_t* timestamp) { } bool AudioCodingModuleImpl::HaveValidEncoder(const char* caller_name) const { - if (!current_encoder_) { + if (!codec_manager_.current_encoder()) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, "%s failed: No send codec is registered.", caller_name); return false; @@ -1415,60 +898,6 @@ int AudioCodingModuleImpl::REDPayloadISAC(int isac_rate, // return status; } -int AudioCodingModuleImpl::GetAudioDecoder(const CodecInst& codec, int codec_id, - int mirror_id, - AudioDecoder** decoder) { - if (ACMCodecDB::OwnsDecoder(codec_id)) { - // This codec has to own its own decoder. Therefore, it should create the - // corresponding AudioDecoder class and insert it into NetEq. If the codec - // does not exist create it. - // - // TODO(turajs): this part of the code is common with RegisterSendCodec(), - // make a method for it. - if (codecs_[mirror_id] == NULL) { - codecs_[mirror_id] = CreateCodec(codec); - if (codecs_[mirror_id] == NULL) { - WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_, - "Cannot Create the codec"); - return -1; - } - mirror_codec_idx_[mirror_id] = mirror_id; - } - - if (mirror_id != codec_id) { - codecs_[codec_id] = codecs_[mirror_id]; - mirror_codec_idx_[codec_id] = mirror_id; - } - *decoder = codecs_[codec_id]->Decoder(); - if (!*decoder) { - assert(false); - return -1; - } - } else { - *decoder = NULL; - } - - return 0; -} - -void AudioCodingModuleImpl::SetCngPayloadType(int sample_rate_hz, - int payload_type) { - for (auto* codec : codecs_) { - if (codec) { - codec->SetCngPt(sample_rate_hz, payload_type); - } - } -} - -void AudioCodingModuleImpl::SetRedPayloadType(int sample_rate_hz, - int payload_type) { - for (auto* codec : codecs_) { - if (codec) { - codec->SetRedPt(sample_rate_hz, payload_type); - } - } -} - int AudioCodingModuleImpl::SetInitialPlayoutDelay(int delay_ms) { { CriticalSectionScoped lock(acm_crit_sect_); 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 04a20598fa..1e9cbb989b 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 @@ -20,6 +20,7 @@ #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" #include "webrtc/modules/audio_coding/main/acm2/acm_receiver.h" #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h" +#include "webrtc/modules/audio_coding/main/acm2/codec_manager.h" namespace webrtc { @@ -42,9 +43,6 @@ class AudioCodingModuleImpl : public AudioCodingModule { // Sender // - // Initialize send codec. - int InitializeSender() override; - // Reset send codec. int ResetEncoder() override; @@ -135,6 +133,11 @@ class AudioCodingModuleImpl : public AudioCodingModule { // Get current received codec. int ReceiveCodec(CodecInst* current_codec) const override; + int RegisterDecoder(int acm_codec_id, + uint8_t payload_type, + int channels, + AudioDecoder* audio_decoder); + // Incoming packet from network parsed and ready for decode. int IncomingPacket(const uint8_t* incoming_payload, const size_t payload_length, @@ -249,18 +252,11 @@ class AudioCodingModuleImpl : public AudioCodingModule { int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data); int Encode(const InputData& input_data); - ACMGenericCodec* CreateCodec(const CodecInst& codec); - int InitializeReceiverSafe() EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); bool HaveValidEncoder(const char* caller_name) const EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); - // Set VAD/DTX status. This function does not acquire a lock, and it is - // created to be called only from inside a critical section. - int SetVADSafe(bool enable_dtx, bool enable_vad, ACMVADMode mode) - EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); - // Preprocessing of input audio, including resampling and down-mixing if // required, before pushing audio into encoder's buffer. // @@ -280,54 +276,13 @@ class AudioCodingModuleImpl : public AudioCodingModule { // to |index|. int UpdateUponReceivingCodec(int index); - // Get a pointer to AudioDecoder of the given codec. For some codecs, e.g. - // iSAC, encoding and decoding have to be performed on a shared - // codec-instance. By calling this method, we get the codec-instance that ACM - // owns, then pass that to NetEq. This way, we perform both encoding and - // decoding on the same codec-instance. Furthermore, ACM would have control - // over decoder functionality if required. If |codec| does not share an - // instance between encoder and decoder, the |*decoder| is set NULL. - // The field ACMCodecDB::CodecSettings.owns_decoder indicates that if a - // codec owns the decoder-instance. For such codecs |*decoder| should be a - // valid pointer, otherwise it will be NULL. - int GetAudioDecoder(const CodecInst& codec, int codec_id, - int mirror_id, AudioDecoder** decoder) - EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); - - void SetCngPayloadType(int sample_rate_hz, int payload_type) - EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); - - void SetRedPayloadType(int sample_rate_hz, int payload_type) - EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); - CriticalSectionWrapper* acm_crit_sect_; int id_; // TODO(henrik.lundin) Make const. uint32_t expected_codec_ts_ GUARDED_BY(acm_crit_sect_); uint32_t expected_in_ts_ GUARDED_BY(acm_crit_sect_); - CodecInst send_codec_inst_ GUARDED_BY(acm_crit_sect_); - - uint8_t cng_nb_pltype_ GUARDED_BY(acm_crit_sect_); - uint8_t cng_wb_pltype_ GUARDED_BY(acm_crit_sect_); - uint8_t cng_swb_pltype_ GUARDED_BY(acm_crit_sect_); - uint8_t cng_fb_pltype_ GUARDED_BY(acm_crit_sect_); - - uint8_t red_nb_pltype_ GUARDED_BY(acm_crit_sect_); - bool vad_enabled_ GUARDED_BY(acm_crit_sect_); - bool dtx_enabled_ GUARDED_BY(acm_crit_sect_); - ACMVADMode vad_mode_ GUARDED_BY(acm_crit_sect_); - ACMGenericCodec* codecs_[ACMCodecDB::kMaxNumCodecs] - GUARDED_BY(acm_crit_sect_); - ACMGenericCodec* current_encoder_ GUARDED_BY(acm_crit_sect_); - int mirror_codec_idx_[ACMCodecDB::kMaxNumCodecs] GUARDED_BY(acm_crit_sect_); - bool stereo_send_ GUARDED_BY(acm_crit_sect_); ACMResampler resampler_ GUARDED_BY(acm_crit_sect_); AcmReceiver receiver_; // AcmReceiver has it's own internal lock. - - // RED. - bool red_enabled_ GUARDED_BY(acm_crit_sect_); - - // Codec internal FEC - bool codec_fec_enabled_ GUARDED_BY(acm_crit_sect_); + CodecManager codec_manager_ GUARDED_BY(acm_crit_sect_); // This is to keep track of CN instances where we can send DTMFs. uint8_t previous_pltype_ GUARDED_BY(acm_crit_sect_); diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc new file mode 100644 index 0000000000..c3e340e0e2 --- /dev/null +++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2015 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/acm2/codec_manager.h" + +#include "webrtc/base/checks.h" +#include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h" + +namespace webrtc { +namespace acm2 { + +namespace { +bool IsCodecRED(const CodecInst* codec) { + return (STR_CASE_CMP(codec->plname, "RED") == 0); +} + +bool IsCodecRED(int index) { + return (IsCodecRED(&ACMCodecDB::database_[index])); +} + +bool IsCodecCN(const CodecInst* codec) { + return (STR_CASE_CMP(codec->plname, "CN") == 0); +} + +bool IsCodecCN(int index) { + return (IsCodecCN(&ACMCodecDB::database_[index])); +} + +// Check if the given codec is a valid to be registered as send codec. +int IsValidSendCodec(const CodecInst& send_codec, + bool is_primary_encoder, + int* mirror_id) { + int dummy_id = 0; + if ((send_codec.channels != 1) && (send_codec.channels != 2)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Wrong number of channels (%d, only mono and stereo are " + "supported) for %s encoder", + send_codec.channels, + is_primary_encoder ? "primary" : "secondary"); + return -1; + } + + int codec_id = ACMCodecDB::CodecNumber(send_codec, mirror_id); + if (codec_id < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Invalid codec setting for the send codec."); + return -1; + } + + // TODO(tlegrand): Remove this check. Already taken care of in + // ACMCodecDB::CodecNumber(). + // Check if the payload-type is valid + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Invalid payload-type %d for %s.", send_codec.pltype, + send_codec.plname); + return -1; + } + + // Telephone-event cannot be a send codec. + if (!STR_CASE_CMP(send_codec.plname, "telephone-event")) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "telephone-event cannot be a send codec"); + *mirror_id = -1; + return -1; + } + + if (ACMCodecDB::codec_settings_[codec_id].channel_support < + send_codec.channels) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "%d number of channels not supportedn for %s.", + send_codec.channels, send_codec.plname); + *mirror_id = -1; + return -1; + } + + if (!is_primary_encoder) { + // If registering the secondary encoder, then RED and CN are not valid + // choices as encoder. + if (IsCodecRED(&send_codec)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "RED cannot be secondary codec"); + *mirror_id = -1; + return -1; + } + + if (IsCodecCN(&send_codec)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "DTX cannot be secondary codec"); + *mirror_id = -1; + return -1; + } + } + return codec_id; +} + +const CodecInst kEmptyCodecInst = {-1, "noCodecRegistered", 0, 0, 0, 0}; +} // namespace + +CodecManager::CodecManager(AudioCodingModuleImpl* acm) + : acm_(acm), + cng_nb_pltype_(255), + cng_wb_pltype_(255), + cng_swb_pltype_(255), + cng_fb_pltype_(255), + red_nb_pltype_(255), + stereo_send_(false), + vad_enabled_(false), + dtx_enabled_(false), + vad_mode_(VADNormal), + current_encoder_(nullptr), + send_codec_inst_(kEmptyCodecInst), + red_enabled_(false), + codec_fec_enabled_(false) { + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + codecs_[i] = nullptr; + mirror_codec_idx_[i] = -1; + } + + // Register the default payload type for RED and for CNG at sampling rates of + // 8, 16, 32 and 48 kHz. + for (int i = (ACMCodecDB::kNumCodecs - 1); i >= 0; i--) { + if (IsCodecRED(i) && ACMCodecDB::database_[i].plfreq == 8000) { + red_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + } else if (IsCodecCN(i)) { + if (ACMCodecDB::database_[i].plfreq == 8000) { + cng_nb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 16000) { + cng_wb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 32000) { + cng_swb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + } else if (ACMCodecDB::database_[i].plfreq == 48000) { + cng_fb_pltype_ = static_cast(ACMCodecDB::database_[i].pltype); + } + } + } + thread_checker_.DetachFromThread(); +} + +CodecManager::~CodecManager() { + for (int i = 0; i < ACMCodecDB::kMaxNumCodecs; i++) { + if (codecs_[i] != NULL) { + // Mirror index holds the address of the codec memory. + assert(mirror_codec_idx_[i] > -1); + if (codecs_[mirror_codec_idx_[i]] != NULL) { + delete codecs_[mirror_codec_idx_[i]]; + codecs_[mirror_codec_idx_[i]] = NULL; + } + + codecs_[i] = NULL; + } + } +} + +int CodecManager::RegisterSendCodec(const CodecInst& send_codec) { + DCHECK(thread_checker_.CalledOnValidThread()); + int mirror_id; + int codec_id = IsValidSendCodec(send_codec, true, &mirror_id); + + // Check for reported errors from function IsValidSendCodec(). + if (codec_id < 0) { + return -1; + } + + int dummy_id = 0; + // RED can be registered with other payload type. If not registered a default + // payload type is used. + if (IsCodecRED(&send_codec)) { + // TODO(tlegrand): Remove this check. Already taken care of in + // ACMCodecDB::CodecNumber(). + // Check if the payload-type is valid + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Invalid payload-type %d for %s.", send_codec.pltype, + send_codec.plname); + return -1; + } + // Set RED payload type. + if (send_codec.plfreq == 8000) { + red_nb_pltype_ = static_cast(send_codec.pltype); + } else { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "RegisterSendCodec() failed, invalid frequency for RED " + "registration"); + return -1; + } + SetRedPayloadType(send_codec.plfreq, send_codec.pltype); + return 0; + } + + // CNG can be registered with other payload type. If not registered the + // default payload types from codec database will be used. + if (IsCodecCN(&send_codec)) { + // CNG is registered. + switch (send_codec.plfreq) { + case 8000: { + cng_nb_pltype_ = static_cast(send_codec.pltype); + break; + } + case 16000: { + cng_wb_pltype_ = static_cast(send_codec.pltype); + break; + } + case 32000: { + cng_swb_pltype_ = static_cast(send_codec.pltype); + break; + } + case 48000: { + cng_fb_pltype_ = static_cast(send_codec.pltype); + break; + } + default: { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "RegisterSendCodec() failed, invalid frequency for CNG " + "registration"); + return -1; + } + } + SetCngPayloadType(send_codec.plfreq, send_codec.pltype); + return 0; + } + + // Set Stereo, and make sure VAD and DTX is turned off. + if (send_codec.channels == 2) { + stereo_send_ = true; + if (vad_enabled_ || dtx_enabled_) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, dummy_id, + "VAD/DTX is turned off, not supported when sending stereo."); + } + vad_enabled_ = false; + dtx_enabled_ = false; + } else { + stereo_send_ = false; + } + + // Check if the codec is already registered as send codec. + bool is_send_codec; + if (current_encoder_) { + int send_codec_mirror_id; + int send_codec_id = + ACMCodecDB::CodecNumber(send_codec_inst_, &send_codec_mirror_id); + assert(send_codec_id >= 0); + is_send_codec = + (send_codec_id == codec_id) || (mirror_id == send_codec_mirror_id); + } else { + is_send_codec = false; + } + + // If new codec, or new settings, register. + if (!is_send_codec) { + if (!codecs_[mirror_id]) { + codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance( + send_codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, + cng_fb_pltype_, red_enabled_, red_nb_pltype_); + if (!codecs_[mirror_id]) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Cannot Create the codec"); + return -1; + } + mirror_codec_idx_[mirror_id] = mirror_id; + } + + if (mirror_id != codec_id) { + codecs_[codec_id] = codecs_[mirror_id]; + mirror_codec_idx_[codec_id] = mirror_id; + } + + ACMGenericCodec* codec_ptr = codecs_[codec_id]; + WebRtcACMCodecParams codec_params; + + memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst)); + codec_params.enable_vad = vad_enabled_; + codec_params.enable_dtx = dtx_enabled_; + codec_params.vad_mode = vad_mode_; + // Force initialization. + if (codec_ptr->InitEncoder(&codec_params, true) < 0) { + // Could not initialize the encoder. + + // Check if already have a registered codec. + // Depending on that different messages are logged. + if (!current_encoder_) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Cannot Initialize the encoder No Encoder is registered"); + } else { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Cannot Initialize the encoder, continue encoding with " + "the previously registered codec"); + } + return -1; + } + + // Update states. + dtx_enabled_ = codec_params.enable_dtx; + vad_enabled_ = codec_params.enable_vad; + vad_mode_ = codec_params.vad_mode; + + // Everything is fine so we can replace the previous codec with this one. + if (current_encoder_) { + // If we change codec we start fresh with RED. + // This is not strictly required by the standard. + + if (codec_ptr->SetCopyRed(red_enabled_) < 0) { + // We tried to preserve the old red status, if failed, it means the + // red status has to be flipped. + red_enabled_ = !red_enabled_; + } + + codec_ptr->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_); + + if (!codec_ptr->HasInternalFEC()) { + codec_fec_enabled_ = false; + } else { + if (codec_ptr->SetFEC(codec_fec_enabled_) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Cannot set codec FEC"); + return -1; + } + } + } + + current_encoder_ = codecs_[codec_id]; + DCHECK(current_encoder_); + memcpy(&send_codec_inst_, &send_codec, sizeof(CodecInst)); + return 0; + } else { + // If codec is the same as already registered check if any parameters + // has changed compared to the current values. + // If any parameter is valid then apply it and record. + bool force_init = false; + + if (mirror_id != codec_id) { + codecs_[codec_id] = codecs_[mirror_id]; + mirror_codec_idx_[codec_id] = mirror_id; + } + + // Check the payload type. + if (send_codec.pltype != send_codec_inst_.pltype) { + // At this point check if the given payload type is valid. + // Record it later when the sampling frequency is changed + // successfully. + if (!ACMCodecDB::ValidPayloadType(send_codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Out of range payload type"); + return -1; + } + } + + // If there is a codec that ONE instance of codec supports multiple + // sampling frequencies, then we need to take care of it here. + // one such a codec is iSAC. Both WB and SWB are encoded and decoded + // with one iSAC instance. Therefore, we need to update the encoder + // frequency if required. + if (send_codec_inst_.plfreq != send_codec.plfreq) { + force_init = true; + } + + // If packet size or number of channels has changed, we need to + // re-initialize the encoder. + if (send_codec_inst_.pacsize != send_codec.pacsize) { + force_init = true; + } + if (send_codec_inst_.channels != send_codec.channels) { + force_init = true; + } + + if (force_init) { + WebRtcACMCodecParams codec_params; + + memcpy(&(codec_params.codec_inst), &send_codec, sizeof(CodecInst)); + codec_params.enable_vad = vad_enabled_; + codec_params.enable_dtx = dtx_enabled_; + codec_params.vad_mode = vad_mode_; + + // Force initialization. + if (current_encoder_->InitEncoder(&codec_params, true) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Could not change the codec packet-size."); + return -1; + } + + send_codec_inst_.plfreq = send_codec.plfreq; + send_codec_inst_.pacsize = send_codec.pacsize; + send_codec_inst_.channels = send_codec.channels; + } + + // If the change of sampling frequency has been successful then + // we store the payload-type. + send_codec_inst_.pltype = send_codec.pltype; + + // Check if a change in Rate is required. + if (send_codec.rate != send_codec_inst_.rate) { + if (codecs_[codec_id]->SetBitRate(send_codec.rate) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, dummy_id, + "Could not change the codec rate."); + return -1; + } + send_codec_inst_.rate = send_codec.rate; + } + + 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, dummy_id, + "Cannot set codec FEC"); + return -1; + } + } + + return 0; + } +} + +int CodecManager::SendCodec(CodecInst* current_codec) const { + int dummy_id = 0; + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, + "SendCodec()"); + + if (!current_encoder_) { + WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, dummy_id, + "SendCodec Failed, no codec is registered"); + return -1; + } + WebRtcACMCodecParams encoder_param; + current_encoder_->EncoderParams(&encoder_param); + encoder_param.codec_inst.pltype = send_codec_inst_.pltype; + memcpy(current_codec, &(encoder_param.codec_inst), sizeof(CodecInst)); + + return 0; +} + +// Register possible receive codecs, can be called multiple times, +// for codecs, CNG (NB, WB and SWB), DTMF, RED. +int CodecManager::RegisterReceiveCodec(const CodecInst& codec) { + if (codec.channels > 2 || codec.channels < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Unsupported number of channels, %d.", codec.channels); + return -1; + } + + int mirror_id; + int codec_id = ACMCodecDB::ReceiverCodecNumber(codec, &mirror_id); + + if (codec_id < 0 || codec_id >= ACMCodecDB::kNumCodecs) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Wrong codec params to be registered as receive codec"); + return -1; + } + + // Check if the payload-type is valid. + if (!ACMCodecDB::ValidPayloadType(codec.pltype)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Invalid payload-type %d for %s.", codec.pltype, codec.plname); + return -1; + } + + AudioDecoder* decoder = NULL; + // Get |decoder| associated with |codec|. |decoder| can be NULL if |codec| + // does not own its decoder. + if (GetAudioDecoder(codec, codec_id, mirror_id, &decoder) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Wrong codec params to be registered as receive codec"); + return -1; + } + uint8_t payload_type = static_cast(codec.pltype); + return acm_->RegisterDecoder(codec_id, payload_type, codec.channels, decoder); +} + +bool CodecManager::SetCopyRed(bool enable) { + if (enable && codec_fec_enabled_) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, + "Codec internal FEC and RED cannot be co-enabled."); + return false; + } + if (current_encoder_ && current_encoder_->SetCopyRed(enable) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "SetCopyRed failed"); + return false; + } + red_enabled_ = enable; + return true; +} + +int CodecManager::SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode mode) { + // Sanity check of the mode. + if ((mode != VADNormal) && (mode != VADLowBitrate) && (mode != VADAggr) && + (mode != VADVeryAggr)) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Invalid VAD Mode %d, no change is made to VAD/DTX status", + mode); + return -1; + } + + // Check that the send codec is mono. We don't support VAD/DTX for stereo + // sending. + if ((enable_dtx || enable_vad) && stereo_send_) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "VAD/DTX not supported for stereo sending"); + dtx_enabled_ = false; + vad_enabled_ = false; + vad_mode_ = mode; + return -1; + } + + // Store VAD/DTX settings. Values can be changed in the call to "SetVAD" + // below. + dtx_enabled_ = enable_dtx; + vad_enabled_ = enable_vad; + vad_mode_ = mode; + + // If a send codec is registered, set VAD/DTX for the codec. + if (current_encoder_ && + current_encoder_->SetVAD(&dtx_enabled_, &vad_enabled_, &vad_mode_) < 0) { + // SetVAD failed. + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "SetVAD failed"); + vad_enabled_ = false; + dtx_enabled_ = false; + return -1; + } + return 0; +} + +void CodecManager::VAD(bool* dtx_enabled, + bool* vad_enabled, + ACMVADMode* mode) const { + *dtx_enabled = dtx_enabled_; + *vad_enabled = vad_enabled_; + *mode = vad_mode_; +} + +int CodecManager::SetCodecFEC(bool enable_codec_fec) { + if (enable_codec_fec == true && red_enabled_ == true) { + WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0, + "Codec internal FEC and RED cannot be co-enabled."); + return -1; + } + + // Set codec FEC. + if (current_encoder_ && current_encoder_->SetFEC(enable_codec_fec) < 0) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Set codec internal FEC failed."); + return -1; + } + codec_fec_enabled_ = enable_codec_fec; + return 0; +} + +void CodecManager::SetCngPayloadType(int sample_rate_hz, int payload_type) { + for (auto* codec : codecs_) { + if (codec) { + codec->SetCngPt(sample_rate_hz, payload_type); + } + } +} + +void CodecManager::SetRedPayloadType(int sample_rate_hz, int payload_type) { + for (auto* codec : codecs_) { + if (codec) { + codec->SetRedPt(sample_rate_hz, payload_type); + } + } +} + +int CodecManager::GetAudioDecoder(const CodecInst& codec, + int codec_id, + int mirror_id, + AudioDecoder** decoder) { + if (ACMCodecDB::OwnsDecoder(codec_id)) { + // This codec has to own its own decoder. Therefore, it should create the + // corresponding AudioDecoder class and insert it into NetEq. If the codec + // does not exist create it. + // + // TODO(turajs): this part of the code is common with RegisterSendCodec(), + // make a method for it. + if (codecs_[mirror_id] == NULL) { + codecs_[mirror_id] = ACMCodecDB::CreateCodecInstance( + codec, cng_nb_pltype_, cng_wb_pltype_, cng_swb_pltype_, + cng_fb_pltype_, red_enabled_, red_nb_pltype_); + if (codecs_[mirror_id] == NULL) { + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0, + "Cannot Create the codec"); + return -1; + } + mirror_codec_idx_[mirror_id] = mirror_id; + } + + if (mirror_id != codec_id) { + codecs_[codec_id] = codecs_[mirror_id]; + mirror_codec_idx_[codec_id] = mirror_id; + } + *decoder = codecs_[codec_id]->Decoder(); + if (!*decoder) { + assert(false); + return -1; + } + } else { + *decoder = NULL; + } + + return 0; +} + +} // namespace acm2 +} // namespace webrtc diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h new file mode 100644 index 0000000000..8d5350d71e --- /dev/null +++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 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_ACM2_CODEC_MANAGER_H_ +#define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_CODEC_MANAGER_H_ + +#include "webrtc/base/constructormagic.h" +#include "webrtc/base/thread_checker.h" +#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" +#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h" +#include "webrtc/common_types.h" + +namespace webrtc { + +class AudioDecoder; + +namespace acm2 { + +class ACMGenericCodec; +class AudioCodingModuleImpl; + +class CodecManager final { + public: + explicit CodecManager(AudioCodingModuleImpl* acm); + ~CodecManager(); + + int RegisterSendCodec(const CodecInst& send_codec); + + int SendCodec(CodecInst* current_codec) const; + + int RegisterReceiveCodec(const CodecInst& receive_codec); + + bool SetCopyRed(bool enable); + + int SetVAD(bool enable_dtx, bool enable_vad, ACMVADMode mode); + + void VAD(bool* dtx_enabled, bool* vad_enabled, ACMVADMode* mode) const; + + int SetCodecFEC(bool enable_codec_fec); + + bool stereo_send() const { return stereo_send_; } + + bool red_enabled() const { return red_enabled_; } + + bool codec_fec_enabled() const { return codec_fec_enabled_; } + + ACMGenericCodec* current_encoder() { return current_encoder_; } + + const ACMGenericCodec* current_encoder() const { return current_encoder_; } + + private: + void SetCngPayloadType(int sample_rate_hz, int payload_type); + + void SetRedPayloadType(int sample_rate_hz, int payload_type); + + // Get a pointer to AudioDecoder of the given codec. For some codecs, e.g. + // iSAC, encoding and decoding have to be performed on a shared + // codec-instance. By calling this method, we get the codec-instance that ACM + // owns, then pass that to NetEq. This way, we perform both encoding and + // decoding on the same codec-instance. Furthermore, ACM would have control + // over decoder functionality if required. If |codec| does not share an + // instance between encoder and decoder, the |*decoder| is set NULL. + // The field ACMCodecDB::CodecSettings.owns_decoder indicates that if a + // codec owns the decoder-instance. For such codecs |*decoder| should be a + // valid pointer, otherwise it will be NULL. + int GetAudioDecoder(const CodecInst& codec, + int codec_id, + int mirror_id, + AudioDecoder** decoder); + + AudioCodingModuleImpl* acm_; + rtc::ThreadChecker thread_checker_; + uint8_t cng_nb_pltype_; + uint8_t cng_wb_pltype_; + uint8_t cng_swb_pltype_; + uint8_t cng_fb_pltype_; + uint8_t red_nb_pltype_; + bool stereo_send_; + bool vad_enabled_; + bool dtx_enabled_; + ACMVADMode vad_mode_; + ACMGenericCodec* current_encoder_; + CodecInst send_codec_inst_; + bool red_enabled_; + bool codec_fec_enabled_; + ACMGenericCodec* codecs_[ACMCodecDB::kMaxNumCodecs]; + int mirror_codec_idx_[ACMCodecDB::kMaxNumCodecs]; + + DISALLOW_COPY_AND_ASSIGN(CodecManager); +}; + +} // namespace acm2 +} // namespace webrtc +#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_CODEC_MANAGER_H_ 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 014b9f3d89..796444e78b 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h @@ -190,20 +190,6 @@ class AudioCodingModule { // Sender // - /////////////////////////////////////////////////////////////////////////// - // int32_t InitializeSender() - // Any encoder-related state of ACM will be initialized to the - // same state when ACM is created. This will not interrupt or - // effect decoding functionality of ACM. ACM will lose all the - // encoding-related settings by calling this function. - // For instance, a send codec has to be registered again. - // - // Return value: - // -1 if failed to initialize, - // 0 if succeeded. - // - virtual int32_t InitializeSender() = 0; - /////////////////////////////////////////////////////////////////////////// // int32_t ResetEncoder() // This API resets the states of encoder. All the encoder settings, such as diff --git a/webrtc/modules/audio_coding/main/test/APITest.cc b/webrtc/modules/audio_coding/main/test/APITest.cc index ccb5c59b6e..1cdf6c753a 100644 --- a/webrtc/modules/audio_coding/main/test/APITest.cc +++ b/webrtc/modules/audio_coding/main/test/APITest.cc @@ -1144,9 +1144,6 @@ void APITest::ChangeCodec(char side) { WriteLockScoped wl(_apiTestRWLock); *thereIsEncoder = false; } - CHECK_ERROR_MT(myACM->InitializeSender()); - Wait(1000); - // After Initialization CN is lost, re-register them if (AudioCodingModule::Codec("CN", &myCodec, 8000, 1) >= 0) { CHECK_ERROR_MT(myACM->RegisterSendCodec(myCodec)); diff --git a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc index b785cc301f..8394bc03ab 100644 --- a/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc +++ b/webrtc/modules/audio_coding/main/test/EncodeDecodeTest.cc @@ -53,7 +53,6 @@ Sender::Sender() 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; diff --git a/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc b/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc index f4db1db3da..1014fc9d0a 100644 --- a/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc +++ b/webrtc/modules/audio_coding/main/test/TwoWayCommunication.cc @@ -281,7 +281,6 @@ void TwoWayCommunication::Perform() { // In the middle of a session with data flowing between two sides, called A // and B, APIs will be called, like ResetEncoder(), and the code should // continue to run, and be able to recover. - bool expect_error_add = false; while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) { msecPassed += 10; EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0); @@ -290,12 +289,7 @@ void TwoWayCommunication::Perform() { EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0); - // Expect call to pass except for the time when no send codec is registered. - if (!expect_error_add) { - EXPECT_GE(_acmB->Add10MsData(audioFrame), 0); - } else { - EXPECT_EQ(-1, _acmB->Add10MsData(audioFrame)); - } + EXPECT_GE(_acmB->Add10MsData(audioFrame), 0); EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0); EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame)); _outFileA.Write10MsData(audioFrame); @@ -315,14 +309,11 @@ void TwoWayCommunication::Perform() { // side B. if (((secPassed % 5) == 4) && (msecPassed == 0)) { EXPECT_EQ(0, _acmA->ResetEncoder()); - EXPECT_EQ(0, _acmB->InitializeSender()); - expect_error_add = true; } // Re-register send codec on side B. if (((secPassed % 5) == 4) && (msecPassed >= 990)) { EXPECT_EQ(0, _acmB->RegisterSendCodec(codecInst_B)); EXPECT_EQ(0, _acmB->SendCodec(&dummy)); - expect_error_add = false; } // Reset decoder on side B, and initialize receiver on side A. if (((secPassed % 7) == 6) && (msecPassed == 0)) { diff --git a/webrtc/modules/utility/source/coder.cc b/webrtc/modules/utility/source/coder.cc index b106c75242..dc0799a245 100644 --- a/webrtc/modules/utility/source/coder.cc +++ b/webrtc/modules/utility/source/coder.cc @@ -21,7 +21,6 @@ AudioCoder::AudioCoder(uint32_t instanceID) _encodedLengthInBytes(0), _decodeTimestamp(0) { - _acm->InitializeSender(); _acm->InitializeReceiver(); _acm->RegisterTransportCallback(this); } diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index 719cc35a5f..472ed8b7fe 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -953,12 +953,12 @@ Channel::Init() // --- ACM initialization - if ((audio_coding_->InitializeReceiver() == -1) || + if ((audio_coding_->InitializeReceiver() == -1) #ifdef WEBRTC_CODEC_AVT // out-of-band Dtmf tones are played out by default - (audio_coding_->SetDtmfPlayoutStatus(true) == -1) || + || (audio_coding_->SetDtmfPlayoutStatus(true) == -1) #endif - (audio_coding_->InitializeSender() == -1)) + ) { _engineStatisticsPtr->SetLastError( VE_AUDIO_CODING_MODULE_ERROR, kTraceError,