Add replacement interface for webrtc::GainConrol

The pointer-to-submodule interfaces are being removed.
This CL:
1) introduces AudioProcessing::Config::GainController1 with most config,
2) adds functions to APM for setting and getting analog gain,
3) creates a temporary GainControlConfigProxy to support the transition
   to the new config.
4) Moves the lock references in GainControlForExperimentalAgc and
   GainControlImpl into the GainControlConfigProxy, as it becomes the
   sole AGC object with functionality exposed to the client.

Bug: webrtc:9947, webrtc:9878
Change-Id: Ic31e15e9bb26d6497a92b77874e0b6cab21ff2b2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/126485
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27316}
This commit is contained in:
Sam Zackrisson
2019-03-27 13:28:08 +01:00
committed by Commit Bot
parent 4bd3177ae5
commit f0d1c03c31
24 changed files with 750 additions and 324 deletions

View File

@ -154,6 +154,7 @@ rtc_static_library("audio_processing") {
":audio_processing_c",
":audio_processing_statistics",
":config",
":gain_control_config_proxy",
":gain_control_interface",
":noise_suppression_proxy",
"../..:webrtc_common",
@ -214,6 +215,19 @@ rtc_source_set("gain_control_interface") {
]
}
rtc_source_set("gain_control_config_proxy") {
sources = [
"gain_control_config_proxy.cc",
"gain_control_config_proxy.h",
]
deps = [
":api",
":gain_control_interface",
"../../rtc_base:criticalsection",
"../../rtc_base:macromagic",
]
}
rtc_source_set("noise_suppression_proxy") {
sources = [
"noise_suppression_proxy.cc",
@ -414,6 +428,7 @@ if (rtc_include_tests) {
"config_unittest.cc",
"echo_cancellation_impl_unittest.cc",
"echo_control_mobile_unittest.cc",
"gain_control_config_proxy_unittest.cc",
"gain_controller2_unittest.cc",
"splitting_filter_unittest.cc",
"test/fake_recording_device_unittest.cc",
@ -438,6 +453,7 @@ if (rtc_include_tests) {
":audioproc_test_utils",
":config",
":file_audio_generator_unittests",
":gain_control_config_proxy",
":mocks",
"../..:webrtc_common",
"../../api:array_view",

View File

@ -188,6 +188,10 @@ void AecDumpImpl::WriteRuntimeSetting(
setting->set_custom_render_processing_setting(x);
break;
}
case AudioProcessing::RuntimeSetting::Type::kCaptureCompressionGain:
// Runtime AGC1 compression gain is ignored.
// TODO(http://bugs.webrtc.org/10432): Store compression gain in aecdumps.
break;
case AudioProcessing::RuntimeSetting::Type::kNotSpecified:
RTC_NOTREACHED();
break;

View File

@ -28,6 +28,7 @@
#include "modules/audio_processing/common.h"
#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/echo_control_mobile_impl.h"
#include "modules/audio_processing/gain_control_config_proxy.h"
#include "modules/audio_processing/gain_control_for_experimental_agc.h"
#include "modules/audio_processing/gain_control_impl.h"
#include "modules/audio_processing/gain_controller2.h"
@ -127,6 +128,19 @@ NoiseSuppression::Level NsConfigLevelToInterfaceLevel(
}
}
GainControl::Mode Agc1ConfigModeToInterfaceMode(
AudioProcessing::Config::GainController1::Mode mode) {
using Agc1Config = AudioProcessing::Config::GainController1;
switch (mode) {
case Agc1Config::kAdaptiveAnalog:
return GainControl::kAdaptiveAnalog;
case Agc1Config::kAdaptiveDigital:
return GainControl::kAdaptiveDigital;
case Agc1Config::kFixedDigital:
return GainControl::kFixedDigital;
}
}
// Maximum lengths that frame of samples being passed from the render side to
// the capture side can have (does not apply to AEC3).
static const size_t kMaxAllowedValuesOfSamplesPerBand = 160;
@ -254,13 +268,14 @@ struct AudioProcessingImpl::ApmPublicSubmodules {
// Accessed externally of APM without any lock acquired.
// TODO(bugs.webrtc.org/9947): Move these submodules into private_submodules_
// when their pointer-to-submodule API functions are gone.
std::unique_ptr<GainControlImpl> gain_control;
std::unique_ptr<LevelEstimatorImpl> level_estimator;
std::unique_ptr<NoiseSuppressionImpl> noise_suppression;
std::unique_ptr<NoiseSuppressionProxy> noise_suppression_proxy;
std::unique_ptr<VoiceDetectionImpl> voice_detection;
std::unique_ptr<GainControlImpl> gain_control;
std::unique_ptr<GainControlForExperimentalAgc>
gain_control_for_experimental_agc;
std::unique_ptr<GainControlConfigProxy> gain_control_config_proxy;
// Accessed internally from both render and capture.
std::unique_ptr<TransientSuppressor> transient_suppressor;
@ -393,7 +408,7 @@ AudioProcessingImpl::AudioProcessingImpl(
capture_nonlocked_.echo_controller_enabled =
static_cast<bool>(echo_control_factory_);
public_submodules_->gain_control.reset(new GainControlImpl(&crit_capture_));
public_submodules_->gain_control.reset(new GainControlImpl());
public_submodules_->level_estimator.reset(
new LevelEstimatorImpl(&crit_capture_));
public_submodules_->noise_suppression.reset(
@ -403,8 +418,10 @@ AudioProcessingImpl::AudioProcessingImpl(
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_));
new GainControlForExperimentalAgc(
public_submodules_->gain_control.get()));
public_submodules_->gain_control_config_proxy.reset(
new GainControlConfigProxy(&crit_capture_, this, agc1()));
// If no echo detector is injected, use the ResidualEchoDetector.
if (!private_submodules_->echo_detector) {
@ -680,6 +697,20 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
config_.echo_canceller.legacy_moderate_suppression_level !=
config.echo_canceller.legacy_moderate_suppression_level);
const bool agc1_config_changed =
config_.gain_controller1.enabled != config.gain_controller1.enabled ||
config_.gain_controller1.mode != config.gain_controller1.mode ||
config_.gain_controller1.target_level_dbfs !=
config.gain_controller1.target_level_dbfs ||
config_.gain_controller1.compression_gain_db !=
config.gain_controller1.compression_gain_db ||
config_.gain_controller1.enable_limiter !=
config.gain_controller1.enable_limiter ||
config_.gain_controller1.analog_level_minimum !=
config.gain_controller1.analog_level_minimum ||
config_.gain_controller1.analog_level_maximum !=
config.gain_controller1.analog_level_maximum;
config_ = config;
if (aec_config_changed) {
@ -696,6 +727,10 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
RTC_LOG(LS_INFO) << "Highpass filter activated: "
<< config_.high_pass_filter.enabled;
if (agc1_config_changed) {
ApplyAgc1Config(config_.gain_controller1);
}
const bool config_ok = GainController2::Validate(config_.gain_controller2);
if (!config_ok) {
RTC_LOG(LS_ERROR) << "AudioProcessing module config error\n"
@ -730,6 +765,38 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
}
}
void AudioProcessingImpl::ApplyAgc1Config(
const Config::GainController1& config) {
GainControl* agc = agc1();
int error = agc->Enable(config.enabled);
RTC_DCHECK_EQ(kNoError, error);
error = agc->set_mode(Agc1ConfigModeToInterfaceMode(config.mode));
RTC_DCHECK_EQ(kNoError, error);
error = agc->set_target_level_dbfs(config.target_level_dbfs);
RTC_DCHECK_EQ(kNoError, error);
error = agc->set_compression_gain_db(config.compression_gain_db);
RTC_DCHECK_EQ(kNoError, error);
error = agc->enable_limiter(config.enable_limiter);
RTC_DCHECK_EQ(kNoError, error);
error = agc->set_analog_level_limits(config.analog_level_minimum,
config.analog_level_maximum);
RTC_DCHECK_EQ(kNoError, error);
}
GainControl* AudioProcessingImpl::agc1() {
if (constants_.use_experimental_agc) {
return public_submodules_->gain_control_for_experimental_agc.get();
}
return public_submodules_->gain_control.get();
}
const GainControl* AudioProcessingImpl::agc1() const {
if (constants_.use_experimental_agc) {
return public_submodules_->gain_control_for_experimental_agc.get();
}
return public_submodules_->gain_control.get();
}
void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) {
// Run in a single-threaded manner when setting the extra options.
rtc::CritScope cs_render(&crit_render_);
@ -793,6 +860,7 @@ void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
RTC_NOTREACHED();
return;
case RuntimeSetting::Type::kCapturePreGain:
case RuntimeSetting::Type::kCaptureCompressionGain:
capture_runtime_settings_enqueuer_.Enqueue(setting);
return;
}
@ -919,6 +987,15 @@ void AudioProcessingImpl::HandleCaptureRuntimeSettings() {
}
// TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump.
break;
case RuntimeSetting::Type::kCaptureCompressionGain: {
float value;
setting.GetFloat(&value);
int int_value = static_cast<int>(value + .5f);
config_.gain_controller1.compression_gain_db = int_value;
int error = agc1()->set_compression_gain_db(int_value);
RTC_DCHECK_EQ(kNoError, error);
break;
}
case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
RTC_NOTREACHED();
break;
@ -941,9 +1018,8 @@ void AudioProcessingImpl::HandleRenderRuntimeSettings() {
private_submodules_->render_pre_processor->SetRuntimeSetting(setting);
}
break;
case RuntimeSetting::Type::kCapturePreGain:
RTC_NOTREACHED();
break;
case RuntimeSetting::Type::kCapturePreGain: // fall-through
case RuntimeSetting::Type::kCaptureCompressionGain: // fall-through
case RuntimeSetting::Type::kNotSpecified:
RTC_NOTREACHED();
break;
@ -1235,7 +1311,7 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
if (private_submodules_->echo_controller) {
// Detect and flag any change in the analog gain.
int analog_mic_level = gain_control()->stream_analog_level();
int analog_mic_level = agc1()->stream_analog_level();
capture_.echo_path_gain_change =
capture_.prev_analog_mic_level != analog_mic_level &&
capture_.prev_analog_mic_level != -1;
@ -1389,7 +1465,7 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
if (config_.gain_controller2.enabled) {
private_submodules_->gain_controller2->NotifyAnalogLevel(
gain_control()->stream_analog_level());
agc1()->stream_analog_level());
private_submodules_->gain_controller2->Process(capture_buffer);
}
@ -1620,6 +1696,17 @@ int AudioProcessingImpl::delay_offset_ms() const {
return capture_.delay_offset_ms;
}
void AudioProcessingImpl::set_stream_analog_level(int level) {
rtc::CritScope cs_capture(&crit_capture_);
int error = agc1()->set_stream_analog_level(level);
RTC_DCHECK_EQ(kNoError, error);
}
int AudioProcessingImpl::recommended_stream_analog_level() const {
rtc::CritScope cs_capture(&crit_capture_);
return agc1()->stream_analog_level();
}
void AudioProcessingImpl::AttachAecDump(std::unique_ptr<AecDump> aec_dump) {
RTC_DCHECK(aec_dump);
rtc::CritScope cs_render(&crit_render_);
@ -1707,10 +1794,7 @@ AudioProcessingStats AudioProcessingImpl::GetStatistics(
}
GainControl* AudioProcessingImpl::gain_control() const {
if (constants_.use_experimental_agc) {
return public_submodules_->gain_control_for_experimental_agc.get();
}
return public_submodules_->gain_control.get();
return public_submodules_->gain_control_config_proxy.get();
}
LevelEstimator* AudioProcessingImpl::level_estimator() const {
@ -2032,7 +2116,7 @@ void AudioProcessingImpl::RecordAudioProcessingState() {
audio_proc_state.delay = capture_nonlocked_.stream_delay_ms;
audio_proc_state.drift =
private_submodules_->echo_cancellation->stream_drift_samples();
audio_proc_state.level = gain_control()->stream_analog_level();
audio_proc_state.level = agc1()->stream_analog_level();
audio_proc_state.keypress = capture_.key_pressed;
aec_dump_->AddAudioProcessingState(audio_proc_state);
}

View File

@ -84,6 +84,8 @@ class AudioProcessingImpl : public AudioProcessing {
void set_delay_offset_ms(int offset) override;
int delay_offset_ms() const override;
void set_stream_key_pressed(bool key_pressed) override;
void set_stream_analog_level(int level) override;
int recommended_stream_analog_level() const override;
// Render-side exclusive methods possibly running APM in a
// multi-threaded manner. Acquire the render lock.
@ -255,6 +257,13 @@ class AudioProcessingImpl : public AudioProcessing {
void HandleCaptureRuntimeSettings()
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
void HandleRenderRuntimeSettings() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_);
void ApplyAgc1Config(const Config::GainController1& agc_config)
RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
// Returns a direct pointer to the AGC1 submodule: either a GainControlImpl
// or GainControlForExperimentalAgc instance.
GainControl* agc1();
const GainControl* agc1() const;
void EmptyQueuedRenderAudio();
void AllocateRenderQueue()

View File

@ -182,17 +182,21 @@ void EnableAllAPComponents(AudioProcessing* ap) {
apm_config.echo_canceller.enabled = true;
#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
apm_config.echo_canceller.mobile_mode = true;
EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveDigital));
EXPECT_NOERR(ap->gain_control()->Enable(true));
apm_config.gain_controller1.enabled = true;
apm_config.gain_controller1.mode =
AudioProcessing::Config::GainController1::kAdaptiveDigital;
#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
// TODO(peah): Update tests to instead use AEC3.
apm_config.echo_canceller.use_legacy_aec = true;
apm_config.echo_canceller.mobile_mode = false;
apm_config.echo_canceller.legacy_moderate_suppression_level = true;
EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
EXPECT_NOERR(ap->gain_control()->set_analog_level_limits(0, 255));
EXPECT_NOERR(ap->gain_control()->Enable(true));
apm_config.gain_controller1.enabled = true;
apm_config.gain_controller1.mode =
AudioProcessing::Config::GainController1::kAdaptiveAnalog;
apm_config.gain_controller1.analog_level_minimum = 0;
apm_config.gain_controller1.analog_level_maximum = 255;
#endif
apm_config.high_pass_filter.enabled = true;
@ -958,12 +962,7 @@ TEST_F(ApmTest, GainControl) {
apm_->gain_control()->set_mode(mode[i]));
EXPECT_EQ(mode[i], apm_->gain_control()->mode());
}
// Testing invalid target levels
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_target_level_dbfs(-3));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_target_level_dbfs(-40));
// Testing valid target levels
// Testing target levels
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_target_level_dbfs(
apm_->gain_control()->target_level_dbfs()));
@ -975,13 +974,7 @@ TEST_F(ApmTest, GainControl) {
EXPECT_EQ(level_dbfs[i], apm_->gain_control()->target_level_dbfs());
}
// Testing invalid compression gains
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_compression_gain_db(-1));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_compression_gain_db(100));
// Testing valid compression gains
// Testing compression gains
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_compression_gain_db(
apm_->gain_control()->compression_gain_db()));
@ -990,6 +983,7 @@ TEST_F(ApmTest, GainControl) {
for (size_t i = 0; i < arraysize(gain_db); i++) {
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_compression_gain_db(gain_db[i]));
ProcessStreamChooser(kFloatFormat);
EXPECT_EQ(gain_db[i], apm_->gain_control()->compression_gain_db());
}
@ -999,19 +993,7 @@ TEST_F(ApmTest, GainControl) {
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->enable_limiter(true));
EXPECT_TRUE(apm_->gain_control()->is_limiter_enabled());
// Testing invalid level limits
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_analog_level_limits(-1, 512));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_analog_level_limits(100000, 512));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_analog_level_limits(512, -1));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_analog_level_limits(512, 100000));
EXPECT_EQ(apm_->kBadParameterError,
apm_->gain_control()->set_analog_level_limits(512, 255));
// Testing valid level limits
// Testing level limits
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_analog_level_limits(
apm_->gain_control()->analog_level_minimum(),
@ -1038,6 +1020,46 @@ TEST_F(ApmTest, GainControl) {
EXPECT_FALSE(apm_->gain_control()->is_enabled());
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(ApmTest, GainControlDiesOnTooLowTargetLevelDbfs) {
EXPECT_DEATH(apm_->gain_control()->set_target_level_dbfs(-1), "");
}
TEST_F(ApmTest, GainControlDiesOnTooHighTargetLevelDbfs) {
EXPECT_DEATH(apm_->gain_control()->set_target_level_dbfs(32), "");
}
TEST_F(ApmTest, GainControlDiesOnTooLowCompressionGainDb) {
EXPECT_DEATH(apm_->gain_control()->set_compression_gain_db(-1), "");
}
TEST_F(ApmTest, GainControlDiesOnTooHighCompressionGainDb) {
EXPECT_DEATH(apm_->gain_control()->set_compression_gain_db(91), "");
}
TEST_F(ApmTest, GainControlDiesOnTooLowAnalogLevelLowerLimit) {
EXPECT_DEATH(apm_->gain_control()->set_analog_level_limits(-1, 512), "");
}
TEST_F(ApmTest, GainControlDiesOnTooHighAnalogLevelUpperLimit) {
EXPECT_DEATH(apm_->gain_control()->set_analog_level_limits(512, 65536), "");
}
TEST_F(ApmTest, GainControlDiesOnInvertedAnalogLevelLimits) {
EXPECT_DEATH(apm_->gain_control()->set_analog_level_limits(512, 255), "");
}
TEST_F(ApmTest, ApmDiesOnTooLowAnalogLevel) {
apm_->gain_control()->set_analog_level_limits(255, 512);
EXPECT_DEATH(apm_->set_stream_analog_level(254), "");
}
TEST_F(ApmTest, ApmDiesOnTooHighAnalogLevel) {
apm_->gain_control()->set_analog_level_limits(255, 512);
EXPECT_DEATH(apm_->set_stream_analog_level(513), "");
}
#endif
void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
EXPECT_EQ(apm_->kNoError,

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_processing/gain_control_config_proxy.h"
namespace webrtc {
namespace {
AudioProcessing::Config::GainController1::Mode InterfaceModeToConfigMode(
GainControl::Mode agc_mode) {
using AgcConfig = AudioProcessing::Config::GainController1;
switch (agc_mode) {
case GainControl::kAdaptiveAnalog:
return AgcConfig::kAdaptiveAnalog;
case GainControl::kAdaptiveDigital:
return AgcConfig::kAdaptiveDigital;
case GainControl::kFixedDigital:
return AgcConfig::kFixedDigital;
}
}
} // namespace
GainControlConfigProxy::GainControlConfigProxy(
rtc::CriticalSection* crit_capture,
AudioProcessing* apm,
GainControl* agc)
: crit_capture_(crit_capture), apm_(apm), agc_(agc) {
RTC_DCHECK(apm);
RTC_DCHECK(agc);
RTC_DCHECK(crit_capture);
}
GainControlConfigProxy::~GainControlConfigProxy() = default;
int GainControlConfigProxy::set_stream_analog_level(int level) {
apm_->set_stream_analog_level(level);
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::stream_analog_level() const {
return apm_->recommended_stream_analog_level();
}
int GainControlConfigProxy::Enable(bool enable) {
auto apm_config = apm_->GetConfig();
apm_config.gain_controller1.enabled = enable;
apm_->ApplyConfig(apm_config);
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::set_mode(Mode mode) {
auto config = apm_->GetConfig();
config.gain_controller1.mode = InterfaceModeToConfigMode(mode);
apm_->ApplyConfig(config);
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::set_target_level_dbfs(int level) {
auto config = apm_->GetConfig();
config.gain_controller1.target_level_dbfs = level;
apm_->ApplyConfig(config);
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::set_compression_gain_db(int gain) {
apm_->SetRuntimeSetting(
AudioProcessing::RuntimeSetting::CreateCompressionGainDb(gain));
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::enable_limiter(bool enable) {
auto config = apm_->GetConfig();
config.gain_controller1.enable_limiter = enable;
apm_->ApplyConfig(config);
return AudioProcessing::kNoError;
}
int GainControlConfigProxy::set_analog_level_limits(int minimum, int maximum) {
auto config = apm_->GetConfig();
config.gain_controller1.analog_level_minimum = minimum;
config.gain_controller1.analog_level_maximum = maximum;
apm_->ApplyConfig(config);
return AudioProcessing::kNoError;
}
bool GainControlConfigProxy::is_limiter_enabled() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->is_limiter_enabled();
}
int GainControlConfigProxy::compression_gain_db() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->compression_gain_db();
}
bool GainControlConfigProxy::is_enabled() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->is_enabled();
}
GainControl::Mode GainControlConfigProxy::mode() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->mode();
}
int GainControlConfigProxy::target_level_dbfs() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->target_level_dbfs();
}
int GainControlConfigProxy::analog_level_minimum() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->analog_level_minimum();
}
int GainControlConfigProxy::analog_level_maximum() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->analog_level_maximum();
}
bool GainControlConfigProxy::stream_is_saturated() const {
rtc::CritScope cs_capture(crit_capture_);
return agc_->stream_is_saturated();
}
} // namespace webrtc

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_AUDIO_PROCESSING_GAIN_CONTROL_CONFIG_PROXY_H_
#define MODULES_AUDIO_PROCESSING_GAIN_CONTROL_CONFIG_PROXY_H_
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/include/gain_control.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// This class forwards all gain control configuration to the audio processing
// module, for compatibility with AudioProcessing::Config.
class GainControlConfigProxy : public GainControl {
public:
GainControlConfigProxy(rtc::CriticalSection* crit_capture,
AudioProcessing* apm,
GainControl* agc);
GainControlConfigProxy(const GainControlConfigProxy&) = delete;
GainControlConfigProxy& operator=(const GainControlConfigProxy&) = delete;
~GainControlConfigProxy() override;
private:
// GainControl API during processing.
int set_stream_analog_level(int level) override;
int stream_analog_level() const override;
// GainControl config setters.
int Enable(bool enable) override;
int set_mode(Mode mode) override;
int set_target_level_dbfs(int level) override;
int set_compression_gain_db(int gain) override;
int enable_limiter(bool enable) override;
int set_analog_level_limits(int minimum, int maximum) override;
// GainControl config getters.
bool is_enabled() const override;
bool is_limiter_enabled() const override;
int compression_gain_db() const override;
int target_level_dbfs() const override;
int analog_level_minimum() const override;
int analog_level_maximum() const override;
bool stream_is_saturated() const override;
Mode mode() const override;
rtc::CriticalSection* crit_capture_ = nullptr;
AudioProcessing* apm_ = nullptr;
GainControl* agc_ RTC_GUARDED_BY(crit_capture_) = nullptr;
};
} // namespace webrtc
#endif // MODULES_AUDIO_PROCESSING_GAIN_CONTROL_CONFIG_PROXY_H_

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_processing/gain_control_config_proxy.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "modules/audio_processing/include/mock_audio_processing.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/ref_counted_object.h"
#include "test/gtest.h"
namespace webrtc {
class GainControlConfigProxyTest : public testing::Test {
protected:
GainControlConfigProxyTest()
: apm_(new rtc::RefCountedObject<
testing::StrictMock<test::MockAudioProcessing>>()),
agc_(),
proxy_(&lock_, apm_, &agc_) {
EXPECT_CALL(*apm_, GetConfig())
.WillRepeatedly(testing::ReturnPointee(&apm_config_));
EXPECT_CALL(*apm_, ApplyConfig(testing::_))
.WillRepeatedly(testing::SaveArg<0>(&apm_config_));
}
GainControl* proxy() { return &proxy_; }
rtc::scoped_refptr<testing::StrictMock<test::MockAudioProcessing>> apm_;
testing::StrictMock<test::MockGainControl> agc_;
AudioProcessing::Config apm_config_;
private:
rtc::CriticalSection lock_;
GainControlConfigProxy proxy_;
};
// GainControl API during processing.
TEST_F(GainControlConfigProxyTest, SetStreamAnalogLevel) {
EXPECT_CALL(*apm_, set_stream_analog_level(100));
proxy()->set_stream_analog_level(100);
}
TEST_F(GainControlConfigProxyTest, StreamAnalogLevel) {
EXPECT_CALL(*apm_, recommended_stream_analog_level())
.WillOnce(testing::Return(100));
EXPECT_EQ(100, proxy()->stream_analog_level());
}
// GainControl config setters.
TEST_F(GainControlConfigProxyTest, SetEnable) {
proxy()->Enable(true);
EXPECT_TRUE(apm_config_.gain_controller1.enabled);
proxy()->Enable(false);
EXPECT_FALSE(apm_config_.gain_controller1.enabled);
}
TEST_F(GainControlConfigProxyTest, SetMode) {
proxy()->set_mode(GainControl::Mode::kAdaptiveAnalog);
EXPECT_EQ(apm_config_.gain_controller1.kAdaptiveAnalog,
apm_config_.gain_controller1.mode);
proxy()->set_mode(GainControl::Mode::kAdaptiveDigital);
EXPECT_EQ(apm_config_.gain_controller1.kAdaptiveDigital,
apm_config_.gain_controller1.mode);
proxy()->set_mode(GainControl::Mode::kFixedDigital);
EXPECT_EQ(apm_config_.gain_controller1.kFixedDigital,
apm_config_.gain_controller1.mode);
}
TEST_F(GainControlConfigProxyTest, SetTargetLevelDbfs) {
proxy()->set_target_level_dbfs(17);
EXPECT_EQ(17, apm_config_.gain_controller1.target_level_dbfs);
}
TEST_F(GainControlConfigProxyTest, SetCompressionGainDb) {
AudioProcessing::RuntimeSetting setting;
EXPECT_CALL(*apm_, SetRuntimeSetting(testing::_))
.WillOnce(testing::SaveArg<0>(&setting));
proxy()->set_compression_gain_db(17);
EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kCaptureCompressionGain,
setting.type());
float value;
setting.GetFloat(&value);
EXPECT_EQ(17, static_cast<int>(value + .5f));
}
TEST_F(GainControlConfigProxyTest, SetEnableLimiter) {
proxy()->enable_limiter(true);
EXPECT_TRUE(apm_config_.gain_controller1.enable_limiter);
proxy()->enable_limiter(false);
EXPECT_FALSE(apm_config_.gain_controller1.enable_limiter);
}
TEST_F(GainControlConfigProxyTest, SetAnalogLevelLimits) {
proxy()->set_analog_level_limits(100, 300);
EXPECT_EQ(100, apm_config_.gain_controller1.analog_level_minimum);
EXPECT_EQ(300, apm_config_.gain_controller1.analog_level_maximum);
}
TEST_F(GainControlConfigProxyTest, GetEnabled) {
EXPECT_CALL(agc_, is_enabled())
.WillOnce(testing::Return(true))
.WillOnce(testing::Return(false));
EXPECT_TRUE(proxy()->is_enabled());
EXPECT_FALSE(proxy()->is_enabled());
}
TEST_F(GainControlConfigProxyTest, GetLimiterEnabled) {
EXPECT_CALL(agc_, is_enabled())
.WillOnce(testing::Return(true))
.WillOnce(testing::Return(false));
EXPECT_TRUE(proxy()->is_enabled());
EXPECT_FALSE(proxy()->is_enabled());
}
TEST_F(GainControlConfigProxyTest, GetCompressionGainDb) {
EXPECT_CALL(agc_, compression_gain_db()).WillOnce(testing::Return(17));
EXPECT_EQ(17, proxy()->compression_gain_db());
}
TEST_F(GainControlConfigProxyTest, GetTargetLevelDbfs) {
EXPECT_CALL(agc_, target_level_dbfs()).WillOnce(testing::Return(17));
EXPECT_EQ(17, proxy()->target_level_dbfs());
}
TEST_F(GainControlConfigProxyTest, GetAnalogLevelMinimum) {
EXPECT_CALL(agc_, analog_level_minimum()).WillOnce(testing::Return(17));
EXPECT_EQ(17, proxy()->analog_level_minimum());
}
TEST_F(GainControlConfigProxyTest, GetAnalogLevelMaximum) {
EXPECT_CALL(agc_, analog_level_maximum()).WillOnce(testing::Return(17));
EXPECT_EQ(17, proxy()->analog_level_maximum());
}
TEST_F(GainControlConfigProxyTest, GetStreamIsSaturated) {
EXPECT_CALL(agc_, stream_is_saturated())
.WillOnce(testing::Return(true))
.WillOnce(testing::Return(false));
EXPECT_TRUE(proxy()->stream_is_saturated());
EXPECT_FALSE(proxy()->stream_is_saturated());
}
TEST_F(GainControlConfigProxyTest, GetMode) {
EXPECT_CALL(agc_, mode())
.WillOnce(testing::Return(GainControl::Mode::kAdaptiveAnalog))
.WillOnce(testing::Return(GainControl::Mode::kAdaptiveDigital))
.WillOnce(testing::Return(GainControl::Mode::kFixedDigital));
EXPECT_EQ(GainControl::Mode::kAdaptiveAnalog, proxy()->mode());
EXPECT_EQ(GainControl::Mode::kAdaptiveDigital, proxy()->mode());
EXPECT_EQ(GainControl::Mode::kFixedDigital, proxy()->mode());
}
} // namespace webrtc

