blob: 1ae4e5c4ce7d299a972d3ceaa8ee1dccbcba6f8d [file] [log] [blame]
pbos@webrtc.org788acd12014-12-15 09:41:24 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/agc/agc_manager_direct.h"
pbos@webrtc.org788acd12014-12-15 09:41:24 +000012
pbos@webrtc.org788acd12014-12-15 09:41:24 +000013#include <cmath>
14
15#ifdef WEBRTC_AGC_DEBUG_DUMP
16#include <cstdio>
17#endif
18
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_processing/agc/gain_map_internal.h"
20#include "modules/audio_processing/gain_control_impl.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010023#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "system_wrappers/include/metrics.h"
pbos@webrtc.org788acd12014-12-15 09:41:24 +000025
26namespace webrtc {
27
Alex Loikoc1676732018-07-02 12:05:28 +020028int AgcManagerDirect::instance_counter_ = 0;
29
pbos@webrtc.org788acd12014-12-15 09:41:24 +000030namespace {
31
pbos@webrtc.org788acd12014-12-15 09:41:24 +000032// Amount the microphone level is lowered with every clipping event.
33const int kClippedLevelStep = 15;
34// Proportion of clipped samples required to declare a clipping event.
35const float kClippedRatioThreshold = 0.1f;
36// Time in frames to wait after a clipping event before checking again.
37const int kClippedWaitFrames = 300;
38
39// Amount of error we tolerate in the microphone level (presumably due to OS
40// quantization) before we assume the user has manually adjusted the microphone.
41const int kLevelQuantizationSlack = 25;
42
43const int kDefaultCompressionGain = 7;
44const int kMaxCompressionGain = 12;
45const int kMinCompressionGain = 2;
46// Controls the rate of compression changes towards the target.
47const float kCompressionGainStep = 0.05f;
48
49const int kMaxMicLevel = 255;
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +000050static_assert(kGainMapSize > kMaxMicLevel, "gain map too small");
pbos@webrtc.org788acd12014-12-15 09:41:24 +000051const int kMinMicLevel = 12;
pbos@webrtc.org788acd12014-12-15 09:41:24 +000052
53// Prevent very large microphone level changes.
54const int kMaxResidualGainChange = 15;
55
56// Maximum additional gain allowed to compensate for microphone level
57// restrictions from clipping events.
58const int kSurplusCompressionGain = 6;
59
Bjorn Volckeradc46c42015-04-15 11:42:40 +020060int ClampLevel(int mic_level) {
kwiberg07038562017-06-12 11:40:47 -070061 return rtc::SafeClamp(mic_level, kMinMicLevel, kMaxMicLevel);
Bjorn Volckeradc46c42015-04-15 11:42:40 +020062}
63
pbos@webrtc.org788acd12014-12-15 09:41:24 +000064int LevelFromGainError(int gain_error, int level) {
kwiberg9e2be5f2016-09-14 05:23:22 -070065 RTC_DCHECK_GE(level, 0);
66 RTC_DCHECK_LE(level, kMaxMicLevel);
pbos@webrtc.org788acd12014-12-15 09:41:24 +000067 if (gain_error == 0) {
68 return level;
69 }
70 // TODO(ajm): Could be made more efficient with a binary search.
71 int new_level = level;
72 if (gain_error > 0) {
73 while (kGainMap[new_level] - kGainMap[level] < gain_error &&
Yves Gerey665174f2018-06-19 15:03:05 +020074 new_level < kMaxMicLevel) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000075 ++new_level;
76 }
77 } else {
78 while (kGainMap[new_level] - kGainMap[level] > gain_error &&
Yves Gerey665174f2018-06-19 15:03:05 +020079 new_level > kMinMicLevel) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000080 --new_level;
81 }
82 }
83 return new_level;
84}
85
86} // namespace
87
88// Facility for dumping debug audio files. All methods are no-ops in the
89// default case where WEBRTC_AGC_DEBUG_DUMP is undefined.
90class DebugFile {
91#ifdef WEBRTC_AGC_DEBUG_DUMP
92 public:
Yves Gerey665174f2018-06-19 15:03:05 +020093 explicit DebugFile(const char* filename) : file_(fopen(filename, "wb")) {
kwiberg9e2be5f2016-09-14 05:23:22 -070094 RTC_DCHECK(file_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +000095 }
Yves Gerey665174f2018-06-19 15:03:05 +020096 ~DebugFile() { fclose(file_); }
Peter Kastingdce40cf2015-08-24 14:52:23 -070097 void Write(const int16_t* data, size_t length_samples) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000098 fwrite(data, 1, length_samples * sizeof(int16_t), file_);
99 }
Yves Gerey665174f2018-06-19 15:03:05 +0200100
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000101 private:
102 FILE* file_;
103#else
104 public:
Yves Gerey665174f2018-06-19 15:03:05 +0200105 explicit DebugFile(const char* filename) {}
106 ~DebugFile() {}
107 void Write(const int16_t* data, size_t length_samples) {}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000108#endif // WEBRTC_AGC_DEBUG_DUMP
109};
110
111AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200112 VolumeCallbacks* volume_callbacks,
henrik.lundinbd681b92016-12-05 09:08:42 -0800113 int startup_min_level,
114 int clipped_level_min)
Alex Loikoc1676732018-07-02 12:05:28 +0200115 : data_dumper_(new ApmDataDumper(instance_counter_)),
116 agc_(new Agc()),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000117 gctrl_(gctrl),
118 volume_callbacks_(volume_callbacks),
119 frames_since_clipped_(kClippedWaitFrames),
120 level_(0),
121 max_level_(kMaxMicLevel),
122 max_compression_gain_(kMaxCompressionGain),
123 target_compression_(kDefaultCompressionGain),
124 compression_(target_compression_),
125 compression_accumulator_(compression_),
126 capture_muted_(false),
127 check_volume_on_next_process_(true), // Check at startup.
128 startup_(true),
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200129 startup_min_level_(ClampLevel(startup_min_level)),
henrik.lundinbd681b92016-12-05 09:08:42 -0800130 clipped_level_min_(clipped_level_min),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000131 file_preproc_(new DebugFile("agc_preproc.pcm")),
Alex Loikoc1676732018-07-02 12:05:28 +0200132 file_postproc_(new DebugFile("agc_postproc.pcm")) {
133 instance_counter_++;
134}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000135
136AgcManagerDirect::AgcManagerDirect(Agc* agc,
137 GainControl* gctrl,
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200138 VolumeCallbacks* volume_callbacks,
henrik.lundinbd681b92016-12-05 09:08:42 -0800139 int startup_min_level,
140 int clipped_level_min)
Alex Loikoc1676732018-07-02 12:05:28 +0200141 : data_dumper_(new ApmDataDumper(instance_counter_)),
142 agc_(agc),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000143 gctrl_(gctrl),
144 volume_callbacks_(volume_callbacks),
145 frames_since_clipped_(kClippedWaitFrames),
146 level_(0),
147 max_level_(kMaxMicLevel),
148 max_compression_gain_(kMaxCompressionGain),
149 target_compression_(kDefaultCompressionGain),
150 compression_(target_compression_),
151 compression_accumulator_(compression_),
152 capture_muted_(false),
153 check_volume_on_next_process_(true), // Check at startup.
154 startup_(true),
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200155 startup_min_level_(ClampLevel(startup_min_level)),
henrik.lundinbd681b92016-12-05 09:08:42 -0800156 clipped_level_min_(clipped_level_min),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000157 file_preproc_(new DebugFile("agc_preproc.pcm")),
Alex Loikoc1676732018-07-02 12:05:28 +0200158 file_postproc_(new DebugFile("agc_postproc.pcm")) {
159 instance_counter_++;
160}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000161
162AgcManagerDirect::~AgcManagerDirect() {}
163
164int AgcManagerDirect::Initialize() {
165 max_level_ = kMaxMicLevel;
166 max_compression_gain_ = kMaxCompressionGain;
167 target_compression_ = kDefaultCompressionGain;
168 compression_ = target_compression_;
169 compression_accumulator_ = compression_;
170 capture_muted_ = false;
171 check_volume_on_next_process_ = true;
172 // TODO(bjornv): Investigate if we need to reset |startup_| as well. For
173 // example, what happens when we change devices.
174
Alex Loikoc1676732018-07-02 12:05:28 +0200175 data_dumper_->InitiateNewSetOfRecordings();
176
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000177 if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100178 RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000179 return -1;
180 }
181 if (gctrl_->set_target_level_dbfs(2) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100182 RTC_LOG(LS_ERROR) << "set_target_level_dbfs(2) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000183 return -1;
184 }
185 if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100186 RTC_LOG(LS_ERROR)
187 << "set_compression_gain_db(kDefaultCompressionGain) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000188 return -1;
189 }
190 if (gctrl_->enable_limiter(true) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100191 RTC_LOG(LS_ERROR) << "enable_limiter(true) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000192 return -1;
193 }
194 return 0;
195}
196
197void AgcManagerDirect::AnalyzePreProcess(int16_t* audio,
198 int num_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700199 size_t samples_per_channel) {
200 size_t length = num_channels * samples_per_channel;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000201 if (capture_muted_) {
202 return;
203 }
204
205 file_preproc_->Write(audio, length);
206
207 if (frames_since_clipped_ < kClippedWaitFrames) {
208 ++frames_since_clipped_;
209 return;
210 }
211
212 // Check for clipped samples, as the AGC has difficulty detecting pitch
213 // under clipping distortion. We do this in the preprocessing phase in order
214 // to catch clipped echo as well.
215 //
216 // If we find a sufficiently clipped frame, drop the current microphone level
217 // and enforce a new maximum level, dropped the same amount from the current
218 // maximum. This harsh treatment is an effort to avoid repeated clipped echo
219 // events. As compensation for this restriction, the maximum compression
220 // gain is increased, through SetMaxLevel().
221 float clipped_ratio = agc_->AnalyzePreproc(audio, length);
222 if (clipped_ratio > kClippedRatioThreshold) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100223 RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
224 << clipped_ratio;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000225 // Always decrease the maximum level, even if the current level is below
226 // threshold.
henrik.lundinbd681b92016-12-05 09:08:42 -0800227 SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep));
henrik.lundin30a12fb2016-11-22 07:02:44 -0800228 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed",
henrik.lundinbd681b92016-12-05 09:08:42 -0800229 level_ - kClippedLevelStep >= clipped_level_min_);
230 if (level_ > clipped_level_min_) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000231 // Don't try to adjust the level if we're already below the limit. As
232 // a consequence, if the user has brought the level above the limit, we
233 // will still not react until the postproc updates the level.
henrik.lundinbd681b92016-12-05 09:08:42 -0800234 SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000235 // Reset the AGC since the level has changed.
236 agc_->Reset();
237 }
238 frames_since_clipped_ = 0;
239 }
240}
241
242void AgcManagerDirect::Process(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700243 size_t length,
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000244 int sample_rate_hz) {
245 if (capture_muted_) {
246 return;
247 }
248
249 if (check_volume_on_next_process_) {
250 check_volume_on_next_process_ = false;
251 // We have to wait until the first process call to check the volume,
252 // because Chromium doesn't guarantee it to be valid any earlier.
253 CheckVolumeAndReset();
254 }
255
Jonas Olsson645b0272018-02-15 15:16:27 +0100256 agc_->Process(audio, length, sample_rate_hz);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000257
258 UpdateGain();
259 UpdateCompressor();
260
261 file_postproc_->Write(audio, length);
Alex Loikoc1676732018-07-02 12:05:28 +0200262
263 data_dumper_->DumpRaw("experimental_gain_control_compression_gain_db", 1,
264 &compression_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000265}
266
267void AgcManagerDirect::SetLevel(int new_level) {
268 int voe_level = volume_callbacks_->GetMicVolume();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000269 if (voe_level == 0) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100270 RTC_DLOG(LS_INFO)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100271 << "[agc] VolumeCallbacks returned level=0, taking no action.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000272 return;
273 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100274 if (voe_level < 0 || voe_level > kMaxMicLevel) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100275 RTC_LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level="
276 << voe_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000277 return;
278 }
279
280 if (voe_level > level_ + kLevelQuantizationSlack ||
281 voe_level < level_ - kLevelQuantizationSlack) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100282 RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
Yves Gerey665174f2018-06-19 15:03:05 +0200283 "stored level from "
284 << level_ << " to " << voe_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000285 level_ = voe_level;
286 // Always allow the user to increase the volume.
287 if (level_ > max_level_) {
288 SetMaxLevel(level_);
289 }
290 // Take no action in this case, since we can't be sure when the volume
291 // was manually adjusted. The compressor will still provide some of the
292 // desired gain change.
293 agc_->Reset();
294 return;
295 }
296
297 new_level = std::min(new_level, max_level_);
298 if (new_level == level_) {
299 return;
300 }
301
302 volume_callbacks_->SetMicVolume(new_level);
Jonas Olsson645b0272018-02-15 15:16:27 +0100303 RTC_DLOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", "
304 << "level_=" << level_ << ", "
305 << "new_level=" << new_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000306 level_ = new_level;
307}
308
309void AgcManagerDirect::SetMaxLevel(int level) {
henrik.lundinbd681b92016-12-05 09:08:42 -0800310 RTC_DCHECK_GE(level, clipped_level_min_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000311 max_level_ = level;
312 // Scale the |kSurplusCompressionGain| linearly across the restricted
313 // level range.
henrik.lundinbd681b92016-12-05 09:08:42 -0800314 max_compression_gain_ =
315 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) /
316 (kMaxMicLevel - clipped_level_min_) *
317 kSurplusCompressionGain +
318 0.5f);
Jonas Olsson645b0272018-02-15 15:16:27 +0100319 RTC_DLOG(LS_INFO) << "[agc] max_level_=" << max_level_
320 << ", max_compression_gain_=" << max_compression_gain_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000321}
322
323void AgcManagerDirect::SetCaptureMuted(bool muted) {
324 if (capture_muted_ == muted) {
325 return;
326 }
327 capture_muted_ = muted;
328
329 if (!muted) {
330 // When we unmute, we should reset things to be safe.
331 check_volume_on_next_process_ = true;
332 }
333}
334
335float AgcManagerDirect::voice_probability() {
aluebsecf6b812015-06-25 12:28:48 -0700336 return agc_->voice_probability();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000337}
338
339int AgcManagerDirect::CheckVolumeAndReset() {
340 int level = volume_callbacks_->GetMicVolume();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000341 // 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_) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100346 RTC_DLOG(LS_INFO)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100347 << "[agc] VolumeCallbacks returned level=0, taking no action.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000348 return 0;
349 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100350 if (level < 0 || level > kMaxMicLevel) {
351 RTC_LOG(LS_ERROR) << "[agc] VolumeCallbacks returned an invalid level="
352 << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000353 return -1;
354 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100355 RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000356
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200357 int minLevel = startup_ ? startup_min_level_ : kMinMicLevel;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000358 if (level < minLevel) {
359 level = minLevel;
Jonas Olsson645b0272018-02-15 15:16:27 +0100360 RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000361 volume_callbacks_->SetMicVolume(level);
362 }
363 agc_->Reset();
364 level_ = level;
365 startup_ = false;
366 return 0;
367}
368
369// Requests the RMS error from AGC and distributes the required gain change
370// between the digital compression stage and volume slider. We use the
371// compressor first, providing a slack region around the current slider
372// 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.
376void AgcManagerDirect::UpdateGain() {
377 int rms_error = 0;
378 if (!agc_->GetRmsErrorDb(&rms_error)) {
379 // No error update ready.
380 return;
381 }
382 // The compressor will always add at least kMinCompressionGain. In effect,
383 // this adjusts our target gain upward by the same amount and rms_error
384 // needs to reflect that.
385 rms_error += kMinCompressionGain;
386
387 // Handle as much error as possible with the compressor first.
kwiberg07038562017-06-12 11:40:47 -0700388 int raw_compression =
389 rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_);
390
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000391 // Deemphasize the compression gain error. Move halfway between the current
392 // target and the newly received target. This serves to soften perceptible
393 // intra-talkspurt adjustments, at the cost of some adaptation speed.
394 if ((raw_compression == max_compression_gain_ &&
Yves Gerey665174f2018-06-19 15:03:05 +0200395 target_compression_ == max_compression_gain_ - 1) ||
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000396 (raw_compression == kMinCompressionGain &&
Yves Gerey665174f2018-06-19 15:03:05 +0200397 target_compression_ == kMinCompressionGain + 1)) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000398 // Special case to allow the target to reach the endpoints of the
399 // compression range. The deemphasis would otherwise halt it at 1 dB shy.
400 target_compression_ = raw_compression;
401 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200402 target_compression_ =
403 (raw_compression - target_compression_) / 2 + target_compression_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000404 }
405
406 // Residual error will be handled by adjusting the volume slider. Use the
407 // raw rather than deemphasized compression here as we would otherwise
408 // shrink the amount of slack the compressor provides.
kwiberg07038562017-06-12 11:40:47 -0700409 const int residual_gain =
410 rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange,
411 kMaxResidualGainChange);
Jonas Olsson645b0272018-02-15 15:16:27 +0100412 RTC_DLOG(LS_INFO) << "[agc] rms_error=" << rms_error
413 << ", target_compression=" << target_compression_
414 << ", residual_gain=" << residual_gain;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000415 if (residual_gain == 0)
416 return;
417
henrik.lundin3edc7f02016-11-24 01:42:46 -0800418 int old_level = level_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000419 SetLevel(LevelFromGainError(residual_gain, level_));
henrik.lundin3edc7f02016-11-24 01:42:46 -0800420 if (old_level != level_) {
421 // level_ was updated by SetLevel; log the new value.
henrik.lundin45bb5132016-12-06 04:28:04 -0800422 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1,
423 kMaxMicLevel, 50);
henrik.lundin3edc7f02016-11-24 01:42:46 -0800424 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000425}
426
427void AgcManagerDirect::UpdateCompressor() {
428 if (compression_ == target_compression_) {
429 return;
430 }
431
432 // Adapt the compression gain slowly towards the target, in order to avoid
433 // highly perceptible changes.
434 if (target_compression_ > compression_) {
435 compression_accumulator_ += kCompressionGainStep;
436 } else {
437 compression_accumulator_ -= kCompressionGainStep;
438 }
439
440 // The compressor accepts integer gains in dB. Adjust the gain when
441 // we've come within half a stepsize of the nearest integer. (We don't
442 // check for equality due to potential floating point imprecision).
443 int new_compression = compression_;
444 int nearest_neighbor = std::floor(compression_accumulator_ + 0.5);
445 if (std::fabs(compression_accumulator_ - nearest_neighbor) <
446 kCompressionGainStep / 2) {
447 new_compression = nearest_neighbor;
448 }
449
450 // Set the new compression gain.
451 if (new_compression != compression_) {
452 compression_ = new_compression;
453 compression_accumulator_ = new_compression;
454 if (gctrl_->set_compression_gain_db(compression_) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100455 RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << compression_
456 << ") failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000457 }
458 }
459}
460
461} // namespace webrtc