1 /*
2 * Copyright (c) 2012 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/gain_control_impl.h"
12
13 #include <cstdint>
14
15 #include "absl/types/optional.h"
16 #include "modules/audio_processing/agc/legacy/gain_control.h"
17 #include "modules/audio_processing/audio_buffer.h"
18 #include "modules/audio_processing/include/audio_processing.h"
19 #include "modules/audio_processing/logging/apm_data_dumper.h"
20 #include "rtc_base/checks.h"
21 #include "rtc_base/logging.h"
22 #include "system_wrappers/include/field_trial.h"
23
24 namespace webrtc {
25
26 typedef void Handle;
27
28 namespace {
MapSetting(GainControl::Mode mode)29 int16_t MapSetting(GainControl::Mode mode) {
30 switch (mode) {
31 case GainControl::kAdaptiveAnalog:
32 return kAgcModeAdaptiveAnalog;
33 case GainControl::kAdaptiveDigital:
34 return kAgcModeAdaptiveDigital;
35 case GainControl::kFixedDigital:
36 return kAgcModeFixedDigital;
37 }
38 RTC_DCHECK_NOTREACHED();
39 return -1;
40 }
41
42 // Applies the sub-frame `gains` to all the bands in `out` and clamps the output
43 // in the signed 16 bit range.
ApplyDigitalGain(const int32_t gains[11],size_t num_bands,float * const * out)44 void 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
73 } // namespace
74
75 struct GainControlImpl::MonoAgcState {
MonoAgcStatewebrtc::GainControlImpl::MonoAgcState76 MonoAgcState() {
77 state = WebRtcAgc_Create();
78 RTC_CHECK(state);
79 }
80
~MonoAgcStatewebrtc::GainControlImpl::MonoAgcState81 ~MonoAgcState() {
82 RTC_DCHECK(state);
83 WebRtcAgc_Free(state);
84 }
85
86 MonoAgcState(const MonoAgcState&) = delete;
87 MonoAgcState& operator=(const MonoAgcState&) = delete;
88 int32_t gains[11];
89 Handle* state;
90 };
91
92 int GainControlImpl::instance_counter_ = 0;
93
GainControlImpl()94 GainControlImpl::GainControlImpl()
95 : data_dumper_(new ApmDataDumper(instance_counter_)),
96 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),
104 stream_is_saturated_(false) {}
105
106 GainControlImpl::~GainControlImpl() = default;
107
ProcessRenderAudio(rtc::ArrayView<const int16_t> packed_render_audio)108 void GainControlImpl::ProcessRenderAudio(
109 rtc::ArrayView<const int16_t> packed_render_audio) {
110 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
111 WebRtcAgc_AddFarend(mono_agcs_[ch]->state, packed_render_audio.data(),
112 packed_render_audio.size());
113 }
114 }
115
PackRenderAudioBuffer(const AudioBuffer & audio,std::vector<int16_t> * packed_buffer)116 void GainControlImpl::PackRenderAudioBuffer(
117 const AudioBuffer& audio,
118 std::vector<int16_t>* packed_buffer) {
119 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
120 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());
124 if (audio.num_channels() == 1) {
125 FloatS16ToS16(audio.split_bands_const(0)[kBand0To8kHz],
126 audio.num_frames_per_band(), mixed_16_kHz_render_data.data());
127 } else {
128 const int num_channels = static_cast<int>(audio.num_channels());
129 for (size_t i = 0; i < audio.num_frames_per_band(); ++i) {
130 int32_t sum = 0;
131 for (int ch = 0; ch < num_channels; ++ch) {
132 sum += FloatS16ToS16(audio.split_channels_const(kBand0To8kHz)[ch][i]);
133 }
134 mixed_16_kHz_render_data[i] = sum / num_channels;
135 }
136 }
137
138 packed_buffer->clear();
139 packed_buffer->insert(
140 packed_buffer->end(), mixed_16_kHz_render.data(),
141 (mixed_16_kHz_render.data() + audio.num_frames_per_band()));
142 }
143
AnalyzeCaptureAudio(const AudioBuffer & audio)144 int GainControlImpl::AnalyzeCaptureAudio(const AudioBuffer& audio) {
145 RTC_DCHECK(num_proc_channels_);
146 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength, audio.num_frames_per_band());
147 RTC_DCHECK_EQ(audio.num_channels(), *num_proc_channels_);
148 RTC_DCHECK_LE(*num_proc_channels_, mono_agcs_.size());
149
150 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
155 if (mode_ == kAdaptiveAnalog) {
156 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
157 capture_levels_[ch] = analog_capture_level_;
158
159 audio.ExportSplitChannelData(ch, split_bands);
160
161 int err =
162 WebRtcAgc_AddMic(mono_agcs_[ch]->state, split_bands,
163 audio.num_bands(), audio.num_frames_per_band());
164
165 if (err != AudioProcessing::kNoError) {
166 return AudioProcessing::kUnspecifiedError;
167 }
168 }
169 } else if (mode_ == kAdaptiveDigital) {
170 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
171 int32_t capture_level_out = 0;
172
173 audio.ExportSplitChannelData(ch, split_bands);
174
175 int err =
176 WebRtcAgc_VirtualMic(mono_agcs_[ch]->state, split_bands,
177 audio.num_bands(), audio.num_frames_per_band(),
178 analog_capture_level_, &capture_level_out);
179
180 capture_levels_[ch] = capture_level_out;
181
182 if (err != AudioProcessing::kNoError) {
183 return AudioProcessing::kUnspecifiedError;
184 }
185 }
186 }
187
188 return AudioProcessing::kNoError;
189 }
190
ProcessCaptureAudio(AudioBuffer * audio,bool stream_has_echo)191 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
192 bool stream_has_echo) {
193 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
194 return AudioProcessing::kStreamParameterNotSetError;
195 }
196
197 RTC_DCHECK(num_proc_channels_);
198 RTC_DCHECK_GE(AudioBuffer::kMaxSplitFrameLength,
199 audio->num_frames_per_band());
200 RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
201
202 stream_is_saturated_ = false;
203 bool error_reported = false;
204 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
205 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]};
209 audio->ExportSplitChannelData(ch, split_bands);
210
211 // The call to stream_has_echo() is ok from a deadlock perspective
212 // as the capture lock is allready held.
213 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;
220
221 error_reported = error_reported || err_analyze != AudioProcessing::kNoError;
222
223 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;
231 }
232 }
233
234 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));
237 }
238
239 RTC_DCHECK_LT(0ul, *num_proc_channels_);
240 if (mode_ == kAdaptiveAnalog) {
241 // 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]);
246 }
247 }
248
249 if (error_reported) {
250 return AudioProcessing::kUnspecifiedError;
251 }
252
253 was_analog_level_set_ = false;
254
255 return AudioProcessing::kNoError;
256 }
257
258
259 // TODO(ajm): ensure this is called under kAdaptiveAnalog.
set_stream_analog_level(int level)260 int GainControlImpl::set_stream_analog_level(int level) {
261 data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
262
263 was_analog_level_set_ = true;
264 if (level < minimum_capture_level_ || level > maximum_capture_level_) {
265 return AudioProcessing::kBadParameterError;
266 }
267 analog_capture_level_ = level;
268
269 return AudioProcessing::kNoError;
270 }
271
stream_analog_level() const272 int GainControlImpl::stream_analog_level() const {
273 data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
274 &analog_capture_level_);
275 return analog_capture_level_;
276 }
277
set_mode(Mode mode)278 int GainControlImpl::set_mode(Mode mode) {
279 if (MapSetting(mode) == -1) {
280 return AudioProcessing::kBadParameterError;
281 }
282
283 mode_ = mode;
284 RTC_DCHECK(num_proc_channels_);
285 RTC_DCHECK(sample_rate_hz_);
286 Initialize(*num_proc_channels_, *sample_rate_hz_);
287 return AudioProcessing::kNoError;
288 }
289
290
set_analog_level_limits(int minimum,int maximum)291 int GainControlImpl::set_analog_level_limits(int minimum, int maximum) {
292 if (minimum < 0 || maximum > 65535 || maximum < minimum) {
293 return AudioProcessing::kBadParameterError;
294 }
295
296 minimum_capture_level_ = minimum;
297 maximum_capture_level_ = maximum;
298
299 RTC_DCHECK(num_proc_channels_);
300 RTC_DCHECK(sample_rate_hz_);
301 Initialize(*num_proc_channels_, *sample_rate_hz_);
302 return AudioProcessing::kNoError;
303 }
304
305
set_target_level_dbfs(int level)306 int GainControlImpl::set_target_level_dbfs(int level) {
307 if (level > 31 || level < 0) {
308 return AudioProcessing::kBadParameterError;
309 }
310 target_level_dbfs_ = level;
311 return Configure();
312 }
313
set_compression_gain_db(int gain)314 int GainControlImpl::set_compression_gain_db(int gain) {
315 if (gain < 0 || gain > 90) {
316 RTC_LOG(LS_ERROR) << "set_compression_gain_db(" << gain << ") failed.";
317 return AudioProcessing::kBadParameterError;
318 }
319 compression_gain_db_ = gain;
320 return Configure();
321 }
322
enable_limiter(bool enable)323 int GainControlImpl::enable_limiter(bool enable) {
324 limiter_enabled_ = enable;
325 return Configure();
326 }
327
Initialize(size_t num_proc_channels,int sample_rate_hz)328 void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
329 data_dumper_->InitiateNewSetOfRecordings();
330
331 RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
332 sample_rate_hz == 48000);
333
334 num_proc_channels_ = num_proc_channels;
335 sample_rate_hz_ = sample_rate_hz;
336
337 mono_agcs_.resize(*num_proc_channels_);
338 capture_levels_.resize(*num_proc_channels_);
339 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
340 if (!mono_agcs_[ch]) {
341 mono_agcs_[ch].reset(new MonoAgcState());
342 }
343
344 int error = WebRtcAgc_Init(mono_agcs_[ch]->state, minimum_capture_level_,
345 maximum_capture_level_, MapSetting(mode_),
346 *sample_rate_hz_);
347 RTC_DCHECK_EQ(error, 0);
348 capture_levels_[ch] = analog_capture_level_;
349 }
350
351 Configure();
352 }
353
Configure()354 int GainControlImpl::Configure() {
355 WebRtcAgcConfig config;
356 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
357 // change the interface.
358 // RTC_DCHECK_LE(target_level_dbfs_, 0);
359 // config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
360 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
361 config.compressionGaindB = static_cast<int16_t>(compression_gain_db_);
362 config.limiterEnable = limiter_enabled_;
363
364 int error = AudioProcessing::kNoError;
365 for (size_t ch = 0; ch < mono_agcs_.size(); ++ch) {
366 int error_ch = WebRtcAgc_set_config(mono_agcs_[ch]->state, config);
367 if (error_ch != AudioProcessing::kNoError) {
368 error = error_ch;
369 }
370 }
371 return error;
372 }
373 } // namespace webrtc
374