Let Rent-A-Codec™ create and own speech encoders
BUG=webrtc:5028 Review URL: https://codereview.webrtc.org/1410333015 Cr-Commit-Position: refs/heads/master@{#10575}
This commit is contained in:
@ -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<AudioDecoder> 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<AudioDecoder>();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns a new speech encoder, or null on error.
|
||||
// TODO(kwiberg): Don't handle errors here (bug 5033)
|
||||
rtc::scoped_ptr<AudioEncoder> 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>();
|
||||
}
|
||||
|
||||
AudioEncoder* CreateRedEncoder(int red_payload_type,
|
||||
AudioEncoder* encoder,
|
||||
rtc::scoped_ptr<AudioEncoder>* 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<AudioEncoder*>(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
|
||||
|
||||
@ -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<AudioEncoder> speech_encoder_;
|
||||
AudioEncoder* external_speech_encoder_;
|
||||
|
||||
// If we've created an iSAC decoder because someone called GetIsacDecoder,
|
||||
// store it here.
|
||||
rtc::scoped_ptr<AudioDecoder> 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<AudioEncoder> cng_encoder_;
|
||||
rtc::scoped_ptr<AudioEncoder> red_encoder_;
|
||||
|
||||
RentACodec rent_a_codec_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(CodecOwner);
|
||||
};
|
||||
|
||||
|
||||
@ -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<NetEqDecoder> 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<AudioEncoder> 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<AudioEncoder>();
|
||||
}
|
||||
|
||||
rtc::scoped_ptr<AudioDecoder> 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<AudioDecoder>();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RentACodec::RentACodec() = default;
|
||||
RentACodec::~RentACodec() = default;
|
||||
|
||||
AudioEncoder* RentACodec::RentEncoder(const CodecInst& codec_inst) {
|
||||
rtc::scoped_ptr<AudioEncoder> 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
|
||||
|
||||
@ -14,8 +14,21 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#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<NetEqDecoder> 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<AudioEncoder> encoder_;
|
||||
rtc::scoped_ptr<AudioDecoder> isac_decoder_;
|
||||
LockedIsacBandwidthInfo isac_bandwidth_info_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RentACodec);
|
||||
};
|
||||
|
||||
} // namespace acm2
|
||||
|
||||
Reference in New Issue
Block a user