From 805fc710f7fb1b399bcfae70c8b484a77b49267f Mon Sep 17 00:00:00 2001 From: kwiberg Date: Tue, 10 Nov 2015 04:05:16 -0800 Subject: [PATCH] =?UTF-8?q?Let=20Rent-A-Codec=E2=84=A2=20create=20and=20ow?= =?UTF-8?q?n=20speech=20encoders?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=webrtc:5028 Review URL: https://codereview.webrtc.org/1410333015 Cr-Commit-Position: refs/heads/master@{#10575} --- .../audio_coding/main/acm2/codec_owner.cc | 104 ++---------------- .../audio_coding/main/acm2/codec_owner.h | 26 +---- .../audio_coding/main/acm2/rent_a_codec.cc | 89 +++++++++++++++ .../audio_coding/main/acm2/rent_a_codec.h | 33 ++++++ 4 files changed, 137 insertions(+), 115 deletions(-) diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc index df9a992dac..43f684ec7f 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_owner.cc +++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.cc @@ -14,25 +14,6 @@ #include "webrtc/base/logging.h" #include "webrtc/engine_configurations.h" #include "webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h" -#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h" -#ifdef WEBRTC_CODEC_G722 -#include "webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h" -#endif -#ifdef WEBRTC_CODEC_ILBC -#include "webrtc/modules/audio_coding/codecs/ilbc/include/audio_encoder_ilbc.h" -#endif -#ifdef WEBRTC_CODEC_ISACFX -#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" -#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h" -#endif -#ifdef WEBRTC_CODEC_ISAC -#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" -#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" -#endif -#ifdef WEBRTC_CODEC_OPUS -#include "webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h" -#endif -#include "webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h" #ifdef WEBRTC_CODEC_RED #include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h" #endif @@ -40,60 +21,13 @@ namespace webrtc { namespace acm2 { -CodecOwner::CodecOwner() : external_speech_encoder_(nullptr) { +CodecOwner::CodecOwner() : speech_encoder_(nullptr) { } CodecOwner::~CodecOwner() = default; namespace { -rtc::scoped_ptr CreateIsacDecoder( - LockedIsacBandwidthInfo* bwinfo) { -#if defined(WEBRTC_CODEC_ISACFX) - return rtc_make_scoped_ptr(new AudioDecoderIsacFix(bwinfo)); -#elif defined(WEBRTC_CODEC_ISAC) - return rtc_make_scoped_ptr(new AudioDecoderIsac(bwinfo)); -#else - FATAL() << "iSAC is not supported."; - return rtc::scoped_ptr(); -#endif -} - -// Returns a new speech encoder, or null on error. -// TODO(kwiberg): Don't handle errors here (bug 5033) -rtc::scoped_ptr CreateSpeechEncoder( - const CodecInst& speech_inst, - LockedIsacBandwidthInfo* bwinfo) { -#if defined(WEBRTC_CODEC_ISACFX) - if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) - return rtc_make_scoped_ptr(new AudioEncoderIsacFix(speech_inst, bwinfo)); -#endif -#if defined(WEBRTC_CODEC_ISAC) - if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) - return rtc_make_scoped_ptr(new AudioEncoderIsac(speech_inst, bwinfo)); -#endif -#ifdef WEBRTC_CODEC_OPUS - if (STR_CASE_CMP(speech_inst.plname, "opus") == 0) - return rtc_make_scoped_ptr(new AudioEncoderOpus(speech_inst)); -#endif - if (STR_CASE_CMP(speech_inst.plname, "pcmu") == 0) - return rtc_make_scoped_ptr(new AudioEncoderPcmU(speech_inst)); - if (STR_CASE_CMP(speech_inst.plname, "pcma") == 0) - return rtc_make_scoped_ptr(new AudioEncoderPcmA(speech_inst)); - if (STR_CASE_CMP(speech_inst.plname, "l16") == 0) - return rtc_make_scoped_ptr(new AudioEncoderPcm16B(speech_inst)); -#ifdef WEBRTC_CODEC_ILBC - if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0) - return rtc_make_scoped_ptr(new AudioEncoderIlbc(speech_inst)); -#endif -#ifdef WEBRTC_CODEC_G722 - if (STR_CASE_CMP(speech_inst.plname, "g722") == 0) - return rtc_make_scoped_ptr(new AudioEncoderG722(speech_inst)); -#endif - LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname; - return rtc::scoped_ptr(); -} - AudioEncoder* CreateRedEncoder(int red_payload_type, AudioEncoder* encoder, rtc::scoped_ptr* red_encoder) { @@ -147,11 +81,10 @@ bool CodecOwner::SetEncoders(const CodecInst& speech_inst, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { - speech_encoder_ = CreateSpeechEncoder(speech_inst, &isac_bandwidth_info_); - if (!speech_encoder_) + AudioEncoder* speech_encoder = rent_a_codec_.RentEncoder(speech_inst); + if (!speech_encoder) return false; - external_speech_encoder_ = nullptr; - ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type); + SetEncoders(speech_encoder, cng_payload_type, vad_mode, red_payload_type); return true; } @@ -159,30 +92,26 @@ void CodecOwner::SetEncoders(AudioEncoder* external_speech_encoder, int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { - external_speech_encoder_ = external_speech_encoder; - speech_encoder_.reset(); + speech_encoder_ = external_speech_encoder; ChangeCngAndRed(cng_payload_type, vad_mode, red_payload_type); } void CodecOwner::ChangeCngAndRed(int cng_payload_type, ACMVADMode vad_mode, int red_payload_type) { - AudioEncoder* speech_encoder = SpeechEncoder(); + RTC_DCHECK(speech_encoder_); if (cng_payload_type != -1 || red_payload_type != -1) { // The RED and CNG encoders need to be in sync with the speech encoder, so // reset the latter to ensure its buffer is empty. - speech_encoder->Reset(); + speech_encoder_->Reset(); } - AudioEncoder* encoder = - CreateRedEncoder(red_payload_type, speech_encoder, &red_encoder_); + AudioEncoder* encoder = CreateRedEncoder( + red_payload_type, speech_encoder_, &red_encoder_); CreateCngEncoder(cng_payload_type, vad_mode, encoder, &cng_encoder_); - RTC_DCHECK_EQ(!!speech_encoder_ + !!external_speech_encoder_, 1); } AudioDecoder* CodecOwner::GetIsacDecoder() { - if (!isac_decoder_) - isac_decoder_ = CreateIsacDecoder(&isac_bandwidth_info_); - return isac_decoder_.get(); + return rent_a_codec_.RentIsacDecoder(); } AudioEncoder* CodecOwner::Encoder() { @@ -195,18 +124,7 @@ const AudioEncoder* CodecOwner::Encoder() const { return cng_encoder_.get(); if (red_encoder_) return red_encoder_.get(); - return SpeechEncoder(); -} - -AudioEncoder* CodecOwner::SpeechEncoder() { - const auto* const_this = this; - return const_cast(const_this->SpeechEncoder()); -} - -const AudioEncoder* CodecOwner::SpeechEncoder() const { - RTC_DCHECK(!speech_encoder_ || !external_speech_encoder_); - return external_speech_encoder_ ? external_speech_encoder_ - : speech_encoder_.get(); + return speech_encoder_; } } // namespace acm2 diff --git a/webrtc/modules/audio_coding/main/acm2/codec_owner.h b/webrtc/modules/audio_coding/main/acm2/codec_owner.h index d0fb4f760e..29ac098906 100644 --- a/webrtc/modules/audio_coding/main/acm2/codec_owner.h +++ b/webrtc/modules/audio_coding/main/acm2/codec_owner.h @@ -16,17 +16,9 @@ #include "webrtc/common_types.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h" #include "webrtc/modules/audio_coding/codecs/audio_decoder.h" +#include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.h" -#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX) -#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h" -#else -// Dummy implementation, for when we don't have iSAC. -namespace webrtc { -class LockedIsacBandwidthInfo {}; -} -#endif - namespace webrtc { namespace acm2 { @@ -59,25 +51,15 @@ class CodecOwner { const AudioEncoder* Encoder() const; private: - AudioEncoder* SpeechEncoder(); - const AudioEncoder* SpeechEncoder() const; - - // At most one of these is non-null: - rtc::scoped_ptr speech_encoder_; - AudioEncoder* external_speech_encoder_; - - // If we've created an iSAC decoder because someone called GetIsacDecoder, - // store it here. - rtc::scoped_ptr isac_decoder_; - - // iSAC bandwidth estimation info, for use with iSAC encoders and decoders. - LockedIsacBandwidthInfo isac_bandwidth_info_; + AudioEncoder* speech_encoder_; // |cng_encoder_| and |red_encoder_| are valid iff CNG or RED, respectively, // are active. rtc::scoped_ptr cng_encoder_; rtc::scoped_ptr red_encoder_; + RentACodec rent_a_codec_; + RTC_DISALLOW_COPY_AND_ASSIGN(CodecOwner); }; diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc index 2a6c37ff36..a056f78e0b 100644 --- a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc +++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc @@ -10,6 +10,26 @@ #include "webrtc/modules/audio_coding/main/acm2/rent_a_codec.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h" +#ifdef WEBRTC_CODEC_G722 +#include "webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h" +#endif +#ifdef WEBRTC_CODEC_ILBC +#include "webrtc/modules/audio_coding/codecs/ilbc/include/audio_encoder_ilbc.h" +#endif +#ifdef WEBRTC_CODEC_ISACFX +#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" +#include "webrtc/modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h" +#endif +#ifdef WEBRTC_CODEC_ISAC +#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" +#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" +#endif +#ifdef WEBRTC_CODEC_OPUS +#include "webrtc/modules/audio_coding/codecs/opus/include/audio_encoder_opus.h" +#endif +#include "webrtc/modules/audio_coding/codecs/pcm16b/include/audio_encoder_pcm16b.h" #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h" @@ -80,5 +100,74 @@ rtc::Maybe RentACodec::NetEqDecoderFromCodecId(CodecId codec_id, : ned); } +namespace { + +// Returns a new speech encoder, or null on error. +// TODO(kwiberg): Don't handle errors here (bug 5033) +rtc::scoped_ptr CreateEncoder( + const CodecInst& speech_inst, + LockedIsacBandwidthInfo* bwinfo) { +#if defined(WEBRTC_CODEC_ISACFX) + if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) + return rtc_make_scoped_ptr(new AudioEncoderIsacFix(speech_inst, bwinfo)); +#endif +#if defined(WEBRTC_CODEC_ISAC) + if (STR_CASE_CMP(speech_inst.plname, "isac") == 0) + return rtc_make_scoped_ptr(new AudioEncoderIsac(speech_inst, bwinfo)); +#endif +#ifdef WEBRTC_CODEC_OPUS + if (STR_CASE_CMP(speech_inst.plname, "opus") == 0) + return rtc_make_scoped_ptr(new AudioEncoderOpus(speech_inst)); +#endif + if (STR_CASE_CMP(speech_inst.plname, "pcmu") == 0) + return rtc_make_scoped_ptr(new AudioEncoderPcmU(speech_inst)); + if (STR_CASE_CMP(speech_inst.plname, "pcma") == 0) + return rtc_make_scoped_ptr(new AudioEncoderPcmA(speech_inst)); + if (STR_CASE_CMP(speech_inst.plname, "l16") == 0) + return rtc_make_scoped_ptr(new AudioEncoderPcm16B(speech_inst)); +#ifdef WEBRTC_CODEC_ILBC + if (STR_CASE_CMP(speech_inst.plname, "ilbc") == 0) + return rtc_make_scoped_ptr(new AudioEncoderIlbc(speech_inst)); +#endif +#ifdef WEBRTC_CODEC_G722 + if (STR_CASE_CMP(speech_inst.plname, "g722") == 0) + return rtc_make_scoped_ptr(new AudioEncoderG722(speech_inst)); +#endif + LOG_F(LS_ERROR) << "Could not create encoder of type " << speech_inst.plname; + return rtc::scoped_ptr(); +} + +rtc::scoped_ptr CreateIsacDecoder( + LockedIsacBandwidthInfo* bwinfo) { +#if defined(WEBRTC_CODEC_ISACFX) + return rtc_make_scoped_ptr(new AudioDecoderIsacFix(bwinfo)); +#elif defined(WEBRTC_CODEC_ISAC) + return rtc_make_scoped_ptr(new AudioDecoderIsac(bwinfo)); +#else + FATAL() << "iSAC is not supported."; + return rtc::scoped_ptr(); +#endif +} + +} // namespace + +RentACodec::RentACodec() = default; +RentACodec::~RentACodec() = default; + +AudioEncoder* RentACodec::RentEncoder(const CodecInst& codec_inst) { + rtc::scoped_ptr enc = + CreateEncoder(codec_inst, &isac_bandwidth_info_); + if (!enc) + return nullptr; + encoder_ = enc.Pass(); + return encoder_.get(); +} + +AudioDecoder* RentACodec::RentIsacDecoder() { + if (!isac_decoder_) + isac_decoder_ = CreateIsacDecoder(&isac_bandwidth_info_); + return isac_decoder_.get(); +} + } // namespace acm2 } // namespace webrtc diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h index 2c85bcf51c..e74ad08996 100644 --- a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h +++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h @@ -14,8 +14,21 @@ #include #include "webrtc/base/array_view.h" +#include "webrtc/base/constructormagic.h" #include "webrtc/base/maybe.h" +#include "webrtc/base/scoped_ptr.h" #include "webrtc/typedefs.h" +#include "webrtc/modules/audio_coding/codecs/audio_encoder.h" +#include "webrtc/modules/audio_coding/codecs/audio_decoder.h" + +#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX) +#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h" +#else +// Dummy implementation, for when we don't have iSAC. +namespace webrtc { +class LockedIsacBandwidthInfo {}; +} +#endif namespace webrtc { @@ -165,6 +178,26 @@ class RentACodec { static rtc::Maybe NetEqDecoderFromCodecId(CodecId codec_id, int num_channels); + + RentACodec(); + ~RentACodec(); + + // Creates and returns an audio encoder built to the given specification. + // Returns null in case of error. The returned encoder is live until the next + // successful call to this function, or until the Rent-A-Codec is destroyed. + AudioEncoder* RentEncoder(const CodecInst& codec_inst); + + // Creates and returns an iSAC decoder, which will remain live until the + // Rent-A-Codec is destroyed. Subsequent calls will simply return the same + // object. + AudioDecoder* RentIsacDecoder(); + + private: + rtc::scoped_ptr encoder_; + rtc::scoped_ptr isac_decoder_; + LockedIsacBandwidthInfo isac_bandwidth_info_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RentACodec); }; } // namespace acm2