blob: 9714b4c95e9bec07b1f3d030d95eb78cff502f8e [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
28namespace {
29
pbos@webrtc.org788acd12014-12-15 09:41:24 +000030// Amount the microphone level is lowered with every clipping event.
31const int kClippedLevelStep = 15;
32// Proportion of clipped samples required to declare a clipping event.
33const float kClippedRatioThreshold = 0.1f;
34// Time in frames to wait after a clipping event before checking again.
35const int kClippedWaitFrames = 300;
36
37// Amount of error we tolerate in the microphone level (presumably due to OS
38// quantization) before we assume the user has manually adjusted the microphone.
39const int kLevelQuantizationSlack = 25;
40
41const int kDefaultCompressionGain = 7;
42const int kMaxCompressionGain = 12;
43const int kMinCompressionGain = 2;
44// Controls the rate of compression changes towards the target.
45const float kCompressionGainStep = 0.05f;
46
47const int kMaxMicLevel = 255;
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +000048static_assert(kGainMapSize > kMaxMicLevel, "gain map too small");
pbos@webrtc.org788acd12014-12-15 09:41:24 +000049const int kMinMicLevel = 12;
pbos@webrtc.org788acd12014-12-15 09:41:24 +000050
51// Prevent very large microphone level changes.
52const int kMaxResidualGainChange = 15;
53
54// Maximum additional gain allowed to compensate for microphone level
55// restrictions from clipping events.
56const int kSurplusCompressionGain = 6;
57
Bjorn Volckeradc46c42015-04-15 11:42:40 +020058int ClampLevel(int mic_level) {
kwiberg07038562017-06-12 11:40:47 -070059 return rtc::SafeClamp(mic_level, kMinMicLevel, kMaxMicLevel);
Bjorn Volckeradc46c42015-04-15 11:42:40 +020060}
61
pbos@webrtc.org788acd12014-12-15 09:41:24 +000062int LevelFromGainError(int gain_error, int level) {
kwiberg9e2be5f2016-09-14 05:23:22 -070063 RTC_DCHECK_GE(level, 0);
64 RTC_DCHECK_LE(level, kMaxMicLevel);
pbos@webrtc.org788acd12014-12-15 09:41:24 +000065 if (gain_error == 0) {
66 return level;
67 }
68 // TODO(ajm): Could be made more efficient with a binary search.
69 int new_level = level;
70 if (gain_error > 0) {
71 while (kGainMap[new_level] - kGainMap[level] < gain_error &&
Yves Gerey665174f2018-06-19 15:03:05 +020072 new_level < kMaxMicLevel) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000073 ++new_level;
74 }
75 } else {
76 while (kGainMap[new_level] - kGainMap[level] > gain_error &&
Yves Gerey665174f2018-06-19 15:03:05 +020077 new_level > kMinMicLevel) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000078 --new_level;
79 }
80 }
81 return new_level;
82}
83
84} // namespace
85
86// Facility for dumping debug audio files. All methods are no-ops in the
87// default case where WEBRTC_AGC_DEBUG_DUMP is undefined.
88class DebugFile {
89#ifdef WEBRTC_AGC_DEBUG_DUMP
90 public:
Yves Gerey665174f2018-06-19 15:03:05 +020091 explicit DebugFile(const char* filename) : file_(fopen(filename, "wb")) {
kwiberg9e2be5f2016-09-14 05:23:22 -070092 RTC_DCHECK(file_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +000093 }
Yves Gerey665174f2018-06-19 15:03:05 +020094 ~DebugFile() { fclose(file_); }
Peter Kastingdce40cf2015-08-24 14:52:23 -070095 void Write(const int16_t* data, size_t length_samples) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000096 fwrite(data, 1, length_samples * sizeof(int16_t), file_);
97 }
Yves Gerey665174f2018-06-19 15:03:05 +020098
pbos@webrtc.org788acd12014-12-15 09:41:24 +000099 private:
100 FILE* file_;
101#else
102 public:
Yves Gerey665174f2018-06-19 15:03:05 +0200103 explicit DebugFile(const char* filename) {}
104 ~DebugFile() {}
105 void Write(const int16_t* data, size_t length_samples) {}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000106#endif // WEBRTC_AGC_DEBUG_DUMP
107};
108
109AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200110 VolumeCallbacks* volume_callbacks,
henrik.lundinbd681b92016-12-05 09:08:42 -0800111 int startup_min_level,
112 int clipped_level_min)
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000113 : agc_(new Agc()),
114 gctrl_(gctrl),
115 volume_callbacks_(volume_callbacks),
116 frames_since_clipped_(kClippedWaitFrames),
117 level_(0),
118 max_level_(kMaxMicLevel),
119 max_compression_gain_(kMaxCompressionGain),
120 target_compression_(kDefaultCompressionGain),
121 compression_(target_compression_),
122 compression_accumulator_(compression_),
123 capture_muted_(false),
124 check_volume_on_next_process_(true), // Check at startup.
125 startup_(true),
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200126 startup_min_level_(ClampLevel(startup_min_level)),
henrik.lundinbd681b92016-12-05 09:08:42 -0800127 clipped_level_min_(clipped_level_min),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000128 file_preproc_(new DebugFile("agc_preproc.pcm")),
henrik.lundinbd681b92016-12-05 09:08:42 -0800129 file_postproc_(new DebugFile("agc_postproc.pcm")) {}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000130
131AgcManagerDirect::AgcManagerDirect(Agc* agc,
132 GainControl* gctrl,
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200133 VolumeCallbacks* volume_callbacks,
henrik.lundinbd681b92016-12-05 09:08:42 -0800134 int startup_min_level,
135 int clipped_level_min)
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000136 : agc_(agc),
137 gctrl_(gctrl),
138 volume_callbacks_(volume_callbacks),
139 frames_since_clipped_(kClippedWaitFrames),
140 level_(0),
141 max_level_(kMaxMicLevel),
142 max_compression_gain_(kMaxCompressionGain),
143 target_compression_(kDefaultCompressionGain),
144 compression_(target_compression_),
145 compression_accumulator_(compression_),
146 capture_muted_(false),
147 check_volume_on_next_process_(true), // Check at startup.
148 startup_(true),
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200149 startup_min_level_(ClampLevel(startup_min_level)),
henrik.lundinbd681b92016-12-05 09:08:42 -0800150 clipped_level_min_(clipped_level_min),
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000151 file_preproc_(new DebugFile("agc_preproc.pcm")),
henrik.lundinbd681b92016-12-05 09:08:42 -0800152 file_postproc_(new DebugFile("agc_postproc.pcm")) {}
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000153
154AgcManagerDirect::~AgcManagerDirect() {}
155
156int AgcManagerDirect::Initialize() {
157 max_level_ = kMaxMicLevel;
158 max_compression_gain_ = kMaxCompressionGain;
159 target_compression_ = kDefaultCompressionGain;
160 compression_ = target_compression_;
161 compression_accumulator_ = compression_;
162 capture_muted_ = false;
163 check_volume_on_next_process_ = true;
164 // TODO(bjornv): Investigate if we need to reset |startup_| as well. For
165 // example, what happens when we change devices.
166
167 if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100168 RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000169 return -1;
170 }
171 if (gctrl_->set_target_level_dbfs(2) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG(LS_ERROR) << "set_target_level_dbfs(2) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000173 return -1;
174 }
175 if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100176 RTC_LOG(LS_ERROR)
177 << "set_compression_gain_db(kDefaultCompressionGain) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000178 return -1;
179 }
180 if (gctrl_->enable_limiter(true) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100181 RTC_LOG(LS_ERROR) << "enable_limiter(true) failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000182 return -1;
183 }
184 return 0;
185}
186
187void AgcManagerDirect::AnalyzePreProcess(int16_t* audio,
188 int num_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700189 size_t samples_per_channel) {
190 size_t length = num_channels * samples_per_channel;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000191 if (capture_muted_) {
192 return;
193 }
194
195 file_preproc_->Write(audio, length);
196
197 if (frames_since_clipped_ < kClippedWaitFrames) {
198 ++frames_since_clipped_;
199 return;
200 }
201
202 // Check for clipped samples, as the AGC has difficulty detecting pitch
203 // under clipping distortion. We do this in the preprocessing phase in order
204 // to catch clipped echo as well.
205 //
206 // If we find a sufficiently clipped frame, drop the current microphone level
207 // and enforce a new maximum level, dropped the same amount from the current
208 // maximum. This harsh treatment is an effort to avoid repeated clipped echo
209 // events. As compensation for this restriction, the maximum compression
210 // gain is increased, through SetMaxLevel().
211 float clipped_ratio = agc_->AnalyzePreproc(audio, length);
212 if (clipped_ratio > kClippedRatioThreshold) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100213 RTC_DLOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
214 << clipped_ratio;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000215 // Always decrease the maximum level, even if the current level is below
216 // threshold.
henrik.lundinbd681b92016-12-05 09:08:42 -0800217 SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep));
henrik.lundin30a12fb2016-11-22 07:02:44 -0800218 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed",
henrik.lundinbd681b92016-12-05 09:08:42 -0800219 level_ - kClippedLevelStep >= clipped_level_min_);
220 if (level_ > clipped_level_min_) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000221 // Don't try to adjust the level if we're already below the limit. As
222 // a consequence, if the user has brought the level above the limit, we
223 // will still not react until the postproc updates the level.
henrik.lundinbd681b92016-12-05 09:08:42 -0800224 SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep));
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000225 // Reset the AGC since the level has changed.
226 agc_->Reset();
227 }
228 frames_since_clipped_ = 0;
229 }
230}
231
232void AgcManagerDirect::Process(const int16_t* audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700233 size_t length,
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000234 int sample_rate_hz) {
235 if (capture_muted_) {
236 return;
237 }
238
239 if (check_volume_on_next_process_) {
240 check_volume_on_next_process_ = false;
241 // We have to wait until the first process call to check the volume,
242 // because Chromium doesn't guarantee it to be valid any earlier.
243 CheckVolumeAndReset();
244 }
245
Jonas Olsson645b0272018-02-15 15:16:27 +0100246 agc_->Process(audio, length, sample_rate_hz);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000247
248 UpdateGain();
249 UpdateCompressor();
250
251 file_postproc_->Write(audio, length);
252}
253
254void AgcManagerDirect::SetLevel(int new_level) {
255 int voe_level = volume_callbacks_->GetMicVolume();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000256 if (voe_level == 0) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100257 RTC_DLOG(LS_INFO)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100258 << "[agc] VolumeCallbacks returned level=0, taking no action.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000259 return;
260 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100261 if (voe_level < 0 || voe_level > kMaxMicLevel) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100262 RTC_LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level="
263 << voe_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000264 return;
265 }
266
267 if (voe_level > level_ + kLevelQuantizationSlack ||
268 voe_level < level_ - kLevelQuantizationSlack) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100269 RTC_DLOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
Yves Gerey665174f2018-06-19 15:03:05 +0200270 "stored level from "
271 << level_ << " to " << voe_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000272 level_ = voe_level;
273 // Always allow the user to increase the volume.
274 if (level_ > max_level_) {
275 SetMaxLevel(level_);
276 }
277 // Take no action in this case, since we can't be sure when the volume
278 // was manually adjusted. The compressor will still provide some of the
279 // desired gain change.
280 agc_->Reset();
281 return;
282 }
283
284 new_level = std::min(new_level, max_level_);
285 if (new_level == level_) {
286 return;
287 }
288
289 volume_callbacks_->SetMicVolume(new_level);
Jonas Olsson645b0272018-02-15 15:16:27 +0100290 RTC_DLOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", "
291 << "level_=" << level_ << ", "
292 << "new_level=" << new_level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000293 level_ = new_level;
294}
295
296void AgcManagerDirect::SetMaxLevel(int level) {
henrik.lundinbd681b92016-12-05 09:08:42 -0800297 RTC_DCHECK_GE(level, clipped_level_min_);
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000298 max_level_ = level;
299 // Scale the |kSurplusCompressionGain| linearly across the restricted
300 // level range.
henrik.lundinbd681b92016-12-05 09:08:42 -0800301 max_compression_gain_ =
302 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) /
303 (kMaxMicLevel - clipped_level_min_) *
304 kSurplusCompressionGain +
305 0.5f);
Jonas Olsson645b0272018-02-15 15:16:27 +0100306 RTC_DLOG(LS_INFO) << "[agc] max_level_=" << max_level_
307 << ", max_compression_gain_=" << max_compression_gain_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000308}
309
310void AgcManagerDirect::SetCaptureMuted(bool muted) {
311 if (capture_muted_ == muted) {
312 return;
313 }
314 capture_muted_ = muted;
315
316 if (!muted) {
317 // When we unmute, we should reset things to be safe.
318 check_volume_on_next_process_ = true;
319 }
320}
321
322float AgcManagerDirect::voice_probability() {
aluebsecf6b812015-06-25 12:28:48 -0700323 return agc_->voice_probability();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000324}
325
326int AgcManagerDirect::CheckVolumeAndReset() {
327 int level = volume_callbacks_->GetMicVolume();
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000328 // Reasons for taking action at startup:
329 // 1) A person starting a call is expected to be heard.
330 // 2) Independent of interpretation of |level| == 0 we should raise it so the
331 // AGC can do its job properly.
332 if (level == 0 && !startup_) {
Jonas Olsson645b0272018-02-15 15:16:27 +0100333 RTC_DLOG(LS_INFO)
Mirko Bonadei675513b2017-11-09 11:09:25 +0100334 << "[agc] VolumeCallbacks returned level=0, taking no action.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000335 return 0;
336 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100337 if (level < 0 || level > kMaxMicLevel) {
338 RTC_LOG(LS_ERROR) << "[agc] VolumeCallbacks returned an invalid level="
339 << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000340 return -1;
341 }
Jonas Olsson645b0272018-02-15 15:16:27 +0100342 RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000343
Bjorn Volckeradc46c42015-04-15 11:42:40 +0200344 int minLevel = startup_ ? startup_min_level_ : kMinMicLevel;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000345 if (level < minLevel) {
346 level = minLevel;
Jonas Olsson645b0272018-02-15 15:16:27 +0100347 RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000348 volume_callbacks_->SetMicVolume(level);
349 }
350 agc_->Reset();
351 level_ = level;
352 startup_ = false;
353 return 0;
354}
355
356// Requests the RMS error from AGC and distributes the required gain change
357// between the digital compression stage and volume slider. We use the
358// compressor first, providing a slack region around the current slider
359// position to reduce movement.
360//
361// If the slider needs to be moved, we check first if the user has adjusted
362// it, in which case we take no action and cache the updated level.
363void AgcManagerDirect::UpdateGain() {
364 int rms_error = 0;
365 if (!agc_->GetRmsErrorDb(&rms_error)) {
366 // No error update ready.
367 return;
368 }
369 // The compressor will always add at least kMinCompressionGain. In effect,
370 // this adjusts our target gain upward by the same amount and rms_error
371 // needs to reflect that.
372 rms_error += kMinCompressionGain;
373
374 // Handle as much error as possible with the compressor first.
kwiberg07038562017-06-12 11:40:47 -0700375 int raw_compression =
376 rtc::SafeClamp(rms_error, kMinCompressionGain, max_compression_gain_);
377
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000378 // Deemphasize the compression gain error. Move halfway between the current
379 // target and the newly received target. This serves to soften perceptible
380 // intra-talkspurt adjustments, at the cost of some adaptation speed.
381 if ((raw_compression == max_compression_gain_ &&
Yves Gerey665174f2018-06-19 15:03:05 +0200382 target_compression_ == max_compression_gain_ - 1) ||
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000383 (raw_compression == kMinCompressionGain &&
Yves Gerey665174f2018-06-19 15:03:05 +0200384 target_compression_ == kMinCompressionGain + 1)) {
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000385 // Special case to allow the target to reach the endpoints of the
386 // compression range. The deemphasis would otherwise halt it at 1 dB shy.
387 target_compression_ = raw_compression;
388 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200389 target_compression_ =
390 (raw_compression - target_compression_) / 2 + target_compression_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000391 }
392
393 // Residual error will be handled by adjusting the volume slider. Use the
394 // raw rather than deemphasized compression here as we would otherwise
395 // shrink the amount of slack the compressor provides.
kwiberg07038562017-06-12 11:40:47 -0700396 const int residual_gain =
397 rtc::SafeClamp(rms_error - raw_compression, -kMaxResidualGainChange,
398 kMaxResidualGainChange);
Jonas Olsson645b0272018-02-15 15:16:27 +0100399 RTC_DLOG(LS_INFO) << "[agc] rms_error=" << rms_error
400 << ", target_compression=" << target_compression_
401 << ", residual_gain=" << residual_gain;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000402 if (residual_gain == 0)
403 return;
404
henrik.lundin3edc7f02016-11-24 01:42:46 -0800405 int old_level = level_;
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000406 SetLevel(LevelFromGainError(residual_gain, level_));
henrik.lundin3edc7f02016-11-24 01:42:46 -0800407 if (old_level != level_) {
408 // level_ was updated by SetLevel; log the new value.
henrik.lundin45bb5132016-12-06 04:28:04 -0800409 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1,
410 kMaxMicLevel, 50);
henrik.lundin3edc7f02016-11-24 01:42:46 -0800411 }
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000412}
413
414void AgcManagerDirect::UpdateCompressor() {
415 if (compression_ == target_compression_) {
416 return;
417 }
418
419 // Adapt the compression gain slowly towards the target, in order to avoid
420 // highly perceptible changes.
421 if (target_compression_ > compression_) {
422 compression_accumulator_ += kCompressionGainStep;
423 } else {
424 compression_accumulator_ -= kCompressionGainStep;
425 }
426
427 // The compressor accepts integer gains in dB. Adjust the gain when
428 // we've come within half a stepsize of the nearest integer. (We don't
429 // check for equality due to potential floating point imprecision).
430 int new_compression = compression_;
431 int nearest_neighbor = std::floor(compression_accumulator_ + 0.5);
432 if (std::fabs(compression_accumulator_ - nearest_neighbor) <
433 kCompressionGainStep / 2) {
434 new_compression = nearest_neighbor;
435 }
436
437 // Set the new compression gain.
438 if (new_compression != compression_) {
439 compression_ = new_compression;
440 compression_accumulator_ = new_compression;
441 if (gctrl_->set_compression_gain_db(compression_) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100442 RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << compression_
443 << ") failed.";
pbos@webrtc.org788acd12014-12-15 09:41:24 +0000444 }
445 }
446}
447
448} // namespace webrtc