blob: 2a7f5272124d5462bd71740163b10e3e2c5ae9e5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:251/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:082 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:253 *
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 04:47:3111#include "modules/audio_processing/gain_control_impl.h"
niklase@google.com470e71d2011-07-07 08:21:2512
Yves Gerey988cc082018-10-23 10:03:0113#include <cstdint>
14
Danil Chapovalovdb9f7ab2018-06-19 08:50:1115#include "absl/types/optional.h"
Florent Castelli0afde762024-04-19 15:07:0816#include "api/audio/audio_processing.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3117#include "modules/audio_processing/agc/legacy/gain_control.h"
18#include "modules/audio_processing/audio_buffer.h"
19#include "modules/audio_processing/logging/apm_data_dumper.h"
Yves Gerey988cc082018-10-23 10:03:0120#include "rtc_base/checks.h"
Per Åhgren3daedb62019-11-22 11:11:4021#include "rtc_base/logging.h"
Per Åhgren77dc1992019-11-22 23:14:3122#include "system_wrappers/include/field_trial.h"
niklase@google.com470e71d2011-07-07 08:21:2523
niklase@google.com470e71d2011-07-07 08:21:2524namespace webrtc {
25
26typedef void Handle;
27
niklase@google.com470e71d2011-07-07 08:21:2528namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:5429int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:2530 switch (mode) {
31 case GainControl::kAdaptiveAnalog:
32 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:2533 case GainControl::kAdaptiveDigital:
34 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:2535 case GainControl::kFixedDigital:
36 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:2537 }
Artem Titovd3251962021-11-15 15:57:0738 RTC_DCHECK_NOTREACHED();
mflodman@webrtc.org657b2a42012-02-06 11:06:0139 return -1;
niklase@google.com470e71d2011-07-07 08:21:2540}
niklase@google.com470e71d2011-07-07 08:21:2541
Alessio Bazzica78b466a2022-11-18 19:58:0242// Applies the sub-frame `gains` to all the bands in `out` and clamps the output
43// in the signed 16 bit range.
Per Åhgren77dc1992019-11-22 23:14:3144void ApplyDigitalGain(const int32_t gains[11],
45 size_t num_bands,
46 float* const* out) {
47 constexpr float kScaling = 1.f / 65536.f;
48 constexpr int kNumSubSections = 16;
49 constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
50
51 float gains_scaled[11];
52 for (int k = 0; k < 11; ++k) {
53 gains_scaled[k] = gains[k] * kScaling;
54 }
55
56 for (size_t b = 0; b < num_bands; ++b) {
57 float* out_band = out[b];
58 for (int k = 0, sample = 0; k < 10; ++k) {
59 const float delta =
60 (gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
61 float gain = gains_scaled[k];
62 for (int n = 0; n < kNumSubSections; ++n, ++sample) {
63 RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
64 out_band[sample] *= gain;
65 out_band[sample] =
66 std::min(32767.f, std::max(-32768.f, out_band[sample]));
67 gain += delta;
68 }
69 }
70 }
71}
72
peah2446e5a2015-11-18 14:11:1373} // namespace
peah4d291f72015-11-17 07:52:2574
Per Åhgren77dc1992019-11-22 23:14:3175struct GainControlImpl::MonoAgcState {
76 MonoAgcState() {
77 state = WebRtcAgc_Create();
78 RTC_CHECK(state);
peahbfa97112016-03-11 05:09:0479 }
80
Per Åhgren77dc1992019-11-22 23:14:3181 ~MonoAgcState() {
82 RTC_DCHECK(state);
83 WebRtcAgc_Free(state);
peahbfa97112016-03-11 05:09:0484 }
85
Per Åhgren77dc1992019-11-22 23:14:3186 MonoAgcState(const MonoAgcState&) = delete;
87 MonoAgcState& operator=(const MonoAgcState&) = delete;
88 int32_t gains[11];
89 Handle* state;
peahbfa97112016-03-11 05:09:0490};
91
peah135259a2016-10-28 10:12:1192int GainControlImpl::instance_counter_ = 0;
93
Sam Zackrissonf0d1c032019-03-27 12:28:0894GainControlImpl::GainControlImpl()
95 : data_dumper_(new ApmDataDumper(instance_counter_)),
peah4d291f72015-11-17 07:52:2596 mode_(kAdaptiveAnalog),
97 minimum_capture_level_(0),
98 maximum_capture_level_(255),
99 limiter_enabled_(true),
100 target_level_dbfs_(3),
101 compression_gain_db_(9),
102 analog_capture_level_(0),
103 was_analog_level_set_(false),
Sam Zackrissonf0d1c032019-03-27 12:28:08104 stream_is_saturated_(false) {}
niklase@google.com470e71d2011-07-07 08:21:25105
Per Åhgren77dc1992019-11-22 23:14:31106GainControlImpl::~GainControlImpl() = default;
niklase@google.com470e71d2011-07-07 08:21:25107
peah701d6282016-10-25 12:42:20108void GainControlImpl::ProcessRenderAudio(
109 rtc::ArrayView<const int16_t> packed_render_audio) {
Per Åhgren77dc1992019-11-22 23:14:31110 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
111 WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
peah701d6282016-10-25 12:42:20112 packed_render_audio.size());
peah4d291f72015-11-17 07:52:25113 }
114}
115
peah701d6282016-10-25 12:42:20116void GainControlImpl::PackRenderAudioBuffer(
Per Åhgrene35b32c2019-11-22 17:22:04117 const AudioBuffer& audio,
peah701d6282016-10-25 12:42:20118 std::vector<int16_t>* packed_buffer) {
Per Åhgrene35b32c2019-11-22 17:22:04119 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
Per Åhgren77dc1992019-11-22 23:14:31120 std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
121 mixed_16_kHz_render_data;
122 rtc::ArrayView<const int16_t> mixed_16_kHz_render(
123 mixed_16_kHz_render_data.data(), audio.num_frames_per_band());
Per Åhgrene35b32c2019-11-22 17:22:04124 if (audio.num_channels() == 1) {
125 FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
Per Åhgren77dc1992019-11-22 23:14:31126 audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
Per Åhgrena1351272019-08-15 10:15:46127 } else {
Per Åhgrene35b32c2019-11-22 17:22:04128 const int num_channels = static_cast<int>(audio.num_channels());
129 for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
Per Åhgren77dc1992019-11-22 23:14:31130 int32_t sum = 0;
131 for (int ch = 0; ch < num_channels; ++ch) {
132 sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
Per Åhgrena1351272019-08-15 10:15:46133 }
Per Åhgren77dc1992019-11-22 23:14:31134 mixed_16_kHz_render_data[i] = sum / num_channels;
Per Åhgrena1351272019-08-15 10:15:46135 }
Per Åhgrena1351272019-08-15 10:15:46136 }
137
peah701d6282016-10-25 12:42:20138 packed_buffer->clear();
Per Åhgren77dc1992019-11-22 23:14:31139 packed_buffer->insert(
140 packed_buffer->end(), mixed_16_kHz_render.data(),
141 (mixed_16_kHz_render.data() + audio.num_frames_per_band()));
peah701d6282016-10-25 12:42:20142}
143
Per Åhgrene35b32c2019-11-22 17:22:04144int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
peahb8fbb542016-03-15 09:28:08145 RTC_DCHECK(num_proc_channels_);
Per Åhgrene35b32c2019-11-22 17:22:04146 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
147 RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
Per Åhgren77dc1992019-11-22 23:14:31148 RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
niklase@google.com470e71d2011-07-07 08:21:25149
Per Åhgren928146f2019-08-20 07:19:21150 int16_t split_band_data[AudioBuffer::kMaxNumBands]
151 [AudioBuffer::kMaxSplitFrameLength];
152 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
153 split_band_data[0], split_band_data[1], split_band_data[2]};
154
niklase@google.com470e71d2011-07-07 08:21:25155 if (mode_ == kAdaptiveAnalog) {
Per Åhgren77dc1992019-11-22 23:14:31156 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
157 capture_levels_[ch] = analog_capture_level_;
Per Åhgren928146f2019-08-20 07:19:21158
Per Åhgren77dc1992019-11-22 23:14:31159 audio.ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 07:19:21160
161 int err =
Per Åhgren77dc1992019-11-22 23:14:31162 WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
Per Åhgrene35b32c2019-11-22 17:22:04163 audio.num_bands(), audio.num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25164
peahdf3efa82015-11-28 20:35:15165 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-11 05:09:04166 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25167 }
168 }
169 } else if (mode_ == kAdaptiveDigital) {
Per Åhgren77dc1992019-11-22 23:14:31170 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54171 int32_t capture_level_out = 0;
Per Åhgren928146f2019-08-20 07:19:21172
Per Åhgren77dc1992019-11-22 23:14:31173 audio.ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 07:19:21174
175 int err =
Per Åhgren77dc1992019-11-22 23:14:31176 WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
Per Åhgrene35b32c2019-11-22 17:22:04177 audio.num_bands(), audio.num_frames_per_band(),
Per Åhgren928146f2019-08-20 07:19:21178 analog_capture_level_, &capture_level_out);
179
Per Åhgren77dc1992019-11-22 23:14:31180 capture_levels_[ch] = capture_level_out;
niklase@google.com470e71d2011-07-07 08:21:25181
peahdf3efa82015-11-28 20:35:15182 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-11 05:09:04183 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25184 }
niklase@google.com470e71d2011-07-07 08:21:25185 }
186 }
187
peahdf3efa82015-11-28 20:35:15188 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25189}
190
peahb8fbb542016-03-15 09:28:08191int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
192 bool stream_has_echo) {
niklase@google.com470e71d2011-07-07 08:21:25193 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
peahdf3efa82015-11-28 20:35:15194 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25195 }
196
peahb8fbb542016-03-15 09:28:08197 RTC_DCHECK(num_proc_channels_);
Per Åhgren928146f2019-08-20 07:19:21198 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
199 audio->num_frames_per_band());
peahb8fbb542016-03-15 09:28:08200 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25201
202 stream_is_saturated_ = false;
Per Åhgren77dc1992019-11-22 23:14:31203 bool error_reported = false;
204 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
Per Åhgren928146f2019-08-20 07:19:21205 int16_t split_band_data[AudioBuffer::kMaxNumBands]
206 [AudioBuffer::kMaxSplitFrameLength];
207 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
208 split_band_data[0], split_band_data[1], split_band_data[2]};
Per Åhgren77dc1992019-11-22 23:14:31209 audio->ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 07:19:21210
peahdf3efa82015-11-28 20:35:15211 // The call to stream_has_echo() is ok from a deadlock perspective
212 // as the capture lock is allready held.
Per Åhgren77dc1992019-11-22 23:14:31213 int32_t new_capture_level = 0;
214 uint8_t saturation_warning = 0;
215 int err_analyze = WebRtcAgc_Analyze(
216 mono_agcs_[ch]->state, split_bands, audio->num_bands(),
217 audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
218 stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
219 capture_levels_[ch] = new_capture_level;
niklase@google.com470e71d2011-07-07 08:21:25220
Per Åhgren77dc1992019-11-22 23:14:31221 error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
Per Åhgren928146f2019-08-20 07:19:21222
Per Åhgren77dc1992019-11-22 23:14:31223 stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
224 }
225
226 // Choose the minimun gain for application
227 size_t index_to_apply = 0;
228 for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
229 if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
230 index_to_apply = ch;
niklase@google.com470e71d2011-07-07 08:21:25231 }
Per Åhgren77dc1992019-11-22 23:14:31232 }
niklase@google.com470e71d2011-07-07 08:21:25233
Alessio Bazzica78b466a2022-11-18 19:58:02234 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
235 ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
236 audio->split_bands(ch));
niklase@google.com470e71d2011-07-07 08:21:25237 }
238
peahb8fbb542016-03-15 09:28:08239 RTC_DCHECK_LT(0ul, *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25240 if (mode_ == kAdaptiveAnalog) {
Per Åhgren77dc1992019-11-22 23:14:31241 // Take the analog level to be the minimum accross all channels.
242 analog_capture_level_ = capture_levels_[0];
243 for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
244 analog_capture_level_ =
245 std::min(analog_capture_level_, capture_levels_[ch]);
niklase@google.com470e71d2011-07-07 08:21:25246 }
Per Åhgren77dc1992019-11-22 23:14:31247 }
niklase@google.com470e71d2011-07-07 08:21:25248
Per Åhgren77dc1992019-11-22 23:14:31249 if (error_reported) {
250 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25251 }
252
253 was_analog_level_set_ = false;
Per Åhgren77dc1992019-11-22 23:14:31254
peahdf3efa82015-11-28 20:35:15255 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25256}
257
258// TODO(ajm): ensure this is called under kAdaptiveAnalog.
259int GainControlImpl::set_stream_analog_level(int level) {
peah135259a2016-10-28 10:12:11260 data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
peahdf3efa82015-11-28 20:35:15261
niklase@google.com470e71d2011-07-07 08:21:25262 was_analog_level_set_ = true;
263 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 20:35:15264 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25265 }
niklase@google.com470e71d2011-07-07 08:21:25266 analog_capture_level_ = level;
267
peahdf3efa82015-11-28 20:35:15268 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25269}
270
Sam Zackrissonf0d1c032019-03-27 12:28:08271int GainControlImpl::stream_analog_level() const {
peah135259a2016-10-28 10:12:11272 data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
273 &analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25274 return analog_capture_level_;
275}
276
niklase@google.com470e71d2011-07-07 08:21:25277int GainControlImpl::set_mode(Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25278 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 20:35:15279 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25280 }
281
282 mode_ = mode;
peahb8fbb542016-03-15 09:28:08283 RTC_DCHECK(num_proc_channels_);
284 RTC_DCHECK(sample_rate_hz_);
285 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-11 05:09:04286 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25287}
288
Yves Gerey665174f2018-06-19 13:03:05289int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
Per Åhgren77dc1992019-11-22 23:14:31290 if (minimum < 0 || maximum > 65535 || maximum < minimum) {
peahdf3efa82015-11-28 20:35:15291 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25292 }
293
Per Åhgren77dc1992019-11-22 23:14:31294 minimum_capture_level_ = minimum;
295 maximum_capture_level_ = maximum;
niklase@google.com470e71d2011-07-07 08:21:25296
Per Åhgren77dc1992019-11-22 23:14:31297 RTC_DCHECK(num_proc_channels_);
298 RTC_DCHECK(sample_rate_hz_);
299 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-11 05:09:04300 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25301}
302
niklase@google.com470e71d2011-07-07 08:21:25303int GainControlImpl::set_target_level_dbfs(int level) {
niklase@google.com470e71d2011-07-07 08:21:25304 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 20:35:15305 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25306 }
Sam Zackrisson421c8592019-02-11 12:39:46307 target_level_dbfs_ = level;
niklase@google.com470e71d2011-07-07 08:21:25308 return Configure();
309}
310
niklase@google.com470e71d2011-07-07 08:21:25311int GainControlImpl::set_compression_gain_db(int gain) {
niklase@google.com470e71d2011-07-07 08:21:25312 if (gain < 0 || gain > 90) {
Per Åhgren3daedb62019-11-22 11:11:40313 RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
peahdf3efa82015-11-28 20:35:15314 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25315 }
Sam Zackrisson421c8592019-02-11 12:39:46316 compression_gain_db_ = gain;
niklase@google.com470e71d2011-07-07 08:21:25317 return Configure();
318}
319
niklase@google.com470e71d2011-07-07 08:21:25320int GainControlImpl::enable_limiter(bool enable) {
Sam Zackrisson421c8592019-02-11 12:39:46321 limiter_enabled_ = enable;
niklase@google.com470e71d2011-07-07 08:21:25322 return Configure();
323}
324
peahb8fbb542016-03-15 09:28:08325void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
peah135259a2016-10-28 10:12:11326 data_dumper_->InitiateNewSetOfRecordings();
peahb8fbb542016-03-15 09:28:08327
Per Åhgren27bd76b2019-11-26 08:23:45328 RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
329 sample_rate_hz == 48000);
330
Oskar Sundbomaa8b67d2017-11-17 13:34:48331 num_proc_channels_ = num_proc_channels;
332 sample_rate_hz_ = sample_rate_hz;
peahb8fbb542016-03-15 09:28:08333
Per Åhgren77dc1992019-11-22 23:14:31334 mono_agcs_.resize(*num_proc_channels_);
335 capture_levels_.resize(*num_proc_channels_);
336 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
337 if (!mono_agcs_[ch]) {
338 mono_agcs_[ch].reset(new MonoAgcState());
peahbfa97112016-03-11 05:09:04339 }
Per Åhgren77dc1992019-11-22 23:14:31340
341 int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
342 maximum_capture_level_, MapSetting(mode_),
343 *sample_rate_hz_);
344 RTC_DCHECK_EQ(error, 0);
345 capture_levels_[ch] = analog_capture_level_;
peahbfa97112016-03-11 05:09:04346 }
347
348 Configure();
peah4d291f72015-11-17 07:52:25349}
350
peahbfa97112016-03-11 05:09:04351int GainControlImpl::Configure() {
pbos@webrtc.orge468bc92014-12-18 09:11:33352 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25353 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
354 // change the interface.
Yves Gerey665174f2018-06-19 13:03:05355 // RTC_DCHECK_LE(target_level_dbfs_, 0);
356 // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
pbos@webrtc.orgb7192b82013-04-10 07:50:54357 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
Yves Gerey665174f2018-06-19 13:03:05358 config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25359 config.limiterEnable = limiter_enabled_;
360
peahbfa97112016-03-11 05:09:04361 int error = AudioProcessing::kNoError;
Per Åhgren77dc1992019-11-22 23:14:31362 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
363 int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
364 if (error_ch != AudioProcessing::kNoError) {
365 error = error_ch;
peahbfa97112016-03-11 05:09:04366 }
367 }
368 return error;
niklase@google.com470e71d2011-07-07 08:21:25369}
niklase@google.com470e71d2011-07-07 08:21:25370} // namespace webrtc