Line data Source code
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 "webrtc/modules/audio_processing/gain_control_impl.h"
12 :
13 : #include "webrtc/base/constructormagic.h"
14 : #include "webrtc/base/optional.h"
15 : #include "webrtc/modules/audio_processing/audio_buffer.h"
16 : #include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
17 : #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h"
18 :
19 : namespace webrtc {
20 :
21 : typedef void Handle;
22 :
23 : namespace {
24 0 : int16_t MapSetting(GainControl::Mode mode) {
25 0 : switch (mode) {
26 : case GainControl::kAdaptiveAnalog:
27 0 : return kAgcModeAdaptiveAnalog;
28 : case GainControl::kAdaptiveDigital:
29 0 : return kAgcModeAdaptiveDigital;
30 : case GainControl::kFixedDigital:
31 0 : return kAgcModeFixedDigital;
32 : }
33 0 : RTC_NOTREACHED();
34 0 : return -1;
35 : }
36 :
37 : } // namespace
38 :
39 : class GainControlImpl::GainController {
40 : public:
41 0 : explicit GainController() {
42 0 : state_ = WebRtcAgc_Create();
43 0 : RTC_CHECK(state_);
44 0 : }
45 :
46 0 : ~GainController() {
47 0 : RTC_DCHECK(state_);
48 0 : WebRtcAgc_Free(state_);
49 0 : }
50 :
51 0 : Handle* state() {
52 0 : RTC_DCHECK(state_);
53 0 : return state_;
54 : }
55 :
56 0 : void Initialize(int minimum_capture_level,
57 : int maximum_capture_level,
58 : Mode mode,
59 : int sample_rate_hz,
60 : int capture_level) {
61 0 : RTC_DCHECK(state_);
62 : int error =
63 0 : WebRtcAgc_Init(state_, minimum_capture_level, maximum_capture_level,
64 0 : MapSetting(mode), sample_rate_hz);
65 0 : RTC_DCHECK_EQ(0, error);
66 :
67 0 : set_capture_level(capture_level);
68 0 : }
69 :
70 0 : void set_capture_level(int capture_level) {
71 0 : capture_level_ = rtc::Optional<int>(capture_level);
72 0 : }
73 :
74 0 : int get_capture_level() {
75 0 : RTC_DCHECK(capture_level_);
76 0 : return *capture_level_;
77 : }
78 :
79 : private:
80 : Handle* state_;
81 : // TODO(peah): Remove the optional once the initialization is moved into the
82 : // ctor.
83 : rtc::Optional<int> capture_level_;
84 :
85 : RTC_DISALLOW_COPY_AND_ASSIGN(GainController);
86 : };
87 :
88 : int GainControlImpl::instance_counter_ = 0;
89 :
90 0 : GainControlImpl::GainControlImpl(rtc::CriticalSection* crit_render,
91 0 : rtc::CriticalSection* crit_capture)
92 : : crit_render_(crit_render),
93 : crit_capture_(crit_capture),
94 0 : data_dumper_(new ApmDataDumper(instance_counter_)),
95 : mode_(kAdaptiveAnalog),
96 : minimum_capture_level_(0),
97 : maximum_capture_level_(255),
98 : limiter_enabled_(true),
99 : target_level_dbfs_(3),
100 : compression_gain_db_(9),
101 : analog_capture_level_(0),
102 : was_analog_level_set_(false),
103 0 : stream_is_saturated_(false) {
104 0 : RTC_DCHECK(crit_render);
105 0 : RTC_DCHECK(crit_capture);
106 0 : }
107 :
108 0 : GainControlImpl::~GainControlImpl() {}
109 :
110 0 : void GainControlImpl::ProcessRenderAudio(
111 : rtc::ArrayView<const int16_t> packed_render_audio) {
112 0 : rtc::CritScope cs_capture(crit_capture_);
113 0 : if (!enabled_) {
114 0 : return;
115 : }
116 :
117 0 : for (auto& gain_controller : gain_controllers_) {
118 0 : WebRtcAgc_AddFarend(gain_controller->state(), packed_render_audio.data(),
119 0 : packed_render_audio.size());
120 : }
121 : }
122 :
123 0 : void GainControlImpl::PackRenderAudioBuffer(
124 : AudioBuffer* audio,
125 : std::vector<int16_t>* packed_buffer) {
126 0 : RTC_DCHECK_GE(160, audio->num_frames_per_band());
127 :
128 0 : packed_buffer->clear();
129 : packed_buffer->insert(
130 0 : packed_buffer->end(), audio->mixed_low_pass_data(),
131 0 : (audio->mixed_low_pass_data() + audio->num_frames_per_band()));
132 0 : }
133 :
134 0 : int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) {
135 0 : rtc::CritScope cs(crit_capture_);
136 :
137 0 : if (!enabled_) {
138 0 : return AudioProcessing::kNoError;
139 : }
140 :
141 0 : RTC_DCHECK(num_proc_channels_);
142 0 : RTC_DCHECK_GE(160, audio->num_frames_per_band());
143 0 : RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
144 0 : RTC_DCHECK_LE(*num_proc_channels_, gain_controllers_.size());
145 :
146 0 : if (mode_ == kAdaptiveAnalog) {
147 0 : int capture_channel = 0;
148 0 : for (auto& gain_controller : gain_controllers_) {
149 0 : gain_controller->set_capture_level(analog_capture_level_);
150 0 : int err = WebRtcAgc_AddMic(
151 : gain_controller->state(), audio->split_bands(capture_channel),
152 0 : audio->num_bands(), audio->num_frames_per_band());
153 :
154 0 : if (err != AudioProcessing::kNoError) {
155 0 : return AudioProcessing::kUnspecifiedError;
156 : }
157 0 : ++capture_channel;
158 : }
159 0 : } else if (mode_ == kAdaptiveDigital) {
160 0 : int capture_channel = 0;
161 0 : for (auto& gain_controller : gain_controllers_) {
162 0 : int32_t capture_level_out = 0;
163 0 : int err = WebRtcAgc_VirtualMic(
164 : gain_controller->state(), audio->split_bands(capture_channel),
165 : audio->num_bands(), audio->num_frames_per_band(),
166 0 : analog_capture_level_, &capture_level_out);
167 :
168 0 : gain_controller->set_capture_level(capture_level_out);
169 :
170 0 : if (err != AudioProcessing::kNoError) {
171 0 : return AudioProcessing::kUnspecifiedError;
172 : }
173 0 : ++capture_channel;
174 : }
175 : }
176 :
177 0 : return AudioProcessing::kNoError;
178 : }
179 :
180 0 : int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio,
181 : bool stream_has_echo) {
182 0 : rtc::CritScope cs(crit_capture_);
183 :
184 0 : if (!enabled_) {
185 0 : return AudioProcessing::kNoError;
186 : }
187 :
188 0 : if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) {
189 0 : return AudioProcessing::kStreamParameterNotSetError;
190 : }
191 :
192 0 : RTC_DCHECK(num_proc_channels_);
193 0 : RTC_DCHECK_GE(160, audio->num_frames_per_band());
194 0 : RTC_DCHECK_EQ(audio->num_channels(), *num_proc_channels_);
195 :
196 0 : stream_is_saturated_ = false;
197 0 : int capture_channel = 0;
198 0 : for (auto& gain_controller : gain_controllers_) {
199 0 : int32_t capture_level_out = 0;
200 0 : uint8_t saturation_warning = 0;
201 :
202 : // The call to stream_has_echo() is ok from a deadlock perspective
203 : // as the capture lock is allready held.
204 0 : int err = WebRtcAgc_Process(
205 : gain_controller->state(), audio->split_bands_const(capture_channel),
206 : audio->num_bands(), audio->num_frames_per_band(),
207 : audio->split_bands(capture_channel),
208 : gain_controller->get_capture_level(), &capture_level_out,
209 0 : stream_has_echo, &saturation_warning);
210 :
211 0 : if (err != AudioProcessing::kNoError) {
212 0 : return AudioProcessing::kUnspecifiedError;
213 : }
214 :
215 0 : gain_controller->set_capture_level(capture_level_out);
216 0 : if (saturation_warning == 1) {
217 0 : stream_is_saturated_ = true;
218 : }
219 :
220 0 : ++capture_channel;
221 : }
222 :
223 0 : RTC_DCHECK_LT(0ul, *num_proc_channels_);
224 0 : if (mode_ == kAdaptiveAnalog) {
225 : // Take the analog level to be the average across the handles.
226 0 : analog_capture_level_ = 0;
227 0 : for (auto& gain_controller : gain_controllers_) {
228 0 : analog_capture_level_ += gain_controller->get_capture_level();
229 : }
230 :
231 0 : analog_capture_level_ /= (*num_proc_channels_);
232 : }
233 :
234 0 : was_analog_level_set_ = false;
235 0 : return AudioProcessing::kNoError;
236 : }
237 :
238 0 : int GainControlImpl::compression_gain_db() const {
239 0 : rtc::CritScope cs(crit_capture_);
240 0 : return compression_gain_db_;
241 : }
242 :
243 : // TODO(ajm): ensure this is called under kAdaptiveAnalog.
244 0 : int GainControlImpl::set_stream_analog_level(int level) {
245 0 : rtc::CritScope cs(crit_capture_);
246 0 : data_dumper_->DumpRaw("gain_control_set_stream_analog_level", 1, &level);
247 :
248 0 : was_analog_level_set_ = true;
249 0 : if (level < minimum_capture_level_ || level > maximum_capture_level_) {
250 0 : return AudioProcessing::kBadParameterError;
251 : }
252 0 : analog_capture_level_ = level;
253 :
254 0 : return AudioProcessing::kNoError;
255 : }
256 :
257 0 : int GainControlImpl::stream_analog_level() {
258 0 : rtc::CritScope cs(crit_capture_);
259 0 : data_dumper_->DumpRaw("gain_control_stream_analog_level", 1,
260 0 : &analog_capture_level_);
261 : // TODO(ajm): enable this assertion?
262 : //RTC_DCHECK_EQ(kAdaptiveAnalog, mode_);
263 :
264 0 : return analog_capture_level_;
265 : }
266 :
267 0 : int GainControlImpl::Enable(bool enable) {
268 0 : rtc::CritScope cs_render(crit_render_);
269 0 : rtc::CritScope cs_capture(crit_capture_);
270 0 : if (enable && !enabled_) {
271 0 : enabled_ = enable; // Must be set before Initialize() is called.
272 :
273 0 : RTC_DCHECK(num_proc_channels_);
274 0 : RTC_DCHECK(sample_rate_hz_);
275 0 : Initialize(*num_proc_channels_, *sample_rate_hz_);
276 : } else {
277 0 : enabled_ = enable;
278 : }
279 0 : return AudioProcessing::kNoError;
280 : }
281 :
282 0 : bool GainControlImpl::is_enabled() const {
283 0 : rtc::CritScope cs(crit_capture_);
284 0 : return enabled_;
285 : }
286 :
287 0 : int GainControlImpl::set_mode(Mode mode) {
288 0 : rtc::CritScope cs_render(crit_render_);
289 0 : rtc::CritScope cs_capture(crit_capture_);
290 0 : if (MapSetting(mode) == -1) {
291 0 : return AudioProcessing::kBadParameterError;
292 : }
293 :
294 0 : mode_ = mode;
295 0 : RTC_DCHECK(num_proc_channels_);
296 0 : RTC_DCHECK(sample_rate_hz_);
297 0 : Initialize(*num_proc_channels_, *sample_rate_hz_);
298 0 : return AudioProcessing::kNoError;
299 : }
300 :
301 0 : GainControl::Mode GainControlImpl::mode() const {
302 0 : rtc::CritScope cs(crit_capture_);
303 0 : return mode_;
304 : }
305 :
306 0 : int GainControlImpl::set_analog_level_limits(int minimum,
307 : int maximum) {
308 0 : if (minimum < 0) {
309 0 : return AudioProcessing::kBadParameterError;
310 : }
311 :
312 0 : if (maximum > 65535) {
313 0 : return AudioProcessing::kBadParameterError;
314 : }
315 :
316 0 : if (maximum < minimum) {
317 0 : return AudioProcessing::kBadParameterError;
318 : }
319 :
320 0 : size_t num_proc_channels_local = 0u;
321 0 : int sample_rate_hz_local = 0;
322 : {
323 0 : rtc::CritScope cs(crit_capture_);
324 :
325 0 : minimum_capture_level_ = minimum;
326 0 : maximum_capture_level_ = maximum;
327 :
328 0 : RTC_DCHECK(num_proc_channels_);
329 0 : RTC_DCHECK(sample_rate_hz_);
330 0 : num_proc_channels_local = *num_proc_channels_;
331 0 : sample_rate_hz_local = *sample_rate_hz_;
332 : }
333 0 : Initialize(num_proc_channels_local, sample_rate_hz_local);
334 0 : return AudioProcessing::kNoError;
335 : }
336 :
337 0 : int GainControlImpl::analog_level_minimum() const {
338 0 : rtc::CritScope cs(crit_capture_);
339 0 : return minimum_capture_level_;
340 : }
341 :
342 0 : int GainControlImpl::analog_level_maximum() const {
343 0 : rtc::CritScope cs(crit_capture_);
344 0 : return maximum_capture_level_;
345 : }
346 :
347 0 : bool GainControlImpl::stream_is_saturated() const {
348 0 : rtc::CritScope cs(crit_capture_);
349 0 : return stream_is_saturated_;
350 : }
351 :
352 0 : int GainControlImpl::set_target_level_dbfs(int level) {
353 0 : if (level > 31 || level < 0) {
354 0 : return AudioProcessing::kBadParameterError;
355 : }
356 : {
357 0 : rtc::CritScope cs(crit_capture_);
358 0 : target_level_dbfs_ = level;
359 : }
360 0 : return Configure();
361 : }
362 :
363 0 : int GainControlImpl::target_level_dbfs() const {
364 0 : rtc::CritScope cs(crit_capture_);
365 0 : return target_level_dbfs_;
366 : }
367 :
368 0 : int GainControlImpl::set_compression_gain_db(int gain) {
369 0 : if (gain < 0 || gain > 90) {
370 0 : return AudioProcessing::kBadParameterError;
371 : }
372 : {
373 0 : rtc::CritScope cs(crit_capture_);
374 0 : compression_gain_db_ = gain;
375 : }
376 0 : return Configure();
377 : }
378 :
379 0 : int GainControlImpl::enable_limiter(bool enable) {
380 : {
381 0 : rtc::CritScope cs(crit_capture_);
382 0 : limiter_enabled_ = enable;
383 : }
384 0 : return Configure();
385 : }
386 :
387 0 : bool GainControlImpl::is_limiter_enabled() const {
388 0 : rtc::CritScope cs(crit_capture_);
389 0 : return limiter_enabled_;
390 : }
391 :
392 0 : void GainControlImpl::Initialize(size_t num_proc_channels, int sample_rate_hz) {
393 0 : rtc::CritScope cs_render(crit_render_);
394 0 : rtc::CritScope cs_capture(crit_capture_);
395 0 : data_dumper_->InitiateNewSetOfRecordings();
396 :
397 0 : num_proc_channels_ = rtc::Optional<size_t>(num_proc_channels);
398 0 : sample_rate_hz_ = rtc::Optional<int>(sample_rate_hz);
399 :
400 0 : if (!enabled_) {
401 0 : return;
402 : }
403 :
404 0 : gain_controllers_.resize(*num_proc_channels_);
405 0 : for (auto& gain_controller : gain_controllers_) {
406 0 : if (!gain_controller) {
407 0 : gain_controller.reset(new GainController());
408 : }
409 0 : gain_controller->Initialize(minimum_capture_level_, maximum_capture_level_,
410 0 : mode_, *sample_rate_hz_, analog_capture_level_);
411 : }
412 :
413 0 : Configure();
414 : }
415 :
416 0 : int GainControlImpl::Configure() {
417 0 : rtc::CritScope cs_render(crit_render_);
418 0 : rtc::CritScope cs_capture(crit_capture_);
419 : WebRtcAgcConfig config;
420 : // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we
421 : // change the interface.
422 : //RTC_DCHECK_LE(target_level_dbfs_, 0);
423 : //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_);
424 0 : config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_);
425 0 : config.compressionGaindB =
426 0 : static_cast<int16_t>(compression_gain_db_);
427 0 : config.limiterEnable = limiter_enabled_;
428 :
429 0 : int error = AudioProcessing::kNoError;
430 0 : for (auto& gain_controller : gain_controllers_) {
431 : const int handle_error =
432 0 : WebRtcAgc_set_config(gain_controller->state(), config);
433 0 : if (handle_error != AudioProcessing::kNoError) {
434 0 : error = handle_error;
435 : }
436 : }
437 0 : return error;
438 : }
439 : } // namespace webrtc
|