blob: 841d901933edff9f2b2bbc519e95853e1052062e [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
bjornv@webrtc.org0c6f9312012-01-30 09:39:08 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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/gain_control_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdint>
14
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020015#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/audio_processing/agc/legacy/gain_control.h"
17#include "modules/audio_processing/audio_buffer.h"
Yves Gerey988cc082018-10-23 12:03:01 +020018#include "modules/audio_processing/include/audio_processing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_processing/logging/apm_data_dumper.h"
Yves Gerey988cc082018-10-23 12:03:01 +020020#include "rtc_base/checks.h"
Per Åhgren3daedb62019-11-22 12:11:40 +010021#include "rtc_base/logging.h"
Per Åhgren77dc1992019-11-23 00:14:31 +010022#include "system_wrappers/include/field_trial.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023
niklase@google.com470e71d2011-07-07 08:21:25 +000024namespace webrtc {
25
26typedef void Handle;
27
niklase@google.com470e71d2011-07-07 08:21:25 +000028namespace {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000029int16_t MapSetting(GainControl::Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +000030 switch (mode) {
31 case GainControl::kAdaptiveAnalog:
32 return kAgcModeAdaptiveAnalog;
niklase@google.com470e71d2011-07-07 08:21:25 +000033 case GainControl::kAdaptiveDigital:
34 return kAgcModeAdaptiveDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000035 case GainControl::kFixedDigital:
36 return kAgcModeFixedDigital;
niklase@google.com470e71d2011-07-07 08:21:25 +000037 }
nisseeb4ca4e2017-01-12 02:24:27 -080038 RTC_NOTREACHED();
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000039 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
niklase@google.com470e71d2011-07-07 08:21:25 +000041
Per Åhgren77dc1992019-11-23 00:14:31 +010042// Checks whether the legacy digital gain application should be used.
43bool UseLegacyDigitalGainApplier() {
44 return field_trial::IsEnabled("WebRTC-UseLegacyDigitalGainApplier");
45}
46
47// Floating point variant of WebRtcAgc_Process.
48void ApplyDigitalGain(const int32_t gains[11],
49 size_t num_bands,
50 float* const* out) {
51 constexpr float kScaling = 1.f / 65536.f;
52 constexpr int kNumSubSections = 16;
53 constexpr float kOneByNumSubSections = 1.f / kNumSubSections;
54
55 float gains_scaled[11];
56 for (int k = 0; k < 11; ++k) {
57 gains_scaled[k] = gains[k] * kScaling;
58 }
59
60 for (size_t b = 0; b < num_bands; ++b) {
61 float* out_band = out[b];
62 for (int k = 0, sample = 0; k < 10; ++k) {
63 const float delta =
64 (gains_scaled[k + 1] - gains_scaled[k]) * kOneByNumSubSections;
65 float gain = gains_scaled[k];
66 for (int n = 0; n < kNumSubSections; ++n, ++sample) {
67 RTC_DCHECK_EQ(k * kNumSubSections + n, sample);
68 out_band[sample] *= gain;
69 out_band[sample] =
70 std::min(32767.f, std::max(-32768.f, out_band[sample]));
71 gain += delta;
72 }
73 }
74 }
75}
76
peah2446e5a2015-11-18 06:11:13 -080077} // namespace
peah4d291f72015-11-16 23:52:25 -080078
Per Åhgren77dc1992019-11-23 00:14:31 +010079struct GainControlImpl::MonoAgcState {
80 MonoAgcState() {
81 state = WebRtcAgc_Create();
82 RTC_CHECK(state);
peahbfa97112016-03-10 21:09:04 -080083 }
84
Per Åhgren77dc1992019-11-23 00:14:31 +010085 ~MonoAgcState() {
86 RTC_DCHECK(state);
87 WebRtcAgc_Free(state);
peahbfa97112016-03-10 21:09:04 -080088 }
89
Per Åhgren77dc1992019-11-23 00:14:31 +010090 MonoAgcState(const MonoAgcState&) = delete;
91 MonoAgcState& operator=(const MonoAgcState&) = delete;
92 int32_t gains[11];
93 Handle* state;
peahbfa97112016-03-10 21:09:04 -080094};
95
peah135259a2016-10-28 03:12:11 -070096int GainControlImpl::instance_counter_ = 0;
97
Sam Zackrissonf0d1c032019-03-27 13:28:08 +010098GainControlImpl::GainControlImpl()
99 : data_dumper_(new ApmDataDumper(instance_counter_)),
Per Åhgren77dc1992019-11-23 00:14:31 +0100100 use_legacy_gain_applier_(UseLegacyDigitalGainApplier()),
peah4d291f72015-11-16 23:52:25 -0800101 mode_(kAdaptiveAnalog),
102 minimum_capture_level_(0),
103 maximum_capture_level_(255),
104 limiter_enabled_(true),
105 target_level_dbfs_(3),
106 compression_gain_db_(9),
107 analog_capture_level_(0),
108 was_analog_level_set_(false),
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100109 stream_is_saturated_(false) {}
niklase@google.com470e71d2011-07-07 08:21:25 +0000110
Per Åhgren77dc1992019-11-23 00:14:31 +0100111GainControlImpl::~GainControlImpl() = default;
niklase@google.com470e71d2011-07-07 08:21:25 +0000112
peah701d6282016-10-25 05:42:20 -0700113void GainControlImpl::ProcessRenderAudio(
114 rtc::ArrayView<const int16_t> packed_render_audio) {
peahbfa97112016-03-10 21:09:04 -0800115 if (!enabled_) {
peah4d291f72015-11-16 23:52:25 -0800116 return;
117 }
118
Per Åhgren77dc1992019-11-23 00:14:31 +0100119 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
120 WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
peah701d6282016-10-25 05:42:20 -0700121 packed_render_audio.size());
peah4d291f72015-11-16 23:52:25 -0800122 }
123}
124
peah701d6282016-10-25 05:42:20 -0700125void GainControlImpl::PackRenderAudioBuffer(
Per Åhgrene35b32c2019-11-22 18:22:04 +0100126 const AudioBuffer& audio,
peah701d6282016-10-25 05:42:20 -0700127 std::vector<int16_t>* packed_buffer) {
Per Åhgrene35b32c2019-11-22 18:22:04 +0100128 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
Per Åhgren77dc1992019-11-23 00:14:31 +0100129 std::array<int16_t, AudioBuffer::kMaxSplitFrameLength>
130 mixed_16_kHz_render_data;
131 rtc::ArrayView<const int16_t> mixed_16_kHz_render(
132 mixed_16_kHz_render_data.data(), audio.num_frames_per_band());
Per Åhgrene35b32c2019-11-22 18:22:04 +0100133 if (audio.num_channels() == 1) {
134 FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
Per Åhgren77dc1992019-11-23 00:14:31 +0100135 audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
Per Åhgrena1351272019-08-15 12:15:46 +0200136 } else {
Per Åhgrene35b32c2019-11-22 18:22:04 +0100137 const int num_channels = static_cast<int>(audio.num_channels());
138 for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100139 int32_t sum = 0;
140 for (int ch = 0; ch < num_channels; ++ch) {
141 sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
Per Åhgrena1351272019-08-15 12:15:46 +0200142 }
Per Åhgren77dc1992019-11-23 00:14:31 +0100143 mixed_16_kHz_render_data[i] = sum / num_channels;
Per Åhgrena1351272019-08-15 12:15:46 +0200144 }
Per Åhgrena1351272019-08-15 12:15:46 +0200145 }
146
peah701d6282016-10-25 05:42:20 -0700147 packed_buffer->clear();
Per Åhgren77dc1992019-11-23 00:14:31 +0100148 packed_buffer->insert(
149 packed_buffer->end(), mixed_16_kHz_render.data(),
150 (mixed_16_kHz_render.data() + audio.num_frames_per_band()));
peah701d6282016-10-25 05:42:20 -0700151}
152
Per Åhgrene35b32c2019-11-22 18:22:04 +0100153int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
peahbfa97112016-03-10 21:09:04 -0800154 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800155 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 }
157
peahb8fbb542016-03-15 02:28:08 -0700158 RTC_DCHECK(num_proc_channels_);
Per Åhgrene35b32c2019-11-22 18:22:04 +0100159 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
160 RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
Per Åhgren77dc1992019-11-23 00:14:31 +0100161 RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
Per Åhgren928146f2019-08-20 09:19:21 +0200163 int16_t split_band_data[AudioBuffer::kMaxNumBands]
164 [AudioBuffer::kMaxSplitFrameLength];
165 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
166 split_band_data[0], split_band_data[1], split_band_data[2]};
167
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 if (mode_ == kAdaptiveAnalog) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100169 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
170 capture_levels_[ch] = analog_capture_level_;
Per Åhgren928146f2019-08-20 09:19:21 +0200171
Per Åhgren77dc1992019-11-23 00:14:31 +0100172 audio.ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 09:19:21 +0200173
174 int err =
Per Åhgren77dc1992019-11-23 00:14:31 +0100175 WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
Per Åhgrene35b32c2019-11-22 18:22:04 +0100176 audio.num_bands(), audio.num_frames_per_band());
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
peahdf3efa82015-11-28 12:35:15 -0800178 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800179 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 }
181 }
182 } else if (mode_ == kAdaptiveDigital) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100183 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000184 int32_t capture_level_out = 0;
Per Åhgren928146f2019-08-20 09:19:21 +0200185
Per Åhgren77dc1992019-11-23 00:14:31 +0100186 audio.ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 09:19:21 +0200187
188 int err =
Per Åhgren77dc1992019-11-23 00:14:31 +0100189 WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
Per Åhgrene35b32c2019-11-22 18:22:04 +0100190 audio.num_bands(), audio.num_frames_per_band(),
Per Åhgren928146f2019-08-20 09:19:21 +0200191 analog_capture_level_, &capture_level_out);
192
Per Åhgren77dc1992019-11-23 00:14:31 +0100193 capture_levels_[ch] = capture_level_out;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194
peahdf3efa82015-11-28 12:35:15 -0800195 if (err != AudioProcessing::kNoError) {
peahbfa97112016-03-10 21:09:04 -0800196 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 }
199 }
200
peahdf3efa82015-11-28 12:35:15 -0800201 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000202}
203
peahb8fbb542016-03-15 02:28:08 -0700204int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
205 bool stream_has_echo) {
peahbfa97112016-03-10 21:09:04 -0800206 if (!enabled_) {
peahdf3efa82015-11-28 12:35:15 -0800207 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208 }
209
210 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
peahdf3efa82015-11-28 12:35:15 -0800211 return AudioProcessing::kStreamParameterNotSetError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 }
213
peahb8fbb542016-03-15 02:28:08 -0700214 RTC_DCHECK(num_proc_channels_);
Per Åhgren928146f2019-08-20 09:19:21 +0200215 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
216 audio->num_frames_per_band());
peahb8fbb542016-03-15 02:28:08 -0700217 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
219 stream_is_saturated_ = false;
Per Åhgren77dc1992019-11-23 00:14:31 +0100220 bool error_reported = false;
221 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
Per Åhgren928146f2019-08-20 09:19:21 +0200222 int16_t split_band_data[AudioBuffer::kMaxNumBands]
223 [AudioBuffer::kMaxSplitFrameLength];
224 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
225 split_band_data[0], split_band_data[1], split_band_data[2]};
Per Åhgren77dc1992019-11-23 00:14:31 +0100226 audio->ExportSplitChannelData(ch, split_bands);
Per Åhgren928146f2019-08-20 09:19:21 +0200227
peahdf3efa82015-11-28 12:35:15 -0800228 // The call to stream_has_echo() is ok from a deadlock perspective
229 // as the capture lock is allready held.
Per Åhgren77dc1992019-11-23 00:14:31 +0100230 int32_t new_capture_level = 0;
231 uint8_t saturation_warning = 0;
232 int err_analyze = WebRtcAgc_Analyze(
233 mono_agcs_[ch]->state, split_bands, audio->num_bands(),
234 audio->num_frames_per_band(), capture_levels_[ch], &new_capture_level,
235 stream_has_echo, &saturation_warning, mono_agcs_[ch]->gains);
236 capture_levels_[ch] = new_capture_level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000237
Per Åhgren77dc1992019-11-23 00:14:31 +0100238 error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
Per Åhgren928146f2019-08-20 09:19:21 +0200239
Per Åhgren77dc1992019-11-23 00:14:31 +0100240 stream_is_saturated_ = stream_is_saturated_ || saturation_warning == 1;
241 }
242
243 // Choose the minimun gain for application
244 size_t index_to_apply = 0;
245 for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
246 if (mono_agcs_[index_to_apply]->gains[10] < mono_agcs_[ch]->gains[10]) {
247 index_to_apply = ch;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 }
Per Åhgren77dc1992019-11-23 00:14:31 +0100249 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
Per Åhgren77dc1992019-11-23 00:14:31 +0100251 if (use_legacy_gain_applier_) {
252 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
253 int16_t split_band_data[AudioBuffer::kMaxNumBands]
254 [AudioBuffer::kMaxSplitFrameLength];
255 int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
256 split_band_data[0], split_band_data[1], split_band_data[2]};
257 audio->ExportSplitChannelData(ch, split_bands);
258
259 int err_process = WebRtcAgc_Process(
260 mono_agcs_[ch]->state, mono_agcs_[index_to_apply]->gains, split_bands,
261 audio->num_bands(), split_bands);
262 RTC_DCHECK_EQ(err_process, 0);
263
264 audio->ImportSplitChannelData(ch, split_bands);
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 }
Per Åhgren77dc1992019-11-23 00:14:31 +0100266 } else {
267 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
268 ApplyDigitalGain(mono_agcs_[index_to_apply]->gains, audio->num_bands(),
269 audio->split_bands(ch));
270 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 }
272
peahb8fbb542016-03-15 02:28:08 -0700273 RTC_DCHECK_LT(0ul, *num_proc_channels_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 if (mode_ == kAdaptiveAnalog) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100275 // Take the analog level to be the minimum accross all channels.
276 analog_capture_level_ = capture_levels_[0];
277 for (size_t ch = 1; ch < mono_agcs_.size(); ++ch) {
278 analog_capture_level_ =
279 std::min(analog_capture_level_, capture_levels_[ch]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 }
Per Åhgren77dc1992019-11-23 00:14:31 +0100281 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
Per Åhgren77dc1992019-11-23 00:14:31 +0100283 if (error_reported) {
284 return AudioProcessing::kUnspecifiedError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 }
286
287 was_analog_level_set_ = false;
Per Åhgren77dc1992019-11-23 00:14:31 +0100288
peahdf3efa82015-11-28 12:35:15 -0800289 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290}
291
aluebs11d4a422016-04-28 14:58:32 -0700292
niklase@google.com470e71d2011-07-07 08:21:25 +0000293// TODO(ajm): ensure this is called under kAdaptiveAnalog.
294int GainControlImpl::set_stream_analog_level(int level) {
peah135259a2016-10-28 03:12:11 -0700295 data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
peahdf3efa82015-11-28 12:35:15 -0800296
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 was_analog_level_set_ = true;
298 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
peahdf3efa82015-11-28 12:35:15 -0800299 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000301 analog_capture_level_ = level;
302
peahdf3efa82015-11-28 12:35:15 -0800303 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000304}
305
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100306int GainControlImpl::stream_analog_level() const {
peah135259a2016-10-28 03:12:11 -0700307 data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
308 &analog_capture_level_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 return analog_capture_level_;
310}
311
312int GainControlImpl::Enable(bool enable) {
peahbfa97112016-03-10 21:09:04 -0800313 if (enable && !enabled_) {
314 enabled_ = enable; // Must be set before Initialize() is called.
peahb8fbb542016-03-15 02:28:08 -0700315
316 RTC_DCHECK(num_proc_channels_);
317 RTC_DCHECK(sample_rate_hz_);
318 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800319 } else {
320 enabled_ = enable;
321 }
322 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000323}
324
niklase@google.com470e71d2011-07-07 08:21:25 +0000325int GainControlImpl::set_mode(Mode mode) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 if (MapSetting(mode) == -1) {
peahdf3efa82015-11-28 12:35:15 -0800327 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 }
329
330 mode_ = mode;
peahb8fbb542016-03-15 02:28:08 -0700331 RTC_DCHECK(num_proc_channels_);
332 RTC_DCHECK(sample_rate_hz_);
333 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800334 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000335}
336
niklase@google.com470e71d2011-07-07 08:21:25 +0000337
Yves Gerey665174f2018-06-19 15:03:05 +0200338int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
Per Åhgren77dc1992019-11-23 00:14:31 +0100339 if (minimum < 0 || maximum > 65535 || maximum < minimum) {
peahdf3efa82015-11-28 12:35:15 -0800340 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 }
342
Per Åhgren77dc1992019-11-23 00:14:31 +0100343 minimum_capture_level_ = minimum;
344 maximum_capture_level_ = maximum;
niklase@google.com470e71d2011-07-07 08:21:25 +0000345
Per Åhgren77dc1992019-11-23 00:14:31 +0100346 RTC_DCHECK(num_proc_channels_);
347 RTC_DCHECK(sample_rate_hz_);
348 Initialize(*num_proc_channels_, *sample_rate_hz_);
peahbfa97112016-03-10 21:09:04 -0800349 return AudioProcessing::kNoError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000350}
351
niklase@google.com470e71d2011-07-07 08:21:25 +0000352
353int GainControlImpl::set_target_level_dbfs(int level) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 if (level > 31 || level < 0) {
peahdf3efa82015-11-28 12:35:15 -0800355 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 }
Sam Zackrisson421c8592019-02-11 13:39:46 +0100357 target_level_dbfs_ = level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 return Configure();
359}
360
niklase@google.com470e71d2011-07-07 08:21:25 +0000361int GainControlImpl::set_compression_gain_db(int gain) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000362 if (gain < 0 || gain > 90) {
Per Åhgren3daedb62019-11-22 12:11:40 +0100363 RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
peahdf3efa82015-11-28 12:35:15 -0800364 return AudioProcessing::kBadParameterError;
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 }
Sam Zackrisson421c8592019-02-11 13:39:46 +0100366 compression_gain_db_ = gain;
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 return Configure();
368}
369
niklase@google.com470e71d2011-07-07 08:21:25 +0000370int GainControlImpl::enable_limiter(bool enable) {
Sam Zackrisson421c8592019-02-11 13:39:46 +0100371 limiter_enabled_ = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 return Configure();
373}
374
peahb8fbb542016-03-15 02:28:08 -0700375void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
peah135259a2016-10-28 03:12:11 -0700376 data_dumper_->InitiateNewSetOfRecordings();
peahb8fbb542016-03-15 02:28:08 -0700377
Per Åhgren27bd76b2019-11-26 09:23:45 +0100378 RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
379 sample_rate_hz == 48000);
380
Oskar Sundbomaa8b67d2017-11-17 14:34:48 +0100381 num_proc_channels_ = num_proc_channels;
382 sample_rate_hz_ = sample_rate_hz;
peahb8fbb542016-03-15 02:28:08 -0700383
peahbfa97112016-03-10 21:09:04 -0800384 if (!enabled_) {
385 return;
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 }
387
Per Åhgren77dc1992019-11-23 00:14:31 +0100388 mono_agcs_.resize(*num_proc_channels_);
389 capture_levels_.resize(*num_proc_channels_);
390 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
391 if (!mono_agcs_[ch]) {
392 mono_agcs_[ch].reset(new MonoAgcState());
peahbfa97112016-03-10 21:09:04 -0800393 }
Per Åhgren77dc1992019-11-23 00:14:31 +0100394
395 int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
396 maximum_capture_level_, MapSetting(mode_),
397 *sample_rate_hz_);
398 RTC_DCHECK_EQ(error, 0);
399 capture_levels_[ch] = analog_capture_level_;
peahbfa97112016-03-10 21:09:04 -0800400 }
401
402 Configure();
peah4d291f72015-11-16 23:52:25 -0800403}
404
peahbfa97112016-03-10 21:09:04 -0800405int GainControlImpl::Configure() {
pbos@webrtc.orge468bc92014-12-18 09:11:33 +0000406 WebRtcAgcConfig config;
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
408 // change the interface.
Yves Gerey665174f2018-06-19 15:03:05 +0200409 // RTC_DCHECK_LE(target_level_dbfs_, 0);
410 // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000411 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
Yves Gerey665174f2018-06-19 15:03:05 +0200412 config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 config.limiterEnable = limiter_enabled_;
414
peahbfa97112016-03-10 21:09:04 -0800415 int error = AudioProcessing::kNoError;
Per Åhgren77dc1992019-11-23 00:14:31 +0100416 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
417 int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
418 if (error_ch != AudioProcessing::kNoError) {
419 error = error_ch;
peahbfa97112016-03-10 21:09:04 -0800420 }
421 }
422 return error;
niklase@google.com470e71d2011-07-07 08:21:25 +0000423}
niklase@google.com470e71d2011-07-07 08:21:25 +0000424} // namespace webrtc