From 4cdbd57fe3bc252e437035b0589d0fbf39200157 Mon Sep 17 00:00:00 2001 From: kwiberg Date: Wed, 30 Mar 2016 03:10:05 -0700 Subject: [PATCH] AudioCodingModule: Add methods for injecting external encoder stacks BUG=webrtc:5028 Review URL: https://codereview.webrtc.org/1673213002 Cr-Commit-Position: refs/heads/master@{#12158} --- .../acm2/audio_coding_module_impl.cc | 75 ++++++++++++++----- .../acm2/audio_coding_module_impl.h | 15 +++- .../modules/audio_coding/acm2/rent_a_codec.cc | 6 +- .../modules/audio_coding/acm2/rent_a_codec.h | 7 +- .../include/audio_coding_module.h | 53 +++++++++++++ 5 files changed, 125 insertions(+), 31 deletions(-) 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 59a604937d..d30daaaf34 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.cc @@ -302,20 +302,41 @@ void AudioCodingModuleImpl::RegisterExternalSendCodec( encoder_stack_ = encoder_factory_->rent_a_codec.RentEncoderStack(sp); } +void AudioCodingModuleImpl::ModifyEncoder( + FunctionView*)> modifier) { + rtc::CritScope lock(&acm_crit_sect_); + + // Wipe the encoder factory, so that everything that relies on it will fail. + // We don't want the complexity of supporting swapping back and forth. + if (encoder_factory_) { + encoder_factory_.reset(); + RTC_CHECK(!encoder_stack_); // Ensure we hadn't started using the factory. + } + + modifier(&encoder_stack_); +} + // Get current send codec. rtc::Optional AudioCodingModuleImpl::SendCodec() const { rtc::CritScope lock(&acm_crit_sect_); - auto* ci = encoder_factory_->codec_manager.GetCodecInst(); - if (ci) { - return rtc::Optional(*ci); + if (encoder_factory_) { + auto* ci = encoder_factory_->codec_manager.GetCodecInst(); + if (ci) { + return rtc::Optional(*ci); + } + CreateSpeechEncoderIfNecessary(encoder_factory_.get()); + const std::unique_ptr& enc = + encoder_factory_->codec_manager.GetStackParams()->speech_encoder; + if (enc) { + return rtc::Optional(CodecManager::ForgeCodecInst(enc.get())); + } + return rtc::Optional(); + } else { + return encoder_stack_ + ? rtc::Optional( + CodecManager::ForgeCodecInst(encoder_stack_.get())) + : rtc::Optional(); } - CreateSpeechEncoderIfNecessary(encoder_factory_.get()); - const std::unique_ptr& enc = - encoder_factory_->codec_manager.GetStackParams()->speech_encoder; - if (enc) { - return rtc::Optional(CodecManager::ForgeCodecInst(enc.get())); - } - return rtc::Optional(); } // Get current send frequency. @@ -665,10 +686,23 @@ int AudioCodingModuleImpl::PlayoutFrequency() const { return receiver_.last_output_sample_rate_hz(); } -// Register possible receive codecs, can be called multiple times, -// for codecs, CNG (NB, WB and SWB), DTMF, RED. int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { rtc::CritScope lock(&acm_crit_sect_); + auto* ef = encoder_factory_.get(); + return RegisterReceiveCodecUnlocked( + codec, [ef] { return ef->rent_a_codec.RentIsacDecoder(); }); +} + +int AudioCodingModuleImpl::RegisterReceiveCodec( + const CodecInst& codec, + FunctionView()> isac_factory) { + rtc::CritScope lock(&acm_crit_sect_); + return RegisterReceiveCodecUnlocked(codec, isac_factory); +} + +int AudioCodingModuleImpl::RegisterReceiveCodecUnlocked( + const CodecInst& codec, + FunctionView()> isac_factory) { RTC_DCHECK(receiver_initialized_); if (codec.channels > 2) { LOG_F(LS_ERROR) << "Unsupported number of channels: " << codec.channels; @@ -691,14 +725,15 @@ int AudioCodingModuleImpl::RegisterReceiveCodec(const CodecInst& codec) { return -1; } - // Get |decoder| associated with |codec|. |decoder| is NULL if |codec| does - // not own its decoder. - return receiver_.AddCodec( - *codec_index, codec.pltype, codec.channels, codec.plfreq, - STR_CASE_CMP(codec.plname, "isac") == 0 - ? encoder_factory_->rent_a_codec.RentIsacDecoder() - : nullptr, - codec.plname); + AudioDecoder* isac_decoder = nullptr; + if (STR_CASE_CMP(codec.plname, "isac") == 0) { + if (!isac_decoder_) { + isac_decoder_ = isac_factory(); + } + isac_decoder = isac_decoder_.get(); + } + return receiver_.AddCodec(*codec_index, codec.pltype, codec.channels, + codec.plfreq, isac_decoder, codec.plname); } int AudioCodingModuleImpl::RegisterExternalReceiveCodec( diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.h index 195ec28dea..e463d29f9b 100644 --- a/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.h +++ b/webrtc/modules/audio_coding/acm2/audio_coding_module_impl.h @@ -49,6 +49,9 @@ class AudioCodingModuleImpl final : public AudioCodingModule { void RegisterExternalSendCodec( AudioEncoder* external_speech_encoder) override; + void ModifyEncoder( + FunctionView*)> modifier) override; + // Get current send codec. rtc::Optional SendCodec() const override; @@ -119,9 +122,10 @@ class AudioCodingModuleImpl final : public AudioCodingModule { // Get current playout frequency. int PlayoutFrequency() const override; - // Register possible receive codecs, can be called multiple times, - // for codecs, CNG, DTMF, RED. int RegisterReceiveCodec(const CodecInst& receive_codec) override; + int RegisterReceiveCodec( + const CodecInst& receive_codec, + FunctionView()> isac_factory) override; int RegisterExternalReceiveCodec(int rtp_payload_type, AudioDecoder* external_decoder, @@ -213,6 +217,11 @@ class AudioCodingModuleImpl final : public AudioCodingModule { const std::string histogram_name_; }; + int RegisterReceiveCodecUnlocked( + const CodecInst& codec, + FunctionView()> isac_factory) + EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); + int Add10MsDataInternal(const AudioFrame& audio_frame, InputData* input_data) EXCLUSIVE_LOCKS_REQUIRED(acm_crit_sect_); int Encode(const InputData& input_data) @@ -258,6 +267,8 @@ class AudioCodingModuleImpl final : public AudioCodingModule { // RegisterEncoder. std::unique_ptr encoder_stack_ GUARDED_BY(acm_crit_sect_); + std::unique_ptr isac_decoder_ GUARDED_BY(acm_crit_sect_); + // This is to keep track of CN instances where we can send DTMFs. uint8_t previous_pltype_ GUARDED_BY(acm_crit_sect_); diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc index f37b12c181..71d34d1068 100644 --- a/webrtc/modules/audio_coding/acm2/rent_a_codec.cc +++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.cc @@ -294,10 +294,8 @@ std::unique_ptr RentACodec::RentEncoderStack( return encoder_stack; } -AudioDecoder* RentACodec::RentIsacDecoder() { - if (!isac_decoder_) - isac_decoder_ = CreateIsacDecoder(&isac_bandwidth_info_); - return isac_decoder_.get(); +std::unique_ptr RentACodec::RentIsacDecoder() { + return CreateIsacDecoder(&isac_bandwidth_info_); } } // namespace acm2 diff --git a/webrtc/modules/audio_coding/acm2/rent_a_codec.h b/webrtc/modules/audio_coding/acm2/rent_a_codec.h index d6f159a5b0..e41f77d103 100644 --- a/webrtc/modules/audio_coding/acm2/rent_a_codec.h +++ b/webrtc/modules/audio_coding/acm2/rent_a_codec.h @@ -222,16 +222,13 @@ class RentACodec { // will be stolen. std::unique_ptr RentEncoderStack(StackParameters* param); - // 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(); + // Creates and returns an iSAC decoder. + std::unique_ptr RentIsacDecoder(); private: std::unique_ptr speech_encoder_; std::unique_ptr cng_encoder_; std::unique_ptr red_encoder_; - std::unique_ptr isac_decoder_; LockedIsacBandwidthInfo isac_bandwidth_info_; RTC_DISALLOW_COPY_AND_ASSIGN(RentACodec); diff --git a/webrtc/modules/audio_coding/include/audio_coding_module.h b/webrtc/modules/audio_coding/include/audio_coding_module.h index 9e7991f22f..305d8ea6d3 100644 --- a/webrtc/modules/audio_coding/include/audio_coding_module.h +++ b/webrtc/modules/audio_coding/include/audio_coding_module.h @@ -207,6 +207,52 @@ class AudioCodingModule { virtual void RegisterExternalSendCodec( AudioEncoder* external_speech_encoder) = 0; + // Just like std::function, FunctionView will wrap any callable and hide its + // actual type, exposing only its signature. But unlike std::function, + // FunctionView doesn't own its callable---it just points to it. Thus, it's a + // good choice mainly as a function argument when the callable argument will + // not be called again once the function has returned. + template + class FunctionView; // Undefined. + + template + class FunctionView final { + public: + // This constructor is implicit, so that callers won't have to convert + // lambdas to FunctionView explicitly. This is safe + // because FunctionView is only a reference to the real callable. + template + FunctionView(F&& f) + : f_(&f), call_(Call::type>) {} + + RetT operator()(ArgT... args) const { + return call_(f_, std::forward(args)...); + } + + private: + template + static RetT Call(void* f, ArgT... args) { + return (*static_cast(f))(std::forward(args)...); + } + void* f_; + RetT (*call_)(void* f, ArgT... args); + }; + + // |modifier| is called exactly once with one argument: a pointer to the + // unique_ptr that holds the current encoder (which is null if there is no + // current encoder). For the duration of the call, |modifier| has exclusive + // access to the unique_ptr; it may call the encoder, steal the encoder and + // replace it with another encoder or with nullptr, etc. + virtual void ModifyEncoder( + FunctionView*)> modifier) = 0; + + // Utility method for simply replacing the existing encoder with a new one. + void SetEncoder(std::unique_ptr new_encoder) { + ModifyEncoder([&](std::unique_ptr* encoder) { + *encoder = std::move(new_encoder); + }); + } + /////////////////////////////////////////////////////////////////////////// // int32_t SendCodec() // Get parameters for the codec currently registered as send codec. @@ -472,6 +518,13 @@ class AudioCodingModule { // virtual int RegisterReceiveCodec(const CodecInst& receive_codec) = 0; + // Register a decoder; call repeatedly to register multiple decoders. |df| is + // a decoder factory that returns an iSAC decoder; it will be called once if + // the decoder being registered is iSAC. + virtual int RegisterReceiveCodec( + const CodecInst& receive_codec, + FunctionView()> isac_factory) = 0; + // Registers an external decoder. The name is only used to provide information // back to the caller about the decoder. Hence, the name is arbitrary, and may // be empty.