Add speech encoder to the encoder stack specification struct

BUG=webrtc:5028

Review URL: https://codereview.webrtc.org/1527933002

Cr-Commit-Position: refs/heads/master@{#11037}
This commit is contained in:
kwiberg
2015-12-15 14:21:33 -08:00
committed by Commit bot
parent 7eb914debb
commit 95d9851a6c
4 changed files with 45 additions and 31 deletions

View File

@ -165,7 +165,8 @@ int CodecManager::RegisterEncoder(const CodecInst& send_codec) {
AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
if (!enc)
return -1;
rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
codec_stack_params_.speech_encoder = enc;
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
RTC_DCHECK(CurrentEncoder());
}
@ -187,7 +188,8 @@ void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) {
static const char kName[] = "external";
memcpy(send_codec_inst_.plname, kName, sizeof(kName));
rent_a_codec_.RentEncoderStack(external_speech_encoder, &codec_stack_params_);
codec_stack_params_.speech_encoder = external_speech_encoder;
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
}
rtc::Optional<CodecInst> CodecManager::GetCodecInst() const {
@ -219,8 +221,7 @@ bool CodecManager::SetCopyRed(bool enable) {
if (codec_stack_params_.use_red != enable) {
codec_stack_params_.use_red = enable;
if (CurrentEncoder())
rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(),
&codec_stack_params_);
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
}
return true;
}
@ -232,8 +233,10 @@ int CodecManager::SetVAD(bool enable, ACMVADMode mode) {
// Check that the send codec is mono. We don't support VAD/DTX for stereo
// sending.
auto* enc = rent_a_codec_.GetEncoder();
const bool stereo_send = enc ? (enc->NumChannels() != 1) : false;
const bool stereo_send =
codec_stack_params_.speech_encoder
? (codec_stack_params_.speech_encoder->NumChannels() != 1)
: false;
if (enable && stereo_send) {
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
"VAD/DTX not supported for stereo sending");
@ -252,8 +255,8 @@ int CodecManager::SetVAD(bool enable, ACMVADMode mode) {
codec_stack_params_.vad_mode != mode) {
codec_stack_params_.use_cng = enable;
codec_stack_params_.vad_mode = mode;
if (enc)
rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
if (codec_stack_params_.speech_encoder)
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
}
return 0;
}

View File

