diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 119eee9777..37a824b404 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -80,11 +80,11 @@ static bool LayoutHasKeyboard(AudioProcessing::ChannelLayout layout) { static_assert(AudioProcessing::kNoError == 0, "kNoError must be zero"); struct AudioProcessingImpl::ApmPublicSubmodules { - ApmPublicSubmodules() : gain_control(nullptr) {} + ApmPublicSubmodules() {} // Accessed externally of APM without any lock acquired. std::unique_ptr echo_cancellation; std::unique_ptr echo_control_mobile; - GainControlImpl* gain_control; + std::unique_ptr gain_control; std::unique_ptr high_pass_filter; std::unique_ptr level_estimator; std::unique_ptr noise_suppression; @@ -173,8 +173,8 @@ AudioProcessingImpl::AudioProcessingImpl(const Config& config, new EchoCancellationImpl(this, &crit_render_, &crit_capture_)); public_submodules_->echo_control_mobile.reset( new EchoControlMobileImpl(this, &crit_render_, &crit_capture_)); - public_submodules_->gain_control = - new GainControlImpl(this, &crit_capture_, &crit_capture_); + public_submodules_->gain_control.reset( + new GainControlImpl(this, &crit_capture_, &crit_capture_)); public_submodules_->high_pass_filter.reset( new HighPassFilterImpl(&crit_capture_)); public_submodules_->level_estimator.reset( @@ -184,10 +184,8 @@ AudioProcessingImpl::AudioProcessingImpl(const Config& config, public_submodules_->voice_detection.reset( new VoiceDetectionImpl(&crit_capture_)); public_submodules_->gain_control_for_experimental_agc.reset( - new GainControlForExperimentalAgc(public_submodules_->gain_control, - &crit_capture_)); - private_submodules_->component_list.push_back( - public_submodules_->gain_control); + new GainControlForExperimentalAgc( + public_submodules_->gain_control.get(), &crit_capture_)); } SetExtraOptions(config); @@ -318,6 +316,7 @@ int AudioProcessingImpl::InitializeLocked() { } } + InitializeGainController(); InitializeEchoCanceller(); InitializeEchoControlMobile(); InitializeExperimentalAgc(); @@ -1093,7 +1092,7 @@ GainControl* AudioProcessingImpl::gain_control() const { if (constants_.use_experimental_agc) { return public_submodules_->gain_control_for_experimental_agc.get(); } - return public_submodules_->gain_control; + return public_submodules_->gain_control.get(); } HighPassFilter* AudioProcessingImpl::high_pass_filter() const { @@ -1127,7 +1126,8 @@ bool AudioProcessingImpl::is_data_processed() const { public_submodules_->high_pass_filter->is_enabled() || public_submodules_->noise_suppression->is_enabled() || public_submodules_->echo_cancellation->is_enabled() || - public_submodules_->echo_control_mobile->is_enabled()) { + public_submodules_->echo_control_mobile->is_enabled() || + public_submodules_->gain_control->is_enabled()) { return true; } @@ -1191,7 +1191,7 @@ void AudioProcessingImpl::InitializeExperimentalAgc() { if (constants_.use_experimental_agc) { if (!private_submodules_->agc_manager.get()) { private_submodules_->agc_manager.reset(new AgcManagerDirect( - public_submodules_->gain_control, + public_submodules_->gain_control.get(), public_submodules_->gain_control_for_experimental_agc.get(), constants_.agc_startup_min_volume)); } @@ -1247,6 +1247,10 @@ void AudioProcessingImpl::InitializeEchoCanceller() { public_submodules_->echo_cancellation->Initialize(); } +void AudioProcessingImpl::InitializeGainController() { + public_submodules_->gain_control->Initialize(); +} + void AudioProcessingImpl::InitializeEchoControlMobile() { public_submodules_->echo_control_mobile->Initialize(); } diff --git a/webrtc/modules/audio_processing/audio_processing_impl.h b/webrtc/modules/audio_processing/audio_processing_impl.h index d79d34c8bc..20ca3a4c74 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.h +++ b/webrtc/modules/audio_processing/audio_processing_impl.h @@ -198,6 +198,8 @@ class AudioProcessingImpl : public AudioProcessing { EXCLUSIVE_LOCKS_REQUIRED(crit_capture_); void InitializeEchoCanceller() EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); + void InitializeGainController() + EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); void InitializeEchoControlMobile() EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); int InitializeLocked(const ProcessingConfig& config) diff --git a/webrtc/modules/audio_processing/gain_control_impl.cc b/webrtc/modules/audio_processing/gain_control_impl.cc index 04a6c7ba29..936a286cdb 100644 --- a/webrtc/modules/audio_processing/gain_control_impl.cc +++ b/webrtc/modules/audio_processing/gain_control_impl.cc @@ -10,8 +10,7 @@ #include "webrtc/modules/audio_processing/gain_control_impl.h" -#include - +#include "webrtc/base/optional.h" #include "webrtc/modules/audio_processing/audio_buffer.h" #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h" @@ -29,7 +28,7 @@ int16_t MapSetting(GainControl::Mode mode) { case GainControl::kFixedDigital: return kAgcModeFixedDigital; } - assert(false); + RTC_DCHECK(false); return -1; } @@ -42,11 +41,59 @@ static const size_t kMaxNumFramesToBuffer = 100; } // namespace +class GainControlImpl::GainController { + public: + explicit GainController() { + state_ = WebRtcAgc_Create(); + RTC_CHECK(state_); + } + + ~GainController() { + RTC_DCHECK(state_); + WebRtcAgc_Free(state_); + } + + Handle* state() { + RTC_DCHECK(state_); + return state_; + } + + void Initialize(int minimum_capture_level, + int maximum_capture_level, + Mode mode, + int sample_rate_hz, + int capture_level) { + RTC_DCHECK(state_); + int error = + WebRtcAgc_Init(state_, minimum_capture_level, maximum_capture_level, + MapSetting(mode), sample_rate_hz); + RTC_DCHECK_EQ(0, error); + + set_capture_level(capture_level); + } + + void set_capture_level(int capture_level) { + capture_level_ = rtc::Optional(capture_level); + } + + int get_capture_level() { + RTC_DCHECK(capture_level_); + return *capture_level_; + } + + private: + Handle* state_; + // TODO(peah): Remove the optional once the initialization is moved into the + // ctor. + rtc::Optional capture_level_; + + RTC_DISALLOW_COPY_AND_ASSIGN(GainController); +}; + GainControlImpl::GainControlImpl(const AudioProcessing* apm, rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture) - : ProcessingComponent(), - apm_(apm), + : apm_(apm), crit_render_(crit_render), crit_capture_(crit_capture), mode_(kAdaptiveAnalog), @@ -68,20 +115,20 @@ GainControlImpl::~GainControlImpl() {} int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { rtc::CritScope cs(crit_render_); - if (!is_component_enabled()) { + if (!enabled_) { return AudioProcessing::kNoError; } - assert(audio->num_frames_per_band() <= 160); + RTC_DCHECK_GE(160u, audio->num_frames_per_band()); render_queue_buffer_.resize(0); - for (size_t i = 0; i < num_handles(); i++) { - Handle* my_handle = static_cast(handle(i)); - int err = - WebRtcAgc_GetAddFarendError(my_handle, audio->num_frames_per_band()); + for (auto& gain_controller : gain_controllers_) { + int err = WebRtcAgc_GetAddFarendError(gain_controller->state(), + audio->num_frames_per_band()); - if (err != AudioProcessing::kNoError) - return GetHandleError(my_handle); + if (err != AudioProcessing::kNoError) { + return AudioProcessing::kUnspecifiedError; + } // Buffer the samples in the render queue. render_queue_buffer_.insert( @@ -106,17 +153,17 @@ int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { void GainControlImpl::ReadQueuedRenderData() { rtc::CritScope cs(crit_capture_); - if (!is_component_enabled()) { + if (!enabled_) { return; } while (render_signal_queue_->Remove(&capture_queue_buffer_)) { size_t buffer_index = 0; const size_t num_frames_per_band = - capture_queue_buffer_.size() / num_handles(); - for (size_t i = 0; i < num_handles(); i++) { - Handle* my_handle = static_cast(handle(i)); - WebRtcAgc_AddFarend(my_handle, &capture_queue_buffer_[buffer_index], + capture_queue_buffer_.size() / num_handles_required(); + for (auto& gain_controller : gain_controllers_) { + WebRtcAgc_AddFarend(gain_controller->state(), + &capture_queue_buffer_[buffer_index], num_frames_per_band); buffer_index += num_frames_per_band; @@ -127,49 +174,42 @@ void GainControlImpl::ReadQueuedRenderData() { int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { rtc::CritScope cs(crit_capture_); - if (!is_component_enabled()) { + if (!enabled_) { return AudioProcessing::kNoError; } - assert(audio->num_frames_per_band() <= 160); - assert(audio->num_channels() == num_handles()); - - int err = AudioProcessing::kNoError; + RTC_DCHECK_GE(160u, audio->num_frames_per_band()); + RTC_DCHECK_EQ(audio->num_channels(), num_handles_required()); + RTC_DCHECK_LE(num_handles_required(), gain_controllers_.size()); if (mode_ == kAdaptiveAnalog) { - capture_levels_.assign(num_handles(), analog_capture_level_); - for (size_t i = 0; i < num_handles(); i++) { - Handle* my_handle = static_cast(handle(i)); - err = WebRtcAgc_AddMic( - my_handle, - audio->split_bands(i), - audio->num_bands(), - audio->num_frames_per_band()); + int capture_channel = 0; + for (auto& gain_controller : gain_controllers_) { + gain_controller->set_capture_level(analog_capture_level_); + int err = WebRtcAgc_AddMic( + gain_controller->state(), audio->split_bands(capture_channel), + audio->num_bands(), audio->num_frames_per_band()); if (err != AudioProcessing::kNoError) { - return GetHandleError(my_handle); + return AudioProcessing::kUnspecifiedError; } + ++capture_channel; } } else if (mode_ == kAdaptiveDigital) { - - for (size_t i = 0; i < num_handles(); i++) { - Handle* my_handle = static_cast(handle(i)); + int capture_channel = 0; + for (auto& gain_controller : gain_controllers_) { int32_t capture_level_out = 0; + int err = WebRtcAgc_VirtualMic( + gain_controller->state(), audio->split_bands(capture_channel), + audio->num_bands(), audio->num_frames_per_band(), + analog_capture_level_, &capture_level_out); - err = WebRtcAgc_VirtualMic( - my_handle, - audio->split_bands(i), - audio->num_bands(), - audio->num_frames_per_band(), - analog_capture_level_, - &capture_level_out); - - capture_levels_[i] = capture_level_out; + gain_controller->set_capture_level(capture_level_out); if (err != AudioProcessing::kNoError) { - return GetHandleError(my_handle); + return AudioProcessing::kUnspecifiedError; } - + ++capture_channel; } } @@ -179,7 +219,7 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { rtc::CritScope cs(crit_capture_); - if (!is_component_enabled()) { + if (!enabled_) { return AudioProcessing::kNoError; } @@ -187,46 +227,44 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { return AudioProcessing::kStreamParameterNotSetError; } - assert(audio->num_frames_per_band() <= 160); - assert(audio->num_channels() == num_handles()); + RTC_DCHECK_GE(160u, audio->num_frames_per_band()); + RTC_DCHECK_EQ(audio->num_channels(), num_handles_required()); stream_is_saturated_ = false; - for (size_t i = 0; i < num_handles(); i++) { - Handle* my_handle = static_cast(handle(i)); + int capture_channel = 0; + for (auto& gain_controller : gain_controllers_) { int32_t capture_level_out = 0; uint8_t saturation_warning = 0; // The call to stream_has_echo() is ok from a deadlock perspective // as the capture lock is allready held. int err = WebRtcAgc_Process( - my_handle, - audio->split_bands_const(i), - audio->num_bands(), - audio->num_frames_per_band(), - audio->split_bands(i), - capture_levels_[i], - &capture_level_out, - apm_->echo_cancellation()->stream_has_echo(), - &saturation_warning); + gain_controller->state(), audio->split_bands_const(capture_channel), + audio->num_bands(), audio->num_frames_per_band(), + audio->split_bands(capture_channel), + gain_controller->get_capture_level(), &capture_level_out, + apm_->echo_cancellation()->stream_has_echo(), &saturation_warning); if (err != AudioProcessing::kNoError) { - return GetHandleError(my_handle); + return AudioProcessing::kUnspecifiedError; } - capture_levels_[i] = capture_level_out; + gain_controller->set_capture_level(capture_level_out); if (saturation_warning == 1) { stream_is_saturated_ = true; } + + ++capture_channel; } if (mode_ == kAdaptiveAnalog) { // Take the analog level to be the average across the handles. analog_capture_level_ = 0; - for (size_t i = 0; i < num_handles(); i++) { - analog_capture_level_ += capture_levels_[i]; + for (auto& gain_controller : gain_controllers_) { + analog_capture_level_ += gain_controller->get_capture_level(); } - analog_capture_level_ /= num_handles(); + analog_capture_level_ /= num_handles_required(); } was_analog_level_set_ = false; @@ -257,12 +295,18 @@ int GainControlImpl::stream_analog_level() { int GainControlImpl::Enable(bool enable) { rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); - return EnableComponent(enable); + if (enable && !enabled_) { + enabled_ = enable; // Must be set before Initialize() is called. + Initialize(); + } else { + enabled_ = enable; + } + return AudioProcessing::kNoError; } bool GainControlImpl::is_enabled() const { rtc::CritScope cs(crit_capture_); - return is_component_enabled(); + return enabled_; } int GainControlImpl::set_mode(Mode mode) { @@ -273,7 +317,8 @@ int GainControlImpl::set_mode(Mode mode) { } mode_ = mode; - return Initialize(); + Initialize(); + return AudioProcessing::kNoError; } GainControl::Mode GainControlImpl::mode() const { @@ -299,7 +344,8 @@ int GainControlImpl::set_analog_level_limits(int minimum, minimum_capture_level_ = minimum; maximum_capture_level_ = maximum; - return Initialize(); + Initialize(); + return AudioProcessing::kNoError; } int GainControlImpl::analog_level_minimum() const { @@ -318,12 +364,13 @@ bool GainControlImpl::stream_is_saturated() const { } int GainControlImpl::set_target_level_dbfs(int level) { - rtc::CritScope cs(crit_capture_); if (level > 31 || level < 0) { return AudioProcessing::kBadParameterError; } - - target_level_dbfs_ = level; + { + rtc::CritScope cs(crit_capture_); + target_level_dbfs_ = level; + } return Configure(); } @@ -333,12 +380,13 @@ int GainControlImpl::target_level_dbfs() const { } int GainControlImpl::set_compression_gain_db(int gain) { - rtc::CritScope cs(crit_capture_); if (gain < 0 || gain > 90) { return AudioProcessing::kBadParameterError; } - - compression_gain_db_ = gain; + { + rtc::CritScope cs(crit_capture_); + compression_gain_db_ = gain; + } return Configure(); } @@ -348,8 +396,10 @@ int GainControlImpl::compression_gain_db() const { } int GainControlImpl::enable_limiter(bool enable) { - rtc::CritScope cs(crit_capture_); - limiter_enabled_ = enable; + { + rtc::CritScope cs(crit_capture_); + limiter_enabled_ = enable; + } return Configure(); } @@ -358,26 +408,32 @@ bool GainControlImpl::is_limiter_enabled() const { return limiter_enabled_; } -int GainControlImpl::Initialize() { - int err = ProcessingComponent::Initialize(); - if (err != AudioProcessing::kNoError || !is_component_enabled()) { - return err; +void GainControlImpl::Initialize() { + rtc::CritScope cs_render(crit_render_); + rtc::CritScope cs_capture(crit_capture_); + if (!enabled_) { + return; } + int sample_rate_hz = apm_->proc_sample_rate_hz(); + gain_controllers_.resize(num_handles_required()); + for (auto& gain_controller : gain_controllers_) { + if (!gain_controller) { + gain_controller.reset(new GainController()); + } + gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_, + mode_, sample_rate_hz, analog_capture_level_); + } + + Configure(); + AllocateRenderQueue(); - - rtc::CritScope cs_capture(crit_capture_); - const int n = num_handles(); - RTC_CHECK_GE(n, 0) << "Bad number of handles: " << n; - - capture_levels_.assign(n, analog_capture_level_); - return AudioProcessing::kNoError; } void GainControlImpl::AllocateRenderQueue() { - const size_t new_render_queue_element_max_size = - std::max(static_cast(1), - kMaxAllowedValuesOfSamplesPerFrame * num_handles()); + const size_t new_render_queue_element_max_size = std::max( + static_cast(1), + kMaxAllowedValuesOfSamplesPerFrame * num_handles_required()); rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); @@ -398,26 +454,7 @@ void GainControlImpl::AllocateRenderQueue() { } } -void* GainControlImpl::CreateHandle() const { - return WebRtcAgc_Create(); -} - -void GainControlImpl::DestroyHandle(void* handle) const { - WebRtcAgc_Free(static_cast(handle)); -} - -int GainControlImpl::InitializeHandle(void* handle) const { - rtc::CritScope cs_render(crit_render_); - rtc::CritScope cs_capture(crit_capture_); - - return WebRtcAgc_Init(static_cast(handle), - minimum_capture_level_, - maximum_capture_level_, - MapSetting(mode_), - apm_->proc_sample_rate_hz()); -} - -int GainControlImpl::ConfigureHandle(void* handle) const { +int GainControlImpl::Configure() { rtc::CritScope cs_render(crit_render_); rtc::CritScope cs_capture(crit_capture_); WebRtcAgcConfig config; @@ -430,18 +467,19 @@ int GainControlImpl::ConfigureHandle(void* handle) const { static_cast(compression_gain_db_); config.limiterEnable = limiter_enabled_; - return WebRtcAgc_set_config(static_cast(handle), config); + int error = AudioProcessing::kNoError; + for (auto& gain_controller : gain_controllers_) { + const int handle_error = + WebRtcAgc_set_config(gain_controller->state(), config); + if (handle_error != AudioProcessing::kNoError) { + error = handle_error; + } + } + return error; } size_t GainControlImpl::num_handles_required() const { // Not locked as it only relies on APM public API which is threadsafe. return apm_->num_proc_channels(); } - -int GainControlImpl::GetHandleError(void* handle) const { - // The AGC has no get_error() function. - // (Despite listing errors in its interface...) - assert(handle != NULL); - return AudioProcessing::kUnspecifiedError; -} } // namespace webrtc diff --git a/webrtc/modules/audio_processing/gain_control_impl.h b/webrtc/modules/audio_processing/gain_control_impl.h index 942a1835e4..54b8ea7920 100644 --- a/webrtc/modules/audio_processing/gain_control_impl.h +++ b/webrtc/modules/audio_processing/gain_control_impl.h @@ -14,6 +14,7 @@ #include #include +#include "webrtc/base/constructormagic.h" #include "webrtc/base/criticalsection.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/common_audio/swap_queue.h" @@ -24,20 +25,18 @@ namespace webrtc { class AudioBuffer; -class GainControlImpl : public GainControl, - public ProcessingComponent { +class GainControlImpl : public GainControl { public: GainControlImpl(const AudioProcessing* apm, rtc::CriticalSection* crit_render, rtc::CriticalSection* crit_capture); - virtual ~GainControlImpl(); + ~GainControlImpl() override; int ProcessRenderAudio(AudioBuffer* audio); int AnalyzeCaptureAudio(AudioBuffer* audio); int ProcessCaptureAudio(AudioBuffer* audio); - // ProcessingComponent implementation. - int Initialize() override; + void Initialize(); // GainControl implementation. bool is_enabled() const override; @@ -49,6 +48,8 @@ class GainControlImpl : public GainControl, void ReadQueuedRenderData(); private: + class GainController; + // GainControl implementation. int Enable(bool enable) override; int set_stream_analog_level(int level) override; @@ -63,15 +64,10 @@ class GainControlImpl : public GainControl, int analog_level_maximum() const override; bool stream_is_saturated() const override; - // ProcessingComponent implementation. - void* CreateHandle() const override; - int InitializeHandle(void* handle) const override; - int ConfigureHandle(void* handle) const override; - void DestroyHandle(void* handle) const override; - size_t num_handles_required() const override; - int GetHandleError(void* handle) const override; + size_t num_handles_required() const; void AllocateRenderQueue(); + int Configure(); // Not guarded as its public API is thread safe. const AudioProcessing* apm_; @@ -79,13 +75,14 @@ class GainControlImpl : public GainControl, rtc::CriticalSection* const crit_render_ ACQUIRED_BEFORE(crit_capture_); rtc::CriticalSection* const crit_capture_; + bool enabled_ = false; + Mode mode_ GUARDED_BY(crit_capture_); int minimum_capture_level_ GUARDED_BY(crit_capture_); int maximum_capture_level_ GUARDED_BY(crit_capture_); bool limiter_enabled_ GUARDED_BY(crit_capture_); int target_level_dbfs_ GUARDED_BY(crit_capture_); int compression_gain_db_ GUARDED_BY(crit_capture_); - std::vector capture_levels_ GUARDED_BY(crit_capture_); int analog_capture_level_ GUARDED_BY(crit_capture_); bool was_analog_level_set_ GUARDED_BY(crit_capture_); bool stream_is_saturated_ GUARDED_BY(crit_capture_); @@ -99,6 +96,10 @@ class GainControlImpl : public GainControl, std::unique_ptr< SwapQueue, RenderQueueItemVerifier>> render_signal_queue_; + + std::vector> gain_controllers_; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GainControlImpl); }; } // namespace webrtc