agc_manager_direct.cc (27081B)
1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_processing/agc/agc_manager_direct.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <atomic> 16 #include <cmath> 17 #include <cstddef> 18 #include <cstdint> 19 #include <cstdio> 20 #include <memory> 21 #include <optional> 22 23 #include "api/array_view.h" 24 #include "api/audio/audio_processing.h" 25 #include "api/environment/environment.h" 26 #include "api/field_trials_view.h" 27 #include "common_audio/include/audio_util.h" 28 #include "modules/audio_processing/agc/agc.h" 29 #include "modules/audio_processing/agc/gain_control.h" 30 #include "modules/audio_processing/agc2/clipping_predictor.h" 31 #include "modules/audio_processing/agc2/gain_map_internal.h" 32 #include "modules/audio_processing/agc2/input_volume_stats_reporter.h" 33 #include "modules/audio_processing/audio_buffer.h" 34 #include "modules/audio_processing/include/audio_frame_view.h" 35 #include "modules/audio_processing/logging/apm_data_dumper.h" 36 #include "rtc_base/checks.h" 37 #include "rtc_base/logging.h" 38 #include "rtc_base/numerics/safe_minmax.h" 39 #include "system_wrappers/include/metrics.h" 40 41 namespace webrtc { 42 43 namespace { 44 45 // Amount of error we tolerate in the microphone level (presumably due to OS 46 // quantization) before we assume the user has manually adjusted the microphone. 47 constexpr int kLevelQuantizationSlack = 25; 48 49 constexpr int kDefaultCompressionGain = 7; 50 constexpr int kMaxCompressionGain = 12; 51 constexpr int kMinCompressionGain = 2; 52 // Controls the rate of compression changes towards the target. 53 constexpr float kCompressionGainStep = 0.05f; 54 55 constexpr int kMaxMicLevel = 255; 56 static_assert(kGainMapSize > kMaxMicLevel, "gain map too small"); 57 constexpr int kMinMicLevel = 12; 58 59 // Prevent very large microphone level changes. 60 constexpr int kMaxResidualGainChange = 15; 61 62 // Maximum additional gain allowed to compensate for microphone level 63 // restrictions from clipping events. 64 constexpr int kSurplusCompressionGain = 6; 65 66 // Target speech level (dBFs) and speech probability threshold used to compute 67 // the RMS error override in `GetSpeechLevelErrorDb()`. These are only used for 68 // computing the error override and they are not passed to `agc_`. 69 // TODO(webrtc:7494): Move these to a config and pass in the ctor. 70 constexpr float kOverrideTargetSpeechLevelDbfs = -18.0f; 71 constexpr float kOverrideSpeechProbabilitySilenceThreshold = 0.5f; 72 // The minimum number of frames between `UpdateGain()` calls. 73 // TODO(webrtc:7494): Move this to a config and pass in the ctor with 74 // kOverrideWaitFrames = 100. Default value zero needed for the unit tests. 75 constexpr int kOverrideWaitFrames = 0; 76 77 using AnalogAgcConfig = 78 AudioProcessing::Config::GainController1::AnalogGainController; 79 80 // If the "WebRTC-Audio-2ndAgcMinMicLevelExperiment" field trial is specified, 81 // parses it and returns a value between 0 and 255 depending on the field-trial 82 // string. Returns an unspecified value if the field trial is not specified, if 83 // disabled or if it cannot be parsed. Example: 84 // 'WebRTC-Audio-2ndAgcMinMicLevelExperiment/Enabled-80' => returns 80. 85 std::optional<int> GetMinMicLevelOverride(const FieldTrialsView& field_trials) { 86 constexpr char kMinMicLevelFieldTrial[] = 87 "WebRTC-Audio-2ndAgcMinMicLevelExperiment"; 88 if (!field_trials.IsEnabled(kMinMicLevelFieldTrial)) { 89 return std::nullopt; 90 } 91 const auto field_trial_string = field_trials.Lookup(kMinMicLevelFieldTrial); 92 int min_mic_level = -1; 93 sscanf(field_trial_string.c_str(), "Enabled-%d", &min_mic_level); 94 if (min_mic_level >= 0 && min_mic_level <= 255) { 95 return min_mic_level; 96 } else { 97 RTC_LOG(LS_WARNING) << "[agc] Invalid parameter for " 98 << kMinMicLevelFieldTrial << ", ignored."; 99 return std::nullopt; 100 } 101 } 102 103 int LevelFromGainError(int gain_error, int level, int min_mic_level) { 104 RTC_DCHECK_GE(level, 0); 105 RTC_DCHECK_LE(level, kMaxMicLevel); 106 if (gain_error == 0) { 107 return level; 108 } 109 110 int new_level = level; 111 if (gain_error > 0) { 112 while (kGainMap[new_level] - kGainMap[level] < gain_error && 113 new_level < kMaxMicLevel) { 114 ++new_level; 115 } 116 } else { 117 while (kGainMap[new_level] - kGainMap[level] > gain_error && 118 new_level > min_mic_level) { 119 --new_level; 120 } 121 } 122 return new_level; 123 } 124 125 // Returns the proportion of samples in the buffer which are at full-scale 126 // (and presumably clipped). 127 float ComputeClippedRatio(const float* const* audio, 128 size_t num_channels, 129 size_t samples_per_channel) { 130 RTC_DCHECK_GT(samples_per_channel, 0); 131 int num_clipped = 0; 132 for (size_t ch = 0; ch < num_channels; ++ch) { 133 int num_clipped_in_ch = 0; 134 for (size_t i = 0; i < samples_per_channel; ++i) { 135 RTC_DCHECK(audio[ch]); 136 if (audio[ch][i] >= 32767.0f || audio[ch][i] <= -32768.0f) { 137 ++num_clipped_in_ch; 138 } 139 } 140 num_clipped = std::max(num_clipped, num_clipped_in_ch); 141 } 142 return static_cast<float>(num_clipped) / (samples_per_channel); 143 } 144 145 void LogClippingMetrics(int clipping_rate) { 146 RTC_LOG(LS_INFO) << "Input clipping rate: " << clipping_rate << "%"; 147 RTC_HISTOGRAM_COUNTS_LINEAR(/*name=*/"WebRTC.Audio.Agc.InputClippingRate", 148 /*sample=*/clipping_rate, /*min=*/0, /*max=*/100, 149 /*bucket_count=*/50); 150 } 151 152 // Computes the speech level error in dB. `speech_level_dbfs` is required to be 153 // in the range [-90.0f, 30.0f] and `speech_probability` in the range 154 // [0.0f, 1.0f]. 155 int GetSpeechLevelErrorDb(float speech_level_dbfs, float speech_probability) { 156 constexpr float kMinSpeechLevelDbfs = -90.0f; 157 constexpr float kMaxSpeechLevelDbfs = 30.0f; 158 RTC_DCHECK_GE(speech_level_dbfs, kMinSpeechLevelDbfs); 159 RTC_DCHECK_LE(speech_level_dbfs, kMaxSpeechLevelDbfs); 160 RTC_DCHECK_GE(speech_probability, 0.0f); 161 RTC_DCHECK_LE(speech_probability, 1.0f); 162 163 if (speech_probability < kOverrideSpeechProbabilitySilenceThreshold) { 164 return 0; 165 } 166 167 const float speech_level = SafeClamp<float>( 168 speech_level_dbfs, kMinSpeechLevelDbfs, kMaxSpeechLevelDbfs); 169 170 return std::round(kOverrideTargetSpeechLevelDbfs - speech_level); 171 } 172 173 } // namespace 174 175 MonoAgc::MonoAgc(ApmDataDumper* /* data_dumper */, 176 int clipped_level_min, 177 bool disable_digital_adaptive, 178 int min_mic_level) 179 : min_mic_level_(min_mic_level), 180 disable_digital_adaptive_(disable_digital_adaptive), 181 agc_(std::make_unique<Agc>()), 182 max_level_(kMaxMicLevel), 183 max_compression_gain_(kMaxCompressionGain), 184 target_compression_(kDefaultCompressionGain), 185 compression_(target_compression_), 186 compression_accumulator_(compression_), 187 clipped_level_min_(clipped_level_min) {} 188 189 MonoAgc::~MonoAgc() = default; 190 191 void MonoAgc::Initialize() { 192 max_level_ = kMaxMicLevel; 193 max_compression_gain_ = kMaxCompressionGain; 194 target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; 195 compression_ = disable_digital_adaptive_ ? 0 : target_compression_; 196 compression_accumulator_ = compression_; 197 capture_output_used_ = true; 198 check_volume_on_next_process_ = true; 199 frames_since_update_gain_ = 0; 200 is_first_frame_ = true; 201 } 202 203 void MonoAgc::Process(ArrayView<const int16_t> audio, 204 std::optional<int> rms_error_override) { 205 new_compression_to_set_ = std::nullopt; 206 207 if (check_volume_on_next_process_) { 208 check_volume_on_next_process_ = false; 209 // We have to wait until the first process call to check the volume, 210 // because Chromium doesn't guarantee it to be valid any earlier. 211 CheckVolumeAndReset(); 212 } 213 214 agc_->Process(audio); 215 216 // Always check if `agc_` has a new error available. If yes, `agc_` gets 217 // reset. 218 // TODO(webrtc:7494) Replace the `agc_` call `GetRmsErrorDb()` with `Reset()` 219 // if an error override is used. 220 int rms_error = 0; 221 bool update_gain = agc_->GetRmsErrorDb(&rms_error); 222 if (rms_error_override.has_value()) { 223 if (is_first_frame_ || frames_since_update_gain_ < kOverrideWaitFrames) { 224 update_gain = false; 225 } else { 226 rms_error = *rms_error_override; 227 update_gain = true; 228 } 229 } 230 231 if (update_gain) { 232 UpdateGain(rms_error); 233 } 234 235 if (!disable_digital_adaptive_) { 236 UpdateCompressor(); 237 } 238 239 is_first_frame_ = false; 240 if (frames_since_update_gain_ < kOverrideWaitFrames) { 241 ++frames_since_update_gain_; 242 } 243 } 244 245 void MonoAgc::HandleClipping(int clipped_level_step) { 246 RTC_DCHECK_GT(clipped_level_step, 0); 247 // Always decrease the maximum level, even if the current level is below 248 // threshold. 249 SetMaxLevel(std::max(clipped_level_min_, max_level_ - clipped_level_step)); 250 if (log_to_histograms_) { 251 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", 252 level_ - clipped_level_step >= clipped_level_min_); 253 } 254 if (level_ > clipped_level_min_) { 255 // Don't try to adjust the level if we're already below the limit. As 256 // a consequence, if the user has brought the level above the limit, we 257 // will still not react until the postproc updates the level. 258 SetLevel(std::max(clipped_level_min_, level_ - clipped_level_step)); 259 // Reset the AGCs for all channels since the level has changed. 260 agc_->Reset(); 261 frames_since_update_gain_ = 0; 262 is_first_frame_ = false; 263 } 264 } 265 266 void MonoAgc::SetLevel(int new_level) { 267 int voe_level = recommended_input_volume_; 268 if (voe_level == 0) { 269 RTC_DLOG(LS_INFO) 270 << "[agc] VolumeCallbacks returned level=0, taking no action."; 271 return; 272 } 273 if (voe_level < 0 || voe_level > kMaxMicLevel) { 274 RTC_LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" 275 << voe_level; 276 return; 277 } 278 279 // Detect manual input volume adjustments by checking if the current level 280 // `voe_level` is outside of the `[level_ - kLevelQuantizationSlack, level_ + 281 // kLevelQuantizationSlack]` range where `level_` is the last input volume 282 // known by this gain controller. 283 if (voe_level > level_ + kLevelQuantizationSlack || 284 voe_level < level_ - kLevelQuantizationSlack) { 285 RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating " 286 "stored level from " 287 << level_ << " to " << voe_level; 288 level_ = voe_level; 289 // Always allow the user to increase the volume. 290 if (level_ > max_level_) { 291 SetMaxLevel(level_); 292 } 293 // Take no action in this case, since we can't be sure when the volume 294 // was manually adjusted. The compressor will still provide some of the 295 // desired gain change. 296 agc_->Reset(); 297 frames_since_update_gain_ = 0; 298 is_first_frame_ = false; 299 return; 300 } 301 302 new_level = std::min(new_level, max_level_); 303 if (new_level == level_) { 304 return; 305 } 306 307 recommended_input_volume_ = new_level; 308 RTC_DLOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", level_=" << level_ 309 << ", new_level=" << new_level; 310 level_ = new_level; 311 } 312 313 void MonoAgc::SetMaxLevel(int level) { 314 RTC_DCHECK_GE(level, clipped_level_min_); 315 max_level_ = level; 316 // Scale the `kSurplusCompressionGain` linearly across the restricted 317 // level range. 318 max_compression_gain_ = 319 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) / 320 (kMaxMicLevel - clipped_level_min_) * 321 kSurplusCompressionGain + 322 0.5f); 323 RTC_DLOG(LS_INFO) << "[agc] max_level_=" << max_level_ 324 << ", max_compression_gain_=" << max_compression_gain_; 325 } 326 327 void MonoAgc::HandleCaptureOutputUsedChange(bool capture_output_used) { 328 if (capture_output_used_ == capture_output_used) { 329 return; 330 } 331 capture_output_used_ = capture_output_used; 332 333 if (capture_output_used) { 334 // When we start using the output, we should reset things to be safe. 335 check_volume_on_next_process_ = true; 336 } 337 } 338 339 int MonoAgc::CheckVolumeAndReset() { 340 int level = recommended_input_volume_; 341 // Reasons for taking action at startup: 342 // 1) A person starting a call is expected to be heard. 343 // 2) Independent of interpretation of `level` == 0 we should raise it so the 344 // AGC can do its job properly. 345 if (level == 0 && !startup_) { 346 RTC_DLOG(LS_INFO) 347 << "[agc] VolumeCallbacks returned level=0, taking no action."; 348 return 0; 349 } 350 if (level < 0 || level > kMaxMicLevel) { 351 RTC_LOG(LS_ERROR) << "[agc] VolumeCallbacks returned an invalid level=" 352 << level; 353 return -1; 354 } 355 RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level; 356 357 if (level < min_mic_level_) { 358 level = min_mic_level_; 359 RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level; 360 recommended_input_volume_ = level; 361 } 362 agc_->Reset(); 363 level_ = level; 364 startup_ = false; 365 frames_since_update_gain_ = 0; 366 is_first_frame_ = true; 367 return 0; 368 } 369 370 // Distributes the required gain change between the digital compression stage 371 // and volume slider. We use the compressor first, providing a slack region 372 // around the current slider position to reduce movement. 373 // 374 // If the slider needs to be moved, we check first if the user has adjusted 375 // it, in which case we take no action and cache the updated level. 376 void MonoAgc::UpdateGain(int rms_error_db) { 377 int rms_error = rms_error_db; 378 379 // Always reset the counter regardless of whether the gain is changed 380 // or not. This matches with the bahvior of `agc_` where the histogram is 381 // reset every time an RMS error is successfully read. 382 frames_since_update_gain_ = 0; 383 384 // The compressor will always add at least kMinCompressionGain. In effect, 385 // this adjusts our target gain upward by the same amount and rms_error 386 // needs to reflect that. 387 rms_error += kMinCompressionGain; 388 389 // Handle as much error as possible with the compressor first. 390 int raw_compression = 391 SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_); 392 393 // Deemphasize the compression gain error. Move halfway between the current 394 // target and the newly received target. This serves to soften perceptible 395 // intra-talkspurt adjustments, at the cost of some adaptation speed. 396 if ((raw_compression == max_compression_gain_ && 397 target_compression_ == max_compression_gain_ - 1) || 398 (raw_compression == kMinCompressionGain && 399 target_compression_ == kMinCompressionGain + 1)) { 400 // Special case to allow the target to reach the endpoints of the 401 // compression range. The deemphasis would otherwise halt it at 1 dB shy. 402 target_compression_ = raw_compression; 403 } else { 404 target_compression_ = 405 (raw_compression - target_compression_) / 2 + target_compression_; 406 } 407 408 // Residual error will be handled by adjusting the volume slider. Use the 409 // raw rather than deemphasized compression here as we would otherwise 410 // shrink the amount of slack the compressor provides. 411 const int residual_gain = 412 SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange, 413 kMaxResidualGainChange); 414 RTC_DLOG(LS_INFO) << "[agc] rms_error=" << rms_error 415 << ", target_compression=" << target_compression_ 416 << ", residual_gain=" << residual_gain; 417 if (residual_gain == 0) 418 return; 419 420 int old_level = level_; 421 SetLevel(LevelFromGainError(residual_gain, level_, min_mic_level_)); 422 if (old_level != level_) { 423 // Reset the AGC since the level has changed. 424 agc_->Reset(); 425 } 426 } 427 428 void MonoAgc::UpdateCompressor() { 429 if (compression_ == target_compression_) { 430 return; 431 } 432 433 // Adapt the compression gain slowly towards the target, in order to avoid 434 // highly perceptible changes. 435 if (target_compression_ > compression_) { 436 compression_accumulator_ += kCompressionGainStep; 437 } else { 438 compression_accumulator_ -= kCompressionGainStep; 439 } 440 441 // The compressor accepts integer gains in dB. Adjust the gain when 442 // we've come within half a stepsize of the nearest integer. (We don't 443 // check for equality due to potential floating point imprecision). 444 int new_compression = compression_; 445 int nearest_neighbor = std::floor(compression_accumulator_ + 0.5); 446 if (std::fabs(compression_accumulator_ - nearest_neighbor) < 447 kCompressionGainStep / 2) { 448 new_compression = nearest_neighbor; 449 } 450 451 // Set the new compression gain. 452 if (new_compression != compression_) { 453 compression_ = new_compression; 454 compression_accumulator_ = new_compression; 455 new_compression_to_set_ = compression_; 456 } 457 } 458 459 std::atomic<int> AgcManagerDirect::instance_counter_(0); 460 461 AgcManagerDirect::AgcManagerDirect( 462 const Environment& env, 463 const AudioProcessing::Config::GainController1::AnalogGainController& 464 analog_config, 465 Agc* agc) 466 : AgcManagerDirect(env, /*num_capture_channels=*/1, analog_config) { 467 RTC_DCHECK(channel_agcs_[0]); 468 RTC_DCHECK(agc); 469 channel_agcs_[0]->set_agc(agc); 470 } 471 472 AgcManagerDirect::AgcManagerDirect(const Environment& env, 473 int num_capture_channels, 474 const AnalogAgcConfig& analog_config) 475 : analog_controller_enabled_(analog_config.enabled), 476 min_mic_level_override_(GetMinMicLevelOverride(env.field_trials())), 477 data_dumper_(new ApmDataDumper(instance_counter_.fetch_add(1) + 1)), 478 num_capture_channels_(num_capture_channels), 479 disable_digital_adaptive_(!analog_config.enable_digital_adaptive), 480 frames_since_clipped_(analog_config.clipped_wait_frames), 481 capture_output_used_(true), 482 clipped_level_step_(analog_config.clipped_level_step), 483 clipped_ratio_threshold_(analog_config.clipped_ratio_threshold), 484 clipped_wait_frames_(analog_config.clipped_wait_frames), 485 channel_agcs_(num_capture_channels), 486 new_compressions_to_set_(num_capture_channels), 487 clipping_predictor_( 488 CreateClippingPredictor(num_capture_channels, 489 analog_config.clipping_predictor)), 490 use_clipping_predictor_step_( 491 !!clipping_predictor_ && 492 analog_config.clipping_predictor.use_predicted_step), 493 clipping_rate_log_(0.0f), 494 clipping_rate_log_counter_(0) { 495 RTC_LOG(LS_INFO) << "[agc] analog controller enabled: " 496 << (analog_controller_enabled_ ? "yes" : "no"); 497 const int min_mic_level = min_mic_level_override_.value_or(kMinMicLevel); 498 RTC_LOG(LS_INFO) << "[agc] Min mic level: " << min_mic_level 499 << " (overridden: " 500 << (min_mic_level_override_.has_value() ? "yes" : "no") 501 << ")"; 502 for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { 503 ApmDataDumper* data_dumper_ch = ch == 0 ? data_dumper_.get() : nullptr; 504 505 channel_agcs_[ch] = std::make_unique<MonoAgc>( 506 data_dumper_ch, analog_config.clipped_level_min, 507 disable_digital_adaptive_, min_mic_level); 508 } 509 RTC_DCHECK(!channel_agcs_.empty()); 510 RTC_DCHECK_GT(clipped_level_step_, 0); 511 RTC_DCHECK_LE(clipped_level_step_, 255); 512 RTC_DCHECK_GT(clipped_ratio_threshold_, 0.0f); 513 RTC_DCHECK_LT(clipped_ratio_threshold_, 1.0f); 514 RTC_DCHECK_GT(clipped_wait_frames_, 0); 515 channel_agcs_[0]->ActivateLogging(); 516 } 517 518 AgcManagerDirect::~AgcManagerDirect() {} 519 520 void AgcManagerDirect::Initialize() { 521 RTC_DLOG(LS_INFO) << "AgcManagerDirect::Initialize"; 522 data_dumper_->InitiateNewSetOfRecordings(); 523 for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { 524 channel_agcs_[ch]->Initialize(); 525 } 526 capture_output_used_ = true; 527 528 AggregateChannelLevels(); 529 clipping_rate_log_ = 0.0f; 530 clipping_rate_log_counter_ = 0; 531 } 532 533 void AgcManagerDirect::SetupDigitalGainControl( 534 GainControl& gain_control) const { 535 if (gain_control.set_mode(GainControl::kFixedDigital) != 0) { 536 RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed."; 537 } 538 const int target_level_dbfs = disable_digital_adaptive_ ? 0 : 2; 539 if (gain_control.set_target_level_dbfs(target_level_dbfs) != 0) { 540 RTC_LOG(LS_ERROR) << "set_target_level_dbfs() failed."; 541 } 542 const int compression_gain_db = 543 disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; 544 if (gain_control.set_compression_gain_db(compression_gain_db) != 0) { 545 RTC_LOG(LS_ERROR) << "set_compression_gain_db() failed."; 546 } 547 const bool enable_limiter = !disable_digital_adaptive_; 548 if (gain_control.enable_limiter(enable_limiter) != 0) { 549 RTC_LOG(LS_ERROR) << "enable_limiter() failed."; 550 } 551 } 552 553 void AgcManagerDirect::AnalyzePreProcess(const AudioBuffer& audio_buffer) { 554 const float* const* audio = audio_buffer.channels_const(); 555 size_t samples_per_channel = audio_buffer.num_frames(); 556 RTC_DCHECK(audio); 557 558 AggregateChannelLevels(); 559 if (!capture_output_used_) { 560 return; 561 } 562 563 if (!!clipping_predictor_) { 564 AudioFrameView<const float> frame = AudioFrameView<const float>( 565 audio, num_capture_channels_, static_cast<int>(samples_per_channel)); 566 clipping_predictor_->Analyze(frame); 567 } 568 569 // Check for clipped samples, as the AGC has difficulty detecting pitch 570 // under clipping distortion. We do this in the preprocessing phase in order 571 // to catch clipped echo as well. 572 // 573 // If we find a sufficiently clipped frame, drop the current microphone level 574 // and enforce a new maximum level, dropped the same amount from the current 575 // maximum. This harsh treatment is an effort to avoid repeated clipped echo 576 // events. As compensation for this restriction, the maximum compression 577 // gain is increased, through SetMaxLevel(). 578 float clipped_ratio = 579 ComputeClippedRatio(audio, num_capture_channels_, samples_per_channel); 580 clipping_rate_log_ = std::max(clipped_ratio, clipping_rate_log_); 581 clipping_rate_log_counter_++; 582 constexpr int kNumFramesIn30Seconds = 3000; 583 if (clipping_rate_log_counter_ == kNumFramesIn30Seconds) { 584 LogClippingMetrics(std::round(100.0f * clipping_rate_log_)); 585 clipping_rate_log_ = 0.0f; 586 clipping_rate_log_counter_ = 0; 587 } 588 589 if (frames_since_clipped_ < clipped_wait_frames_) { 590 ++frames_since_clipped_; 591 return; 592 } 593 594 const bool clipping_detected = clipped_ratio > clipped_ratio_threshold_; 595 bool clipping_predicted = false; 596 int predicted_step = 0; 597 if (!!clipping_predictor_) { 598 for (int channel = 0; channel < num_capture_channels_; ++channel) { 599 const auto step = clipping_predictor_->EstimateClippedLevelStep( 600 channel, recommended_input_volume_, clipped_level_step_, 601 channel_agcs_[channel]->min_mic_level(), kMaxMicLevel); 602 if (step.has_value()) { 603 predicted_step = std::max(predicted_step, step.value()); 604 clipping_predicted = true; 605 } 606 } 607 } 608 if (clipping_detected) { 609 RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" 610 << clipped_ratio; 611 } 612 int step = clipped_level_step_; 613 if (clipping_predicted) { 614 predicted_step = std::max(predicted_step, clipped_level_step_); 615 RTC_DLOG(LS_INFO) << "[agc] Clipping predicted. step=" << predicted_step; 616 if (use_clipping_predictor_step_) { 617 step = predicted_step; 618 } 619 } 620 if (clipping_detected || 621 (clipping_predicted && use_clipping_predictor_step_)) { 622 for (auto& state_ch : channel_agcs_) { 623 state_ch->HandleClipping(step); 624 } 625 frames_since_clipped_ = 0; 626 if (!!clipping_predictor_) { 627 clipping_predictor_->Reset(); 628 } 629 } 630 AggregateChannelLevels(); 631 } 632 633 void AgcManagerDirect::Process(const AudioBuffer& audio_buffer) { 634 Process(audio_buffer, /*speech_probability=*/std::nullopt, 635 /*speech_level_dbfs=*/std::nullopt); 636 } 637 638 void AgcManagerDirect::Process(const AudioBuffer& audio_buffer, 639 std::optional<float> speech_probability, 640 std::optional<float> speech_level_dbfs) { 641 AggregateChannelLevels(); 642 const int volume_after_clipping_handling = recommended_input_volume_; 643 644 if (!capture_output_used_) { 645 return; 646 } 647 648 const size_t num_frames_per_band = audio_buffer.num_frames_per_band(); 649 std::optional<int> rms_error_override = std::nullopt; 650 if (speech_probability.has_value() && speech_level_dbfs.has_value()) { 651 rms_error_override = 652 GetSpeechLevelErrorDb(*speech_level_dbfs, *speech_probability); 653 } 654 for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { 655 std::array<int16_t, AudioBuffer::kMaxSampleRate / 100> audio_data; 656 int16_t* audio_use = audio_data.data(); 657 FloatS16ToS16(audio_buffer.split_bands_const_f(ch)[0], num_frames_per_band, 658 audio_use); 659 channel_agcs_[ch]->Process({audio_use, num_frames_per_band}, 660 rms_error_override); 661 new_compressions_to_set_[ch] = channel_agcs_[ch]->new_compression(); 662 } 663 664 AggregateChannelLevels(); 665 if (volume_after_clipping_handling != recommended_input_volume_) { 666 // The recommended input volume was adjusted in order to match the target 667 // level. 668 UpdateHistogramOnRecommendedInputVolumeChangeToMatchTarget( 669 recommended_input_volume_); 670 } 671 } 672 673 std::optional<int> AgcManagerDirect::GetDigitalComressionGain() { 674 return new_compressions_to_set_[channel_controlling_gain_]; 675 } 676 677 void AgcManagerDirect::HandleCaptureOutputUsedChange(bool capture_output_used) { 678 for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { 679 channel_agcs_[ch]->HandleCaptureOutputUsedChange(capture_output_used); 680 } 681 capture_output_used_ = capture_output_used; 682 } 683 684 float AgcManagerDirect::voice_probability() const { 685 float max_prob = 0.f; 686 for (const auto& state_ch : channel_agcs_) { 687 max_prob = std::max(max_prob, state_ch->voice_probability()); 688 } 689 690 return max_prob; 691 } 692 693 void AgcManagerDirect::set_stream_analog_level(int level) { 694 if (!analog_controller_enabled_) { 695 recommended_input_volume_ = level; 696 } 697 698 for (size_t ch = 0; ch < channel_agcs_.size(); ++ch) { 699 channel_agcs_[ch]->set_stream_analog_level(level); 700 } 701 702 AggregateChannelLevels(); 703 } 704 705 void AgcManagerDirect::AggregateChannelLevels() { 706 int new_recommended_input_volume = 707 channel_agcs_[0]->recommended_analog_level(); 708 channel_controlling_gain_ = 0; 709 for (size_t ch = 1; ch < channel_agcs_.size(); ++ch) { 710 int level = channel_agcs_[ch]->recommended_analog_level(); 711 if (level < new_recommended_input_volume) { 712 new_recommended_input_volume = level; 713 channel_controlling_gain_ = static_cast<int>(ch); 714 } 715 } 716 717 if (min_mic_level_override_.has_value() && new_recommended_input_volume > 0) { 718 new_recommended_input_volume = 719 std::max(new_recommended_input_volume, *min_mic_level_override_); 720 } 721 722 if (analog_controller_enabled_) { 723 recommended_input_volume_ = new_recommended_input_volume; 724 } 725 } 726 727 } // namespace webrtc