View File

@ -20,13 +20,11 @@ namespace webrtc {
int GainControlForExperimentalAgc::instance_counter_ = 0;
GainControlForExperimentalAgc::GainControlForExperimentalAgc(
GainControl* gain_control,
rtc::CriticalSection* crit_capture)
GainControl* gain_control)
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_counter_))),
real_gain_control_(gain_control),
volume_(0),
crit_capture_(crit_capture) {}
volume_(0) {}
GainControlForExperimentalAgc::~GainControlForExperimentalAgc() = default;
@ -39,7 +37,6 @@ bool GainControlForExperimentalAgc::is_enabled() const {
}
int GainControlForExperimentalAgc::set_stream_analog_level(int level) {
rtc::CritScope cs_capture(crit_capture_);
data_dumper_->DumpRaw("experimental_gain_control_set_stream_analog_level", 1,
&level);
do_log_level_ = true;
@ -47,8 +44,7 @@ int GainControlForExperimentalAgc::set_stream_analog_level(int level) {
return AudioProcessing::kNoError;
}
int GainControlForExperimentalAgc::stream_analog_level() {
rtc::CritScope cs_capture(crit_capture_);
int GainControlForExperimentalAgc::stream_analog_level() const {
if (do_log_level_) {
data_dumper_->DumpRaw("experimental_gain_control_stream_analog_level", 1,
&volume_);
@ -107,12 +103,10 @@ bool GainControlForExperimentalAgc::stream_is_saturated() const {
}
void GainControlForExperimentalAgc::SetMicVolume(int volume) {
rtc::CritScope cs_capture(crit_capture_);
volume_ = volume;
}
int GainControlForExperimentalAgc::GetMicVolume() {
rtc::CritScope cs_capture(crit_capture_);
return volume_;
}

View File

@ -13,8 +13,6 @@
#include "modules/audio_processing/agc/agc_manager_direct.h"
#include "modules/audio_processing/include/audio_processing.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/thread_checker.h"
namespace webrtc {
@ -35,15 +33,18 @@ class ApmDataDumper;
class GainControlForExperimentalAgc : public GainControl,
public VolumeCallbacks {
public:
GainControlForExperimentalAgc(GainControl* gain_control,
rtc::CriticalSection* crit_capture);
explicit GainControlForExperimentalAgc(GainControl* gain_control);
GainControlForExperimentalAgc(const GainControlForExperimentalAgc&) = delete;
GainControlForExperimentalAgc& operator=(
const GainControlForExperimentalAgc&) = delete;
~GainControlForExperimentalAgc() override;
// GainControl implementation.
int Enable(bool enable) override;
bool is_enabled() const override;
int set_stream_analog_level(int level) override;
int stream_analog_level() override;
int stream_analog_level() const override;
int set_mode(Mode mode) override;
Mode mode() const override;
int set_target_level_dbfs(int level) override;
@ -67,10 +68,8 @@ class GainControlForExperimentalAgc : public GainControl,
std::unique_ptr<ApmDataDumper> data_dumper_;
GainControl* real_gain_control_;
int volume_;
rtc::CriticalSection* crit_capture_;
bool do_log_level_ = true;
mutable bool do_log_level_ = true;
static int instance_counter_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GainControlForExperimentalAgc);
};
} // namespace webrtc

View File

@ -89,9 +89,8 @@ class GainControlImpl::GainController {
int GainControlImpl::instance_counter_ = 0;
GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_capture)
: crit_capture_(crit_capture),
data_dumper_(new ApmDataDumper(instance_counter_)),
GainControlImpl::GainControlImpl()
: data_dumper_(new ApmDataDumper(instance_counter_)),
mode_(kAdaptiveAnalog),
minimum_capture_level_(0),
maximum_capture_level_(255),
@ -100,15 +99,12 @@ GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_capture)
compression_gain_db_(9),
analog_capture_level_(0),
was_analog_level_set_(false),
stream_is_saturated_(false) {
RTC_DCHECK(crit_capture);
}
stream_is_saturated_(false) {}
GainControlImpl::~GainControlImpl() {}
void GainControlImpl::ProcessRenderAudio(
rtc::ArrayView<const int16_t> packed_render_audio) {
rtc::CritScope cs_capture(crit_capture_);
if (!enabled_) {
return;
}
@ -131,8 +127,6 @@ void GainControlImpl::PackRenderAudioBuffer(
}
int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
rtc::CritScope cs(crit_capture_);
if (!enabled_) {
return AudioProcessing::kNoError;
}
@ -178,8 +172,6 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
bool stream_has_echo) {
rtc::CritScope cs(crit_capture_);
if (!enabled_) {
return AudioProcessing::kNoError;
}
@ -235,13 +227,11 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
}
int GainControlImpl::compression_gain_db() const {
rtc::CritScope cs(crit_capture_);
return compression_gain_db_;
}
// TODO(ajm): ensure this is called under kAdaptiveAnalog.
int GainControlImpl::set_stream_analog_level(int level) {
rtc::CritScope cs(crit_capture_);
data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
was_analog_level_set_ = true;
@ -253,8 +243,7 @@ int GainControlImpl::set_stream_analog_level(int level) {
return AudioProcessing::kNoError;
}
int GainControlImpl::stream_analog_level() {
rtc::CritScope cs(crit_capture_);
int GainControlImpl::stream_analog_level() const {
data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
&analog_capture_level_);
// TODO(ajm): enable this assertion?
@ -264,7 +253,6 @@ int GainControlImpl::stream_analog_level() {
}
int GainControlImpl::Enable(bool enable) {
rtc::CritScope cs_capture(crit_capture_);
if (enable && !enabled_) {
enabled_ = enable; // Must be set before Initialize() is called.
@ -278,12 +266,10 @@ int GainControlImpl::Enable(bool enable) {
}
bool GainControlImpl::is_enabled() const {
rtc::CritScope cs(crit_capture_);
return enabled_;
}
int GainControlImpl::set_mode(Mode mode) {
rtc::CritScope cs_capture(crit_capture_);
if (MapSetting(mode) == -1) {
return AudioProcessing::kBadParameterError;
}
@ -296,7 +282,6 @@ int GainControlImpl::set_mode(Mode mode) {
}
GainControl::Mode GainControlImpl::mode() const {
rtc::CritScope cs(crit_capture_);
return mode_;
}
@ -316,7 +301,6 @@ int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
size_t num_proc_channels_local = 0u;
int sample_rate_hz_local = 0;
{
rtc::CritScope cs(crit_capture_);
minimum_capture_level_ = minimum;
maximum_capture_level_ = maximum;
@ -331,17 +315,14 @@ int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
}
int GainControlImpl::analog_level_minimum() const {
rtc::CritScope cs(crit_capture_);
return minimum_capture_level_;
}
int GainControlImpl::analog_level_maximum() const {
rtc::CritScope cs(crit_capture_);
return maximum_capture_level_;
}
bool GainControlImpl::stream_is_saturated() const {
rtc::CritScope cs(crit_capture_);
return stream_is_saturated_;
}
@ -349,13 +330,11 @@ int GainControlImpl::set_target_level_dbfs(int level) {
if (level > 31 || level < 0) {
return AudioProcessing::kBadParameterError;
}
rtc::CritScope cs(crit_capture_);
target_level_dbfs_ = level;
return Configure();
}
int GainControlImpl::target_level_dbfs() const {
rtc::CritScope cs(crit_capture_);
return target_level_dbfs_;
}
@ -363,24 +342,20 @@ int GainControlImpl::set_compression_gain_db(int gain) {
if (gain < 0 || gain > 90) {
return AudioProcessing::kBadParameterError;
}
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;
return Configure();
}
bool GainControlImpl::is_limiter_enabled() const {
rtc::CritScope cs(crit_capture_);
return limiter_enabled_;
}
void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
rtc::CritScope cs_capture(crit_capture_);
data_dumper_->InitiateNewSetOfRecordings();
num_proc_channels_ = num_proc_channels;

View File

@ -20,8 +20,6 @@
#include "api/array_view.h"
#include "modules/audio_processing/include/gain_control.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/critical_section.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
@ -30,7 +28,10 @@ class AudioBuffer;
class GainControlImpl : public GainControl {
public:
explicit GainControlImpl(rtc::CriticalSection* crit_capture);
GainControlImpl();
GainControlImpl(const GainControlImpl&) = delete;
GainControlImpl& operator=(const GainControlImpl&) = delete;
~GainControlImpl() override;
void ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio);
@ -44,7 +45,7 @@ class GainControlImpl : public GainControl {
// GainControl implementation.
bool is_enabled() const override;
int stream_analog_level() override;
int stream_analog_level() const override;
bool is_limiter_enabled() const override;
Mode mode() const override;
@ -66,31 +67,28 @@ class GainControlImpl : public GainControl {
int analog_level_maximum() const override;
bool stream_is_saturated() const override;
int Configure() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
rtc::CriticalSection* const crit_capture_;
int Configure();
std::unique_ptr<ApmDataDumper> data_dumper_;
bool enabled_ = false;
Mode mode_ RTC_GUARDED_BY(crit_capture_);
int minimum_capture_level_ RTC_GUARDED_BY(crit_capture_);
int maximum_capture_level_ RTC_GUARDED_BY(crit_capture_);
bool limiter_enabled_ RTC_GUARDED_BY(crit_capture_);
int target_level_dbfs_ RTC_GUARDED_BY(crit_capture_);
int compression_gain_db_ RTC_GUARDED_BY(crit_capture_);
int analog_capture_level_ RTC_GUARDED_BY(crit_capture_);
bool was_analog_level_set_ RTC_GUARDED_BY(crit_capture_);
bool stream_is_saturated_ RTC_GUARDED_BY(crit_capture_);
Mode mode_;
int minimum_capture_level_;
int maximum_capture_level_;
bool limiter_enabled_;
int target_level_dbfs_;
int compression_gain_db_;
int analog_capture_level_;
bool was_analog_level_set_;
bool stream_is_saturated_;
std::vector<std::unique_ptr<GainController>> gain_controllers_;
absl::optional<size_t> num_proc_channels_ RTC_GUARDED_BY(crit_capture_);
absl::optional<int> sample_rate_hz_ RTC_GUARDED_BY(crit_capture_);
absl::optional<size_t> num_proc_channels_;
absl::optional<int> sample_rate_hz_;
static int instance_counter_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GainControlImpl);
};
} // namespace webrtc

View File

@ -72,8 +72,7 @@ void RunBitExactnessTest(int sample_rate_hz,
int analog_level_max,
int achieved_stream_analog_level_reference,
rtc::ArrayView<const float> output_reference) {
rtc::CriticalSection crit_capture;
GainControlImpl gain_controller(&crit_capture);
GainControlImpl gain_controller;
SetupComponent(sample_rate_hz, mode, target_level_dbfs, stream_analog_level,
compression_gain_db, enable_limiter, analog_level_min,
analog_level_max, &gain_controller);

View File

@ -239,6 +239,11 @@ class AudioProcessing : public rtc::RefCountInterface {
// The parameters and behavior of the audio processing module are controlled
// by changing the default values in the AudioProcessing::Config struct.
// The config is applied by passing the struct to the ApplyConfig method.
//
// This config is intended to be used during setup, and to enable/disable
// top-level processing effects. Use during processing may cause undesired
// submodule resets, affecting the audio quality. Use the RuntimeSetting
// construct for runtime configuration.
struct Config {
// Enabled the pre-amplifier. It amplifies the capture signal
// before any other processing is done.
@ -273,6 +278,59 @@ class AudioProcessing : public rtc::RefCountInterface {
bool enabled = false;
} voice_detection;
// Enables automatic gain control (AGC) functionality.
// The automatic gain control (AGC) component brings the signal to an
// appropriate range. This is done by applying a digital gain directly and,
// in the analog mode, prescribing an analog gain to be applied at the audio
// HAL.
// Recommended to be enabled on the client-side.
struct GainController1 {
bool enabled = false;
enum Mode {
// Adaptive mode intended for use if an analog volume control is
// available on the capture device. It will require the user to provide
// coupling between the OS mixer controls and AGC through the
// stream_analog_level() functions.
// It consists of an analog gain prescription for the audio device and a
// digital compression stage.
kAdaptiveAnalog,
// Adaptive mode intended for situations in which an analog volume
// control is unavailable. It operates in a similar fashion to the
// adaptive analog mode, but with scaling instead applied in the digital
// domain. As with the analog mode, it additionally uses a digital
// compression stage.
kAdaptiveDigital,
// Fixed mode which enables only the digital compression stage also used
// by the two adaptive modes.
// It is distinguished from the adaptive modes by considering only a
// short time-window of the input signal. It applies a fixed gain
// through most of the input level range, and compresses (gradually
// reduces gain with increasing level) the input signal at higher
// levels. This mode is preferred on embedded devices where the capture
// signal level is predictable, so that a known gain can be applied.
kFixedDigital
};
Mode mode = kAdaptiveAnalog;
// Sets the target peak level (or envelope) of the AGC in dBFs (decibels
// from digital full-scale). The convention is to use positive values. For
// instance, passing in a value of 3 corresponds to -3 dBFs, or a target
// level 3 dB below full-scale. Limited to [0, 31].
int target_level_dbfs = 3;
// Sets the maximum gain the digital compression stage may apply, in dB. A
// higher number corresponds to greater compression, while a value of 0
// will leave the signal uncompressed. Limited to [0, 90].
// For updates after APM setup, use a RuntimeSetting instead.
int compression_gain_db = 9;
// When enabled, the compression stage will hard limit the signal to the
// target level. Otherwise, the signal will be compressed but not limited
// above the target level.
bool enable_limiter = true;
// Sets the minimum and maximum analog levels of the audio capture device.
// Must be set if an analog mode is used. Limited to [0, 65535].
int analog_level_minimum = 0;
int analog_level_maximum = 255;
} gain_controller1;
// Enables the next generation AGC functionality. This feature replaces the
// standard methods of gain control in the previous AGC. Enabling this
// submodule enables an adaptive digital AGC followed by a limiter. By
@ -332,6 +390,7 @@ class AudioProcessing : public rtc::RefCountInterface {
enum class Type {
kNotSpecified,
kCapturePreGain,
kCaptureCompressionGain,
kCustomRenderProcessingRuntimeSetting
};
@ -343,6 +402,14 @@ class AudioProcessing : public rtc::RefCountInterface {
return {Type::kCapturePreGain, gain};
}
// Corresponds to Config::GainController1::compression_gain_db, but for
// runtime configuration.
static RuntimeSetting CreateCompressionGainDb(int gain_db) {
RTC_DCHECK_GE(gain_db, 0);
RTC_DCHECK_LE(gain_db, 90);
return {Type::kCaptureCompressionGain, static_cast<float>(gain_db)};
}
static RuntimeSetting CreateCustomRenderSetting(float payload) {
return {Type::kCustomRenderProcessingRuntimeSetting, payload};
}
@ -489,6 +556,16 @@ class AudioProcessing : public rtc::RefCountInterface {
const StreamConfig& output_config,
float* const* dest) = 0;
// This must be called prior to ProcessStream() if and only if adaptive analog
// gain control is enabled, to pass the current analog level from the audio
// HAL. Must be within the range provided in Config::GainController1.
virtual void set_stream_analog_level(int level) = 0;
// When an analog mode is set, this should be called after ProcessStream()
// to obtain the recommended new analog level for the audio HAL. It is the
// user's responsibility to apply this level.
virtual int recommended_stream_analog_level() const = 0;
// This must be called if and only if echo processing is enabled.
//
// Sets the |delay| in ms between ProcessReverseStream() receiving a far-end
@ -553,6 +630,12 @@ class AudioProcessing : public rtc::RefCountInterface {
// remote track.
virtual AudioProcessingStats GetStatistics(bool has_remote_tracks) const = 0;
// DEPRECATED.
// TODO(https://crbug.com/webrtc/9878): Remove.
// Configure via AudioProcessing::ApplyConfig during setup.
// Set runtime settings via AudioProcessing::SetRuntimeSetting.
// Get stats via AudioProcessing::GetStatistics.
//
// These provide access to the component interfaces and should never return
// NULL. The pointers will be valid for the lifetime of the APM instance.
// The memory for these objects is entirely managed internally.

View File

@ -31,7 +31,7 @@ class GainControl {
// When an analog mode is set, this should be called after |ProcessStream()|
// to obtain the recommended new analog level for the audio HAL. It is the
// users responsibility to apply this level.
virtual int stream_analog_level() = 0;
virtual int stream_analog_level() const = 0;
enum Mode {
// Adaptive mode intended for use if an analog volume control is available

View File

@ -27,7 +27,7 @@ class MockGainControl : public GainControl {
MOCK_METHOD1(Enable, int(bool enable));
MOCK_CONST_METHOD0(is_enabled, bool());
MOCK_METHOD1(set_stream_analog_level, int(int level));
MOCK_METHOD0(stream_analog_level, int());
MOCK_CONST_METHOD0(stream_analog_level, int());
MOCK_METHOD1(set_mode, int(Mode mode));
MOCK_CONST_METHOD0(mode, Mode());
MOCK_METHOD1(set_target_level_dbfs, int(int level));
@ -163,6 +163,8 @@ class MockAudioProcessing : public testing::NiceMock<AudioProcessing> {
MOCK_METHOD1(set_stream_key_pressed, void(bool key_pressed));
MOCK_METHOD1(set_delay_offset_ms, void(int offset));
MOCK_CONST_METHOD0(delay_offset_ms, int());
MOCK_METHOD1(set_stream_analog_level, void(int));
MOCK_CONST_METHOD0(recommended_stream_analog_level, int());
virtual void AttachAecDump(std::unique_ptr<AecDump> aec_dump) {}
MOCK_METHOD0(DetachAecDump, void());