@ -249,37 +249,36 @@ RentACodec::StackParameters::StackParameters() {
RentACodec::StackParameters::~StackParameters() = default;
AudioEncoder* RentACodec::RentEncoderStack(AudioEncoder* speech_encoder,
StackParameters* param) {
RTC_DCHECK(speech_encoder);
AudioEncoder* RentACodec::RentEncoderStack(StackParameters* param) {
RTC_DCHECK(param->speech_encoder);
if (param->use_codec_fec) {
// Switch FEC on. On failure, remember that FEC is off.
if (!speech_encoder->SetFec(true))
if (!param->speech_encoder->SetFec(true))
param->use_codec_fec = false;
} else {
// Switch FEC off. This shouldn't fail.
const bool success = speech_encoder->SetFec(false);
const bool success = param->speech_encoder->SetFec(false);
RTC_DCHECK(success);
}
auto pt = [&speech_encoder](const std::map<int, int>& m) {
auto it = m.find(speech_encoder->SampleRateHz());
auto pt = [&param](const std::map<int, int>& m) {
auto it = m.find(param->speech_encoder->SampleRateHz());
return it == m.end() ? rtc::Optional<int>()
: rtc::Optional<int>(it->second);
};
auto cng_pt = pt(param->cng_payload_types);
param->use_cng =
param->use_cng && cng_pt && speech_encoder->NumChannels() == 1;
param->use_cng && cng_pt && param->speech_encoder->NumChannels() == 1;
auto red_pt = pt(param->red_payload_types);
param->use_red = param->use_red && red_pt;
if (param->use_cng || param->use_red) {
// 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();
param->speech_encoder->Reset();
}
encoder_stack_ = speech_encoder;
encoder_stack_ = param->speech_encoder;
if (param->use_red) {
red_encoder_ = CreateRedEncoder(encoder_stack_, *red_pt);
if (red_encoder_)

View File

@ -204,6 +204,7 @@ class RentACodec {
StackParameters();
~StackParameters();
AudioEncoder* speech_encoder = nullptr;
bool use_codec_fec = false;
bool use_red = false;
bool use_cng = false;
@ -219,12 +220,10 @@ class RentACodec {
// will be changed to match (things will be switched off). The returned
// encoder is live until the next successful call to this function, or until
// the Rent-A-Codec is destroyed.
AudioEncoder* RentEncoderStack(AudioEncoder* speech_encoder,
StackParameters* param);
AudioEncoder* RentEncoderStack(StackParameters* param);
// Get the last return values of RentEncoder and RentEncoderStack, or null if
// they haven't been called.
AudioEncoder* GetEncoder() const { return speech_encoder_.get(); }
// The last return value of RentEncoderStack, or null if it hasn't been
// called.
AudioEncoder* GetEncoderStack() const { return encoder_stack_; }
// Creates and returns an iSAC decoder, which will remain live until the

View File

@ -34,7 +34,8 @@ class RentACodecTestF : public ::testing::Test {
ASSERT_TRUE(speech_encoder_);
RentACodec::StackParameters param;
param.use_cng = true;
encoder_ = rent_a_codec_.RentEncoderStack(speech_encoder_, &param);
param.speech_encoder = speech_encoder_;
encoder_ = rent_a_codec_.RentEncoderStack(&param);
}
void EncodeAndVerify(size_t expected_out_length,
@ -110,7 +111,8 @@ TEST(RentACodecTest, ExternalEncoder) {
RentACodec rac;
RentACodec::StackParameters param;
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, &param));
param.speech_encoder = &external_encoder;
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&param));
const int kPacketSizeSamples = kSampleRateHz / 100;
int16_t audio[kPacketSizeSamples] = {0};
uint8_t encoded[kPacketSizeSamples];
@ -140,16 +142,17 @@ TEST(RentACodecTest, ExternalEncoder) {
// Change to internal encoder.
CodecInst codec_inst = kDefaultCodecInst;
codec_inst.pacsize = kPacketSizeSamples;
AudioEncoder* enc = rac.RentEncoder(codec_inst);
ASSERT_TRUE(enc);
EXPECT_EQ(enc, rac.RentEncoderStack(enc, &param));
param.speech_encoder = rac.RentEncoder(codec_inst);
ASSERT_TRUE(param.speech_encoder);
EXPECT_EQ(param.speech_encoder, rac.RentEncoderStack(&param));
// Don't expect any more calls to the external encoder.
info = rac.GetEncoderStack()->Encode(1, audio, arraysize(encoded), encoded);
external_encoder.Mark("B");
// Change back to external encoder again.
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, &param));
param.speech_encoder = &external_encoder;
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&param));
info = rac.GetEncoderStack()->Encode(2, audio, arraysize(encoded), encoded);
EXPECT_EQ(2u, info.encoded_timestamp);
}
@ -173,13 +176,15 @@ void TestCngAndRedResetSpeechEncoder(bool use_cng, bool use_red) {
}
RentACodec::StackParameters param1, param2;
param1.speech_encoder = &speech_encoder;
param2.speech_encoder = &speech_encoder;
param2.use_cng = use_cng;
param2.use_red = use_red;
speech_encoder.Mark("disabled");
RentACodec rac;
rac.RentEncoderStack(&speech_encoder, &param1);
rac.RentEncoderStack(&param1);
speech_encoder.Mark("enabled");
rac.RentEncoderStack(&speech_encoder, &param2);
rac.RentEncoderStack(&param2);
}
TEST(RentACodecTest, CngResetsSpeechEncoder) {
@ -205,5 +210,13 @@ TEST(RentACodecTest, RentEncoderError) {
EXPECT_FALSE(rent_a_codec.RentEncoder(codec_inst));
}
#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST(RentACodecTest, RentEncoderStackWithoutSpeechEncoder) {
RentACodec::StackParameters sp;
EXPECT_EQ(nullptr, sp.speech_encoder);
EXPECT_DEATH(RentACodec().RentEncoderStack(&sp), "");
}
#endif
} // namespace acm2
} // namespace webrtc