Remove crit_render_ lock from webrtc::GainControlImpl
The lock is unnecessary and potentially unsafe:
1) All gain_control accesses in AudioProcessingImpl happen - and are intended to happen - while holding the crit_capture_ lock, and all external API calls take the same lock once inside GainControlImpl.
2) If ProcessCaptureStreamLocked (locked by crit_capture) calls a gain_control function that takes crit_render, the mandated locking order (render before capture) is violated and we might get a deadlock with the render thread.
Bug: b/123456404
Change-Id: Id7a888827e347e5e1d50e2f87d90e8b68f52b7b8
Reviewed-on: https://webrtc-review.googlesource.com/c/122087
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26637}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 5f0d676..3400abf 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -387,48 +387,42 @@
capture_(config.Get<ExperimentalNs>().enabled),
#endif
capture_nonlocked_() {
- {
- rtc::CritScope cs_render(&crit_render_);
- rtc::CritScope cs_capture(&crit_capture_);
+ // Mark Echo Controller enabled if a factory is injected.
+ capture_nonlocked_.echo_controller_enabled =
+ static_cast<bool>(echo_control_factory_);
- // Mark Echo Controller enabled if a factory is injected.
- capture_nonlocked_.echo_controller_enabled =
- static_cast<bool>(echo_control_factory_);
+ public_submodules_->gain_control.reset(new GainControlImpl(&crit_capture_));
+ public_submodules_->level_estimator.reset(
+ new LevelEstimatorImpl(&crit_capture_));
+ public_submodules_->noise_suppression.reset(
+ new NoiseSuppressionImpl(&crit_capture_));
+ public_submodules_->noise_suppression_proxy.reset(new NoiseSuppressionProxy(
+ this, public_submodules_->noise_suppression.get()));
+ public_submodules_->voice_detection.reset(
+ new VoiceDetectionImpl(&crit_capture_));
+ public_submodules_->gain_control_for_experimental_agc.reset(
+ new GainControlForExperimentalAgc(public_submodules_->gain_control.get(),
+ &crit_capture_));
- public_submodules_->gain_control.reset(
- new GainControlImpl(&crit_render_, &crit_capture_));
- public_submodules_->level_estimator.reset(
- new LevelEstimatorImpl(&crit_capture_));
- public_submodules_->noise_suppression.reset(
- new NoiseSuppressionImpl(&crit_capture_));
- public_submodules_->noise_suppression_proxy.reset(new NoiseSuppressionProxy(
- this, public_submodules_->noise_suppression.get()));
- public_submodules_->voice_detection.reset(
- new VoiceDetectionImpl(&crit_capture_));
- public_submodules_->gain_control_for_experimental_agc.reset(
- new GainControlForExperimentalAgc(
- public_submodules_->gain_control.get(), &crit_capture_));
-
- // If no echo detector is injected, use the ResidualEchoDetector.
- if (!private_submodules_->echo_detector) {
- private_submodules_->echo_detector =
- new rtc::RefCountedObject<ResidualEchoDetector>();
- }
-
- private_submodules_->echo_cancellation.reset(new EchoCancellationImpl());
- private_submodules_->echo_control_mobile.reset(new EchoControlMobileImpl());
- // TODO(alessiob): Move the injected gain controller once injection is
- // implemented.
- private_submodules_->gain_controller2.reset(new GainController2());
-
- RTC_LOG(LS_INFO) << "Capture analyzer activated: "
- << !!private_submodules_->capture_analyzer
- << "\nCapture post processor activated: "
- << !!private_submodules_->capture_post_processor
- << "\nRender pre processor activated: "
- << !!private_submodules_->render_pre_processor;
+ // If no echo detector is injected, use the ResidualEchoDetector.
+ if (!private_submodules_->echo_detector) {
+ private_submodules_->echo_detector =
+ new rtc::RefCountedObject<ResidualEchoDetector>();
}
+ private_submodules_->echo_cancellation.reset(new EchoCancellationImpl());
+ private_submodules_->echo_control_mobile.reset(new EchoControlMobileImpl());
+ // TODO(alessiob): Move the injected gain controller once injection is
+ // implemented.
+ private_submodules_->gain_controller2.reset(new GainController2());
+
+ RTC_LOG(LS_INFO) << "Capture analyzer activated: "
+ << !!private_submodules_->capture_analyzer
+ << "\nCapture post processor activated: "
+ << !!private_submodules_->capture_post_processor
+ << "\nRender pre processor activated: "
+ << !!private_submodules_->render_pre_processor;
+
SetExtraOptions(config);
}
diff --git a/modules/audio_processing/gain_control_impl.cc b/modules/audio_processing/gain_control_impl.cc
index 26ab1b4..cd21e4c 100644
--- a/modules/audio_processing/gain_control_impl.cc
+++ b/modules/audio_processing/gain_control_impl.cc
@@ -89,10 +89,8 @@
int GainControlImpl::instance_counter_ = 0;
-GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_render,
- rtc::CriticalSection* crit_capture)
- : crit_render_(crit_render),
- crit_capture_(crit_capture),
+GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_capture)
+ : crit_capture_(crit_capture),
data_dumper_(new ApmDataDumper(instance_counter_)),
mode_(kAdaptiveAnalog),
minimum_capture_level_(0),
@@ -103,7 +101,6 @@
analog_capture_level_(0),
was_analog_level_set_(false),
stream_is_saturated_(false) {
- RTC_DCHECK(crit_render);
RTC_DCHECK(crit_capture);
}
@@ -267,7 +264,6 @@
}
int GainControlImpl::Enable(bool enable) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
if (enable && !enabled_) {
enabled_ = enable; // Must be set before Initialize() is called.
@@ -287,7 +283,6 @@
}
int GainControlImpl::set_mode(Mode mode) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
if (MapSetting(mode) == -1) {
return AudioProcessing::kBadParameterError;
@@ -354,10 +349,8 @@
if (level > 31 || level < 0) {
return AudioProcessing::kBadParameterError;
}
- {
- rtc::CritScope cs(crit_capture_);
- target_level_dbfs_ = level;
- }
+ rtc::CritScope cs(crit_capture_);
+ target_level_dbfs_ = level;
return Configure();
}
@@ -370,18 +363,14 @@
if (gain < 0 || gain > 90) {
return AudioProcessing::kBadParameterError;
}
- {
- rtc::CritScope cs(crit_capture_);
- compression_gain_db_ = gain;
- }
+ rtc::CritScope cs(crit_capture_);
+ compression_gain_db_ = gain;
return Configure();
}
int GainControlImpl::enable_limiter(bool enable) {
- {
- rtc::CritScope cs(crit_capture_);
- limiter_enabled_ = enable;
- }
+ rtc::CritScope cs(crit_capture_);
+ limiter_enabled_ = enable;
return Configure();
}
@@ -391,7 +380,6 @@
}
void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
- rtc::CritScope cs_render(crit_render_);
rtc::CritScope cs_capture(crit_capture_);
data_dumper_->InitiateNewSetOfRecordings();
@@ -415,8 +403,6 @@
}
int GainControlImpl::Configure() {
- rtc::CritScope cs_render(crit_render_);
- rtc::CritScope cs_capture(crit_capture_);
WebRtcAgcConfig config;
// TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
// change the interface.
diff --git a/modules/audio_processing/gain_control_impl.h b/modules/audio_processing/gain_control_impl.h
index fc781d4..9412e88 100644
--- a/modules/audio_processing/gain_control_impl.h
+++ b/modules/audio_processing/gain_control_impl.h
@@ -30,8 +30,7 @@
class GainControlImpl : public GainControl {
public:
- GainControlImpl(rtc::CriticalSection* crit_render,
- rtc::CriticalSection* crit_capture);
+ GainControlImpl(rtc::CriticalSection* crit_capture);
~GainControlImpl() override;
void ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio);
@@ -67,9 +66,8 @@
int analog_level_maximum() const override;
bool stream_is_saturated() const override;
- int Configure();
+ int Configure() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
- rtc::CriticalSection* const crit_render_ RTC_ACQUIRED_BEFORE(crit_capture_);
rtc::CriticalSection* const crit_capture_;
std::unique_ptr<ApmDataDumper> data_dumper_;
diff --git a/modules/audio_processing/gain_control_unittest.cc b/modules/audio_processing/gain_control_unittest.cc
index 62908c7..891e78a 100644
--- a/modules/audio_processing/gain_control_unittest.cc
+++ b/modules/audio_processing/gain_control_unittest.cc
@@ -72,9 +72,8 @@
int analog_level_max,
int achieved_stream_analog_level_reference,
rtc::ArrayView<const float> output_reference) {
- rtc::CriticalSection crit_render;
rtc::CriticalSection crit_capture;
- GainControlImpl gain_controller(&crit_render, &crit_capture);
+ GainControlImpl gain_controller(&crit_capture);
SetupComponent(sample_rate_hz, mode, target_level_dbfs, stream_analog_level,
compression_gain_db, enable_limiter, analog_level_min,
analog_level_max, &gain_controller);
diff --git a/test/fuzzers/agc_fuzzer.cc b/test/fuzzers/agc_fuzzer.cc
index f2c9048..9854a78 100644
--- a/test/fuzzers/agc_fuzzer.cc
+++ b/test/fuzzers/agc_fuzzer.cc
@@ -114,8 +114,7 @@
}
test::FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size));
rtc::CriticalSection crit_capture;
- rtc::CriticalSection crit_render;
- auto gci = absl::make_unique<GainControlImpl>(&crit_render, &crit_capture);
+ auto gci = absl::make_unique<GainControlImpl>(&crit_capture);
FuzzGainController(&fuzz_data, gci.get());
}
} // namespace webrtc