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:
@ -165,7 +165,8 @@ int CodecManager::RegisterEncoder(const CodecInst& send_codec) {
|
|||||||
AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
|
AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
|
||||||
if (!enc)
|
if (!enc)
|
||||||
return -1;
|
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());
|
RTC_DCHECK(CurrentEncoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +188,8 @@ void CodecManager::RegisterEncoder(AudioEncoder* external_speech_encoder) {
|
|||||||
static const char kName[] = "external";
|
static const char kName[] = "external";
|
||||||
memcpy(send_codec_inst_.plname, kName, sizeof(kName));
|
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 {
|
rtc::Optional<CodecInst> CodecManager::GetCodecInst() const {
|
||||||
@ -219,8 +221,7 @@ bool CodecManager::SetCopyRed(bool enable) {
|
|||||||
if (codec_stack_params_.use_red != enable) {
|
if (codec_stack_params_.use_red != enable) {
|
||||||
codec_stack_params_.use_red = enable;
|
codec_stack_params_.use_red = enable;
|
||||||
if (CurrentEncoder())
|
if (CurrentEncoder())
|
||||||
rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(),
|
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
|
||||||
&codec_stack_params_);
|
|
||||||
}
|
}
|
||||||
return true;
|
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
|
// Check that the send codec is mono. We don't support VAD/DTX for stereo
|
||||||
// sending.
|
// sending.
|
||||||
auto* enc = rent_a_codec_.GetEncoder();
|
const bool stereo_send =
|
||||||
const bool stereo_send = enc ? (enc->NumChannels() != 1) : false;
|
codec_stack_params_.speech_encoder
|
||||||
|
? (codec_stack_params_.speech_encoder->NumChannels() != 1)
|
||||||
|
: false;
|
||||||
if (enable && stereo_send) {
|
if (enable && stereo_send) {
|
||||||
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
|
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
|
||||||
"VAD/DTX not supported for stereo sending");
|
"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_.vad_mode != mode) {
|
||||||
codec_stack_params_.use_cng = enable;
|
codec_stack_params_.use_cng = enable;
|
||||||
codec_stack_params_.vad_mode = mode;
|
codec_stack_params_.vad_mode = mode;
|
||||||
if (enc)
|
if (codec_stack_params_.speech_encoder)
|
||||||
rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
|
rent_a_codec_.RentEncoderStack(&codec_stack_params_);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -249,37 +249,36 @@ RentACodec::StackParameters::StackParameters() {
|
|||||||
|
|
||||||
RentACodec::StackParameters::~StackParameters() = default;
|
RentACodec::StackParameters::~StackParameters() = default;
|
||||||
|
|
||||||
AudioEncoder* RentACodec::RentEncoderStack(AudioEncoder* speech_encoder,
|
AudioEncoder* RentACodec::RentEncoderStack(StackParameters* param) {
|
||||||
StackParameters* param) {
|
RTC_DCHECK(param->speech_encoder);
|
||||||
RTC_DCHECK(speech_encoder);
|
|
||||||
|
|
||||||
if (param->use_codec_fec) {
|
if (param->use_codec_fec) {
|
||||||
// Switch FEC on. On failure, remember that FEC is off.
|
// 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;
|
param->use_codec_fec = false;
|
||||||
} else {
|
} else {
|
||||||
// Switch FEC off. This shouldn't fail.
|
// 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);
|
RTC_DCHECK(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pt = [&speech_encoder](const std::map<int, int>& m) {
|
auto pt = [¶m](const std::map<int, int>& m) {
|
||||||
auto it = m.find(speech_encoder->SampleRateHz());
|
auto it = m.find(param->speech_encoder->SampleRateHz());
|
||||||
return it == m.end() ? rtc::Optional<int>()
|
return it == m.end() ? rtc::Optional<int>()
|
||||||
: rtc::Optional<int>(it->second);
|
: rtc::Optional<int>(it->second);
|
||||||
};
|
};
|
||||||
auto cng_pt = pt(param->cng_payload_types);
|
auto cng_pt = pt(param->cng_payload_types);
|
||||||
param->use_cng =
|
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);
|
auto red_pt = pt(param->red_payload_types);
|
||||||
param->use_red = param->use_red && red_pt;
|
param->use_red = param->use_red && red_pt;
|
||||||
|
|
||||||
if (param->use_cng || param->use_red) {
|
if (param->use_cng || param->use_red) {
|
||||||
// The RED and CNG encoders need to be in sync with the speech encoder, so
|
// The RED and CNG encoders need to be in sync with the speech encoder, so
|
||||||
// reset the latter to ensure its buffer is empty.
|
// 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) {
|
if (param->use_red) {
|
||||||
red_encoder_ = CreateRedEncoder(encoder_stack_, *red_pt);
|
red_encoder_ = CreateRedEncoder(encoder_stack_, *red_pt);
|
||||||
if (red_encoder_)
|
if (red_encoder_)
|
||||||
|
@ -204,6 +204,7 @@ class RentACodec {
|
|||||||
StackParameters();
|
StackParameters();
|
||||||
~StackParameters();
|
~StackParameters();
|
||||||
|
|
||||||
|
AudioEncoder* speech_encoder = nullptr;
|
||||||
bool use_codec_fec = false;
|
bool use_codec_fec = false;
|
||||||
bool use_red = false;
|
bool use_red = false;
|
||||||
bool use_cng = false;
|
bool use_cng = false;
|
||||||
@ -219,12 +220,10 @@ class RentACodec {
|
|||||||
// will be changed to match (things will be switched off). The returned
|
// 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
|
// encoder is live until the next successful call to this function, or until
|
||||||
// the Rent-A-Codec is destroyed.
|
// the Rent-A-Codec is destroyed.
|
||||||
AudioEncoder* RentEncoderStack(AudioEncoder* speech_encoder,
|
AudioEncoder* RentEncoderStack(StackParameters* param);
|
||||||
StackParameters* param);
|
|
||||||
|
|
||||||
// Get the last return values of RentEncoder and RentEncoderStack, or null if
|
// The last return value of RentEncoderStack, or null if it hasn't been
|
||||||
// they haven't been called.
|
// called.
|
||||||
AudioEncoder* GetEncoder() const { return speech_encoder_.get(); }
|
|
||||||
AudioEncoder* GetEncoderStack() const { return encoder_stack_; }
|
AudioEncoder* GetEncoderStack() const { return encoder_stack_; }
|
||||||
|
|
||||||
// Creates and returns an iSAC decoder, which will remain live until the
|
// Creates and returns an iSAC decoder, which will remain live until the
|
||||||
|
@ -34,7 +34,8 @@ class RentACodecTestF : public ::testing::Test {
|
|||||||
ASSERT_TRUE(speech_encoder_);
|
ASSERT_TRUE(speech_encoder_);
|
||||||
RentACodec::StackParameters param;
|
RentACodec::StackParameters param;
|
||||||
param.use_cng = true;
|
param.use_cng = true;
|
||||||
encoder_ = rent_a_codec_.RentEncoderStack(speech_encoder_, ¶m);
|
param.speech_encoder = speech_encoder_;
|
||||||
|
encoder_ = rent_a_codec_.RentEncoderStack(¶m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeAndVerify(size_t expected_out_length,
|
void EncodeAndVerify(size_t expected_out_length,
|
||||||
@ -110,7 +111,8 @@ TEST(RentACodecTest, ExternalEncoder) {
|
|||||||
|
|
||||||
RentACodec rac;
|
RentACodec rac;
|
||||||
RentACodec::StackParameters param;
|
RentACodec::StackParameters param;
|
||||||
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, ¶m));
|
param.speech_encoder = &external_encoder;
|
||||||
|
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(¶m));
|
||||||
const int kPacketSizeSamples = kSampleRateHz / 100;
|
const int kPacketSizeSamples = kSampleRateHz / 100;
|
||||||
int16_t audio[kPacketSizeSamples] = {0};
|
int16_t audio[kPacketSizeSamples] = {0};
|
||||||
uint8_t encoded[kPacketSizeSamples];
|
uint8_t encoded[kPacketSizeSamples];
|
||||||
@ -140,16 +142,17 @@ TEST(RentACodecTest, ExternalEncoder) {
|
|||||||
// Change to internal encoder.
|
// Change to internal encoder.
|
||||||
CodecInst codec_inst = kDefaultCodecInst;
|
CodecInst codec_inst = kDefaultCodecInst;
|
||||||
codec_inst.pacsize = kPacketSizeSamples;
|
codec_inst.pacsize = kPacketSizeSamples;
|
||||||
AudioEncoder* enc = rac.RentEncoder(codec_inst);
|
param.speech_encoder = rac.RentEncoder(codec_inst);
|
||||||
ASSERT_TRUE(enc);
|
ASSERT_TRUE(param.speech_encoder);
|
||||||
EXPECT_EQ(enc, rac.RentEncoderStack(enc, ¶m));
|
EXPECT_EQ(param.speech_encoder, rac.RentEncoderStack(¶m));
|
||||||
|
|
||||||
// Don't expect any more calls to the external encoder.
|
// Don't expect any more calls to the external encoder.
|
||||||
info = rac.GetEncoderStack()->Encode(1, audio, arraysize(encoded), encoded);
|
info = rac.GetEncoderStack()->Encode(1, audio, arraysize(encoded), encoded);
|
||||||
external_encoder.Mark("B");
|
external_encoder.Mark("B");
|
||||||
|
|
||||||
// Change back to external encoder again.
|
// Change back to external encoder again.
|
||||||
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, ¶m));
|
param.speech_encoder = &external_encoder;
|
||||||
|
EXPECT_EQ(&external_encoder, rac.RentEncoderStack(¶m));
|
||||||
info = rac.GetEncoderStack()->Encode(2, audio, arraysize(encoded), encoded);
|
info = rac.GetEncoderStack()->Encode(2, audio, arraysize(encoded), encoded);
|
||||||
EXPECT_EQ(2u, info.encoded_timestamp);
|
EXPECT_EQ(2u, info.encoded_timestamp);
|
||||||
}
|
}
|
||||||
@ -173,13 +176,15 @@ void TestCngAndRedResetSpeechEncoder(bool use_cng, bool use_red) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RentACodec::StackParameters param1, param2;
|
RentACodec::StackParameters param1, param2;
|
||||||
|
param1.speech_encoder = &speech_encoder;
|
||||||
|
param2.speech_encoder = &speech_encoder;
|
||||||
param2.use_cng = use_cng;
|
param2.use_cng = use_cng;
|
||||||
param2.use_red = use_red;
|
param2.use_red = use_red;
|
||||||
speech_encoder.Mark("disabled");
|
speech_encoder.Mark("disabled");
|
||||||
RentACodec rac;
|
RentACodec rac;
|
||||||
rac.RentEncoderStack(&speech_encoder, ¶m1);
|
rac.RentEncoderStack(¶m1);
|
||||||
speech_encoder.Mark("enabled");
|
speech_encoder.Mark("enabled");
|
||||||
rac.RentEncoderStack(&speech_encoder, ¶m2);
|
rac.RentEncoderStack(¶m2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RentACodecTest, CngResetsSpeechEncoder) {
|
TEST(RentACodecTest, CngResetsSpeechEncoder) {
|
||||||
@ -205,5 +210,13 @@ TEST(RentACodecTest, RentEncoderError) {
|
|||||||
EXPECT_FALSE(rent_a_codec.RentEncoder(codec_inst));
|
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 acm2
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
Reference in New Issue
Block a user