Index: webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc |
diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc |
index ff779a28b182afaa4831c75c6ac29e110b168420..59a604937d62adf9da23a9bd26c291a875e76959 100644 |
--- a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc |
+++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc |
@@ -31,6 +31,12 @@ namespace webrtc { |
namespace acm2 { |
+struct EncoderFactory { |
+ AudioEncoder* external_speech_encoder = nullptr; |
+ CodecManager codec_manager; |
+ RentACodec rent_a_codec; |
+}; |
+ |
namespace { |
// TODO(turajs): the same functionality is used in NetEq. If both classes |
@@ -90,6 +96,79 @@ void ConvertEncodedInfoToFragmentationHeader( |
frag->fragmentationPlType[i] = info.redundant[i].payload_type; |
} |
} |
+ |
+// Wraps a raw AudioEncoder pointer. The idea is that you can put one of these |
+// in a unique_ptr, to protect the contained raw pointer from being deleted |
+// when the unique_ptr expires. (This is of course a bad idea in general, but |
+// backwards compatibility.) |
+class RawAudioEncoderWrapper final : public AudioEncoder { |
+ public: |
+ RawAudioEncoderWrapper(AudioEncoder* enc) : enc_(enc) {} |
+ size_t MaxEncodedBytes() const override { return enc_->MaxEncodedBytes(); } |
+ int SampleRateHz() const override { return enc_->SampleRateHz(); } |
+ size_t NumChannels() const override { return enc_->NumChannels(); } |
+ int RtpTimestampRateHz() const override { return enc_->RtpTimestampRateHz(); } |
+ size_t Num10MsFramesInNextPacket() const override { |
+ return enc_->Num10MsFramesInNextPacket(); |
+ } |
+ size_t Max10MsFramesInAPacket() const override { |
+ return enc_->Max10MsFramesInAPacket(); |
+ } |
+ int GetTargetBitrate() const override { return enc_->GetTargetBitrate(); } |
+ EncodedInfo EncodeImpl(uint32_t rtp_timestamp, |
+ rtc::ArrayView<const int16_t> audio, |
+ rtc::Buffer* encoded) override { |
+ return enc_->Encode(rtp_timestamp, audio, encoded); |
+ } |
+ EncodedInfo EncodeInternal(uint32_t rtp_timestamp, |
+ rtc::ArrayView<const int16_t> audio, |
+ size_t max_encoded_bytes, |
+ uint8_t* encoded) override { |
+ return enc_->EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, |
+ encoded); |
+ } |
+ void Reset() override { return enc_->Reset(); } |
+ bool SetFec(bool enable) override { return enc_->SetFec(enable); } |
+ bool SetDtx(bool enable) override { return enc_->SetDtx(enable); } |
+ bool SetApplication(Application application) override { |
+ return enc_->SetApplication(application); |
+ } |
+ void SetMaxPlaybackRate(int frequency_hz) override { |
+ return enc_->SetMaxPlaybackRate(frequency_hz); |
+ } |
+ void SetProjectedPacketLossRate(double fraction) override { |
+ return enc_->SetProjectedPacketLossRate(fraction); |
+ } |
+ void SetTargetBitrate(int target_bps) override { |
+ return enc_->SetTargetBitrate(target_bps); |
+ } |
+ |
+ private: |
+ AudioEncoder* enc_; |
+}; |
+ |
+// Return false on error. |
+bool CreateSpeechEncoderIfNecessary(EncoderFactory* ef) { |
+ auto* sp = ef->codec_manager.GetStackParams(); |
+ if (sp->speech_encoder) { |
+ // Do nothing; we already have a speech encoder. |
+ } else if (ef->codec_manager.GetCodecInst()) { |
+ RTC_DCHECK(!ef->external_speech_encoder); |
+ // We have no speech encoder, but we have a specification for making one. |
+ std::unique_ptr<AudioEncoder> enc = |
+ ef->rent_a_codec.RentEncoder(*ef->codec_manager.GetCodecInst()); |
+ if (!enc) |
+ return false; // Encoder spec was bad. |
+ sp->speech_encoder = std::move(enc); |
+ } else if (ef->external_speech_encoder) { |
+ RTC_DCHECK(!ef->codec_manager.GetCodecInst()); |
+ // We have an external speech encoder. |
+ sp->speech_encoder = std::unique_ptr<AudioEncoder>( |
+ new RawAudioEncoderWrapper(ef->external_speech_encoder)); |
+ } |
+ return true; |
+} |
+ |
} // namespace |
void AudioCodingModuleImpl::ChangeLogger::MaybeLog(int value) { |
@@ -200,15 +279,13 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) { |
if (!encoder_factory_->codec_manager.RegisterEncoder(send_codec)) { |
return -1; |
} |
- auto* sp = encoder_factory_->codec_manager.GetStackParams(); |
- if (!sp->speech_encoder && encoder_factory_->codec_manager.GetCodecInst()) { |
- // We have no speech encoder, but we have a specification for making one. |
- AudioEncoder* enc = encoder_factory_->rent_a_codec.RentEncoder( |
- *encoder_factory_->codec_manager.GetCodecInst()); |
- if (!enc) |
- return -1; |
- sp->speech_encoder = enc; |
+ if (encoder_factory_->codec_manager.GetCodecInst()) { |
+ encoder_factory_->external_speech_encoder = nullptr; |
} |
+ if (!CreateSpeechEncoderIfNecessary(encoder_factory_.get())) { |
+ return -1; |
+ } |
+ auto* sp = encoder_factory_->codec_manager.GetStackParams(); |
if (sp->speech_encoder) |
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp); |
return 0; |
@@ -217,8 +294,11 @@ int AudioCodingModuleImpl::RegisterSendCodec(const CodecInst& send_codec) { |
void AudioCodingModuleImpl::RegisterExternalSendCodec( |
AudioEncoder* external_speech_encoder) { |
rtc::CritScope lock(&acm_crit_sect_); |
+ encoder_factory_->codec_manager.UnsetCodecInst(); |
+ encoder_factory_->external_speech_encoder = external_speech_encoder; |
+ RTC_CHECK(CreateSpeechEncoderIfNecessary(encoder_factory_.get())); |
auto* sp = encoder_factory_->codec_manager.GetStackParams(); |
- sp->speech_encoder = external_speech_encoder; |
+ RTC_CHECK(sp->speech_encoder); |
encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp); |
} |
@@ -229,9 +309,11 @@ rtc::Optional<CodecInst> AudioCodingModuleImpl::SendCodec() const { |
if (ci) { |
return rtc::Optional<CodecInst>(*ci); |
} |
- auto* enc = encoder_factory_->codec_manager.GetStackParams()->speech_encoder; |
+ CreateSpeechEncoderIfNecessary(encoder_factory_.get()); |
+ const std::unique_ptr<AudioEncoder>& enc = |
+ encoder_factory_->codec_manager.GetStackParams()->speech_encoder; |
if (enc) { |
- return rtc::Optional<CodecInst>(CodecManager::ForgeCodecInst(enc)); |
+ return rtc::Optional<CodecInst>(CodecManager::ForgeCodecInst(enc.get())); |
} |
return rtc::Optional<CodecInst>(); |
} |
@@ -451,6 +533,7 @@ bool AudioCodingModuleImpl::REDStatus() const { |
int AudioCodingModuleImpl::SetREDStatus(bool enable_red) { |
#ifdef WEBRTC_CODEC_RED |
rtc::CritScope lock(&acm_crit_sect_); |
+ CreateSpeechEncoderIfNecessary(encoder_factory_.get()); |
if (!encoder_factory_->codec_manager.SetCopyRed(enable_red)) { |
return -1; |
} |
@@ -476,6 +559,7 @@ bool AudioCodingModuleImpl::CodecFEC() const { |
int AudioCodingModuleImpl::SetCodecFEC(bool enable_codec_fec) { |
rtc::CritScope lock(&acm_crit_sect_); |
+ CreateSpeechEncoderIfNecessary(encoder_factory_.get()); |
if (!encoder_factory_->codec_manager.SetCodecFEC(enable_codec_fec)) { |
return -1; |
} |
@@ -507,6 +591,7 @@ int AudioCodingModuleImpl::SetVAD(bool enable_dtx, |
// Note: |enable_vad| is not used; VAD is enabled based on the DTX setting. |
RTC_DCHECK_EQ(enable_dtx, enable_vad); |
rtc::CritScope lock(&acm_crit_sect_); |
+ CreateSpeechEncoderIfNecessary(encoder_factory_.get()); |
if (!encoder_factory_->codec_manager.SetVAD(enable_dtx, mode)) { |
return -1; |
} |