audio_processing/agc: Adds config to set minimum microphone volume at startup
The AGC is currently bumping up the mic volume to 33% at startup if it is below that level. This is to avoid getting stuck in a poor state from which the AGC can not move, simply a too low input audio level. For some users, 33% is instead too loud. This CL gives the user the possibility to set that level at create time. - Extends the Config ExperimentalAgc with a startup_mic_volume for the user to set if desired. Note that the bump up does not apply to the legacy AGC and the "regular" AGC is controlled by ExperimentalAgc. - Without any actions, the same default value as previously is used. - In addition I removed a return value from InitializeExperimentalAgc() and InitializeTransient() This has been tested by building Chromium on Mac and verify through apprtc that 1) startup_mic_volume = 128 bumps up to 50%. 2) startup_mic_volume = 500 (out of range) bumps up to 100%. 3) startup_mic_volume = 0 bumps up to 4%, the AGC min level. BUG=4529 TESTED=locally R=andrew@webrtc.org, kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/43109004 Cr-Commit-Position: refs/heads/master@{#9004}
This commit is contained in:
parent
19a3807b36
commit
adc46c4cf7
@ -48,7 +48,6 @@ const float kCompressionGainStep = 0.05f;
|
||||
const int kMaxMicLevel = 255;
|
||||
static_assert(kGainMapSize > kMaxMicLevel, "gain map too small");
|
||||
const int kMinMicLevel = 12;
|
||||
const int kMinInitMicLevel = 85;
|
||||
|
||||
// Prevent very large microphone level changes.
|
||||
const int kMaxResidualGainChange = 15;
|
||||
@ -57,6 +56,10 @@ const int kMaxResidualGainChange = 15;
|
||||
// restrictions from clipping events.
|
||||
const int kSurplusCompressionGain = 6;
|
||||
|
||||
int ClampLevel(int mic_level) {
|
||||
return std::min(std::max(kMinMicLevel, mic_level), kMaxMicLevel);
|
||||
}
|
||||
|
||||
int LevelFromGainError(int gain_error, int level) {
|
||||
assert(level >= 0 && level <= kMaxMicLevel);
|
||||
if (gain_error == 0) {
|
||||
@ -109,7 +112,8 @@ class DebugFile {
|
||||
};
|
||||
|
||||
AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks)
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level)
|
||||
: agc_(new Agc()),
|
||||
gctrl_(gctrl),
|
||||
volume_callbacks_(volume_callbacks),
|
||||
@ -123,13 +127,15 @@ AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
|
||||
capture_muted_(false),
|
||||
check_volume_on_next_process_(true), // Check at startup.
|
||||
startup_(true),
|
||||
startup_min_level_(ClampLevel(startup_min_level)),
|
||||
file_preproc_(new DebugFile("agc_preproc.pcm")),
|
||||
file_postproc_(new DebugFile("agc_postproc.pcm")) {
|
||||
}
|
||||
|
||||
AgcManagerDirect::AgcManagerDirect(Agc* agc,
|
||||
GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks)
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level)
|
||||
: agc_(agc),
|
||||
gctrl_(gctrl),
|
||||
volume_callbacks_(volume_callbacks),
|
||||
@ -143,6 +149,7 @@ AgcManagerDirect::AgcManagerDirect(Agc* agc,
|
||||
capture_muted_(false),
|
||||
check_volume_on_next_process_(true), // Check at startup.
|
||||
startup_(true),
|
||||
startup_min_level_(ClampLevel(startup_min_level)),
|
||||
file_preproc_(new DebugFile("agc_preproc.pcm")),
|
||||
file_postproc_(new DebugFile("agc_postproc.pcm")) {
|
||||
}
|
||||
@ -336,7 +343,7 @@ int AgcManagerDirect::CheckVolumeAndReset() {
|
||||
}
|
||||
LOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
|
||||
|
||||
int minLevel = startup_ ? kMinInitMicLevel : kMinMicLevel;
|
||||
int minLevel = startup_ ? startup_min_level_ : kMinMicLevel;
|
||||
if (level < minLevel) {
|
||||
level = minLevel;
|
||||
LOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
|
||||
|
@ -41,12 +41,17 @@ class AgcManagerDirect {
|
||||
public:
|
||||
// AgcManagerDirect will configure GainControl internally. The user is
|
||||
// responsible for processing the audio using it after the call to Process.
|
||||
AgcManagerDirect(GainControl* gctrl, VolumeCallbacks* volume_callbacks);
|
||||
// The operating range of startup_min_level is [12, 255] and any input value
|
||||
// outside that range will be clamped.
|
||||
AgcManagerDirect(GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level);
|
||||
// Dependency injection for testing. Don't delete |agc| as the memory is owned
|
||||
// by the manager.
|
||||
AgcManagerDirect(Agc* agc,
|
||||
GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks);
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level);
|
||||
~AgcManagerDirect();
|
||||
|
||||
int Initialize();
|
||||
@ -88,6 +93,7 @@ class AgcManagerDirect {
|
||||
bool capture_muted_;
|
||||
bool check_volume_on_next_process_;
|
||||
bool startup_;
|
||||
int startup_min_level_;
|
||||
|
||||
rtc::scoped_ptr<DebugFile> file_preproc_;
|
||||
rtc::scoped_ptr<DebugFile> file_postproc_;
|
||||
|
@ -177,6 +177,7 @@ AudioProcessingImpl::AudioProcessingImpl(const Config& config,
|
||||
#else
|
||||
use_new_agc_(config.Get<ExperimentalAgc>().enabled),
|
||||
#endif
|
||||
agc_startup_min_volume_(config.Get<ExperimentalAgc>().startup_min_volume),
|
||||
transient_suppressor_enabled_(config.Get<ExperimentalNs>().enabled),
|
||||
beamformer_enabled_(config.Get<Beamforming>().enabled),
|
||||
beamformer_(beamformer),
|
||||
@ -285,15 +286,9 @@ int AudioProcessingImpl::InitializeLocked() {
|
||||
}
|
||||
}
|
||||
|
||||
int err = InitializeExperimentalAgc();
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
InitializeExperimentalAgc();
|
||||
|
||||
err = InitializeTransient();
|
||||
if (err != kNoError) {
|
||||
return err;
|
||||
}
|
||||
InitializeTransient();
|
||||
|
||||
InitializeBeamformer();
|
||||
|
||||
@ -959,19 +954,19 @@ bool AudioProcessingImpl::analysis_needed(bool is_data_processed) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::InitializeExperimentalAgc() {
|
||||
void AudioProcessingImpl::InitializeExperimentalAgc() {
|
||||
if (use_new_agc_) {
|
||||
if (!agc_manager_.get()) {
|
||||
agc_manager_.reset(
|
||||
new AgcManagerDirect(gain_control_, gain_control_for_new_agc_.get()));
|
||||
agc_manager_.reset(new AgcManagerDirect(gain_control_,
|
||||
gain_control_for_new_agc_.get(),
|
||||
agc_startup_min_volume_));
|
||||
}
|
||||
agc_manager_->Initialize();
|
||||
agc_manager_->SetCaptureMuted(output_will_be_muted_);
|
||||
}
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
int AudioProcessingImpl::InitializeTransient() {
|
||||
void AudioProcessingImpl::InitializeTransient() {
|
||||
if (transient_suppressor_enabled_) {
|
||||
if (!transient_suppressor_.get()) {
|
||||
transient_suppressor_.reset(new TransientSuppressor());
|
||||
@ -980,7 +975,6 @@ int AudioProcessingImpl::InitializeTransient() {
|
||||
split_rate_,
|
||||
fwd_out_format_.num_channels());
|
||||
}
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
void AudioProcessingImpl::InitializeBeamformer() {
|
||||
|
@ -170,8 +170,8 @@ class AudioProcessingImpl : public AudioProcessing {
|
||||
bool output_copy_needed(bool is_data_processed) const;
|
||||
bool synthesis_needed(bool is_data_processed) const;
|
||||
bool analysis_needed(bool is_data_processed) const;
|
||||
int InitializeExperimentalAgc() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
int InitializeTransient() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeExperimentalAgc() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeTransient() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeBeamformer() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
EchoCancellationImpl* echo_cancellation_;
|
||||
@ -217,6 +217,7 @@ class AudioProcessingImpl : public AudioProcessing {
|
||||
// Only set through the constructor's Config parameter.
|
||||
const bool use_new_agc_;
|
||||
rtc::scoped_ptr<AgcManagerDirect> agc_manager_ GUARDED_BY(crit_);
|
||||
int agc_startup_min_volume_;
|
||||
|
||||
bool transient_suppressor_enabled_;
|
||||
rtc::scoped_ptr<TransientSuppressor> transient_suppressor_;
|
||||
|
@ -72,12 +72,21 @@ struct ReportedDelay {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
// Must be provided through AudioProcessing::Create(Confg&). It will have no
|
||||
// impact if used with AudioProcessing::SetExtraOptions().
|
||||
// Use to enable experimental gain control (AGC). At startup the experimental
|
||||
// AGC moves the microphone volume up to |startup_min_volume| if the current
|
||||
// microphone volume is set too low. The value is clamped to its operating range
|
||||
// [12, 255]. Here, 255 maps to 100%.
|
||||
//
|
||||
// Must be provided through AudioProcessing::Create(Confg&).
|
||||
static const int kAgcStartupMinVolume = 85;
|
||||
struct ExperimentalAgc {
|
||||
ExperimentalAgc() : enabled(true) {}
|
||||
explicit ExperimentalAgc(bool enabled) : enabled(enabled) {}
|
||||
ExperimentalAgc() : enabled(true), startup_min_volume(kAgcStartupMinVolume) {}
|
||||
ExperimentalAgc(bool enabled)
|
||||
: enabled(enabled), startup_min_volume(kAgcStartupMinVolume) {}
|
||||
ExperimentalAgc(bool enabled, int startup_min_volume)
|
||||
: enabled(enabled), startup_min_volume(startup_min_volume) {}
|
||||
bool enabled;
|
||||
int startup_min_volume;
|
||||
};
|
||||
|
||||
// Use to enable experimental noise suppression. It can be set in the
|
||||
|
@ -147,25 +147,28 @@ AgcManager::AgcManager(VoiceEngine* voe)
|
||||
config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
|
||||
audioproc_.reset(AudioProcessing::Create(config));
|
||||
direct_.reset(new AgcManagerDirect(audioproc_->gain_control(),
|
||||
volume_callbacks_.get()));
|
||||
volume_callbacks_.get(),
|
||||
kAgcStartupMinVolume));
|
||||
media_callback_.reset(new MediaCallback(direct_.get(),
|
||||
audioproc_.get(),
|
||||
crit_.get()));
|
||||
preproc_callback_.reset(new PreprocCallback(direct_.get(), crit_.get()));
|
||||
}
|
||||
|
||||
AgcManager::AgcManager(VoEExternalMedia* media, VoEVolumeControl* volume,
|
||||
Agc* agc, AudioProcessing* audioproc)
|
||||
AgcManager::AgcManager(VoEExternalMedia* media,
|
||||
VoEVolumeControl* volume,
|
||||
Agc* agc,
|
||||
AudioProcessing* audioproc)
|
||||
: media_(media),
|
||||
volume_callbacks_(new AgcManagerVolume(volume)),
|
||||
crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
audioproc_(audioproc),
|
||||
direct_(new AgcManagerDirect(agc,
|
||||
audioproc_->gain_control(),
|
||||
volume_callbacks_.get())),
|
||||
media_callback_(new MediaCallback(direct_.get(),
|
||||
audioproc_.get(),
|
||||
crit_.get())),
|
||||
volume_callbacks_.get(),
|
||||
kAgcStartupMinVolume)),
|
||||
media_callback_(
|
||||
new MediaCallback(direct_.get(), audioproc_.get(), crit_.get())),
|
||||
preproc_callback_(new PreprocCallback(direct_.get(), crit_.get())),
|
||||
enabled_(false),
|
||||
initialized_(false) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user