• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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