OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_processing/agc/agc_manager_direct.h" | 11 #include "webrtc/modules/audio_processing/agc/agc_manager_direct.h" |
12 | 12 |
13 #include <cmath> | 13 #include <cmath> |
14 | 14 |
15 #ifdef WEBRTC_AGC_DEBUG_DUMP | 15 #ifdef WEBRTC_AGC_DEBUG_DUMP |
16 #include <cstdio> | 16 #include <cstdio> |
17 #endif | 17 #endif |
18 | 18 |
19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
20 #include "webrtc/modules/audio_processing/agc/gain_map_internal.h" | 20 #include "webrtc/modules/audio_processing/agc/gain_map_internal.h" |
21 #include "webrtc/modules/audio_processing/gain_control_impl.h" | 21 #include "webrtc/modules/audio_processing/gain_control_impl.h" |
22 #include "webrtc/modules/include/module_common_types.h" | 22 #include "webrtc/modules/include/module_common_types.h" |
23 #include "webrtc/system_wrappers/include/logging.h" | 23 #include "webrtc/system_wrappers/include/logging.h" |
24 #include "webrtc/system_wrappers/include/metrics.h" | 24 #include "webrtc/system_wrappers/include/metrics.h" |
25 | 25 |
26 namespace webrtc { | 26 namespace webrtc { |
27 | 27 |
28 namespace { | 28 namespace { |
29 | 29 |
30 // Lowest the microphone level can be lowered due to clipping. | |
31 const int kClippedLevelMin = 170; | |
32 // Amount the microphone level is lowered with every clipping event. | 30 // Amount the microphone level is lowered with every clipping event. |
33 const int kClippedLevelStep = 15; | 31 const int kClippedLevelStep = 15; |
34 // Proportion of clipped samples required to declare a clipping event. | 32 // Proportion of clipped samples required to declare a clipping event. |
35 const float kClippedRatioThreshold = 0.1f; | 33 const float kClippedRatioThreshold = 0.1f; |
36 // Time in frames to wait after a clipping event before checking again. | 34 // Time in frames to wait after a clipping event before checking again. |
37 const int kClippedWaitFrames = 300; | 35 const int kClippedWaitFrames = 300; |
38 | 36 |
39 // Amount of error we tolerate in the microphone level (presumably due to OS | 37 // Amount of error we tolerate in the microphone level (presumably due to OS |
40 // quantization) before we assume the user has manually adjusted the microphone. | 38 // quantization) before we assume the user has manually adjusted the microphone. |
41 const int kLevelQuantizationSlack = 25; | 39 const int kLevelQuantizationSlack = 25; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 } | 106 } |
109 ~DebugFile() { | 107 ~DebugFile() { |
110 } | 108 } |
111 void Write(const int16_t* data, size_t length_samples) { | 109 void Write(const int16_t* data, size_t length_samples) { |
112 } | 110 } |
113 #endif // WEBRTC_AGC_DEBUG_DUMP | 111 #endif // WEBRTC_AGC_DEBUG_DUMP |
114 }; | 112 }; |
115 | 113 |
116 AgcManagerDirect::AgcManagerDirect(GainControl* gctrl, | 114 AgcManagerDirect::AgcManagerDirect(GainControl* gctrl, |
117 VolumeCallbacks* volume_callbacks, | 115 VolumeCallbacks* volume_callbacks, |
118 int startup_min_level) | 116 int startup_min_level, |
| 117 int clipped_level_min) |
119 : agc_(new Agc()), | 118 : agc_(new Agc()), |
120 gctrl_(gctrl), | 119 gctrl_(gctrl), |
121 volume_callbacks_(volume_callbacks), | 120 volume_callbacks_(volume_callbacks), |
122 frames_since_clipped_(kClippedWaitFrames), | 121 frames_since_clipped_(kClippedWaitFrames), |
123 level_(0), | 122 level_(0), |
124 max_level_(kMaxMicLevel), | 123 max_level_(kMaxMicLevel), |
125 max_compression_gain_(kMaxCompressionGain), | 124 max_compression_gain_(kMaxCompressionGain), |
126 target_compression_(kDefaultCompressionGain), | 125 target_compression_(kDefaultCompressionGain), |
127 compression_(target_compression_), | 126 compression_(target_compression_), |
128 compression_accumulator_(compression_), | 127 compression_accumulator_(compression_), |
129 capture_muted_(false), | 128 capture_muted_(false), |
130 check_volume_on_next_process_(true), // Check at startup. | 129 check_volume_on_next_process_(true), // Check at startup. |
131 startup_(true), | 130 startup_(true), |
132 startup_min_level_(ClampLevel(startup_min_level)), | 131 startup_min_level_(ClampLevel(startup_min_level)), |
| 132 clipped_level_min_(clipped_level_min), |
133 file_preproc_(new DebugFile("agc_preproc.pcm")), | 133 file_preproc_(new DebugFile("agc_preproc.pcm")), |
134 file_postproc_(new DebugFile("agc_postproc.pcm")) { | 134 file_postproc_(new DebugFile("agc_postproc.pcm")) {} |
135 } | |
136 | 135 |
137 AgcManagerDirect::AgcManagerDirect(Agc* agc, | 136 AgcManagerDirect::AgcManagerDirect(Agc* agc, |
138 GainControl* gctrl, | 137 GainControl* gctrl, |
139 VolumeCallbacks* volume_callbacks, | 138 VolumeCallbacks* volume_callbacks, |
140 int startup_min_level) | 139 int startup_min_level, |
| 140 int clipped_level_min) |
141 : agc_(agc), | 141 : agc_(agc), |
142 gctrl_(gctrl), | 142 gctrl_(gctrl), |
143 volume_callbacks_(volume_callbacks), | 143 volume_callbacks_(volume_callbacks), |
144 frames_since_clipped_(kClippedWaitFrames), | 144 frames_since_clipped_(kClippedWaitFrames), |
145 level_(0), | 145 level_(0), |
146 max_level_(kMaxMicLevel), | 146 max_level_(kMaxMicLevel), |
147 max_compression_gain_(kMaxCompressionGain), | 147 max_compression_gain_(kMaxCompressionGain), |
148 target_compression_(kDefaultCompressionGain), | 148 target_compression_(kDefaultCompressionGain), |
149 compression_(target_compression_), | 149 compression_(target_compression_), |
150 compression_accumulator_(compression_), | 150 compression_accumulator_(compression_), |
151 capture_muted_(false), | 151 capture_muted_(false), |
152 check_volume_on_next_process_(true), // Check at startup. | 152 check_volume_on_next_process_(true), // Check at startup. |
153 startup_(true), | 153 startup_(true), |
154 startup_min_level_(ClampLevel(startup_min_level)), | 154 startup_min_level_(ClampLevel(startup_min_level)), |
| 155 clipped_level_min_(clipped_level_min), |
155 file_preproc_(new DebugFile("agc_preproc.pcm")), | 156 file_preproc_(new DebugFile("agc_preproc.pcm")), |
156 file_postproc_(new DebugFile("agc_postproc.pcm")) { | 157 file_postproc_(new DebugFile("agc_postproc.pcm")) {} |
157 } | |
158 | 158 |
159 AgcManagerDirect::~AgcManagerDirect() {} | 159 AgcManagerDirect::~AgcManagerDirect() {} |
160 | 160 |
161 int AgcManagerDirect::Initialize() { | 161 int AgcManagerDirect::Initialize() { |
162 max_level_ = kMaxMicLevel; | 162 max_level_ = kMaxMicLevel; |
163 max_compression_gain_ = kMaxCompressionGain; | 163 max_compression_gain_ = kMaxCompressionGain; |
164 target_compression_ = kDefaultCompressionGain; | 164 target_compression_ = kDefaultCompressionGain; |
165 compression_ = target_compression_; | 165 compression_ = target_compression_; |
166 compression_accumulator_ = compression_; | 166 compression_accumulator_ = compression_; |
167 capture_muted_ = false; | 167 capture_muted_ = false; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 // and enforce a new maximum level, dropped the same amount from the current | 211 // and enforce a new maximum level, dropped the same amount from the current |
212 // maximum. This harsh treatment is an effort to avoid repeated clipped echo | 212 // maximum. This harsh treatment is an effort to avoid repeated clipped echo |
213 // events. As compensation for this restriction, the maximum compression | 213 // events. As compensation for this restriction, the maximum compression |
214 // gain is increased, through SetMaxLevel(). | 214 // gain is increased, through SetMaxLevel(). |
215 float clipped_ratio = agc_->AnalyzePreproc(audio, length); | 215 float clipped_ratio = agc_->AnalyzePreproc(audio, length); |
216 if (clipped_ratio > kClippedRatioThreshold) { | 216 if (clipped_ratio > kClippedRatioThreshold) { |
217 LOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" | 217 LOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" |
218 << clipped_ratio; | 218 << clipped_ratio; |
219 // Always decrease the maximum level, even if the current level is below | 219 // Always decrease the maximum level, even if the current level is below |
220 // threshold. | 220 // threshold. |
221 SetMaxLevel(std::max(kClippedLevelMin, max_level_ - kClippedLevelStep)); | 221 SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep)); |
222 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", | 222 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", |
223 level_ - kClippedLevelStep >= kClippedLevelMin); | 223 level_ - kClippedLevelStep >= clipped_level_min_); |
224 if (level_ > kClippedLevelMin) { | 224 if (level_ > clipped_level_min_) { |
225 // Don't try to adjust the level if we're already below the limit. As | 225 // Don't try to adjust the level if we're already below the limit. As |
226 // a consequence, if the user has brought the level above the limit, we | 226 // a consequence, if the user has brought the level above the limit, we |
227 // will still not react until the postproc updates the level. | 227 // will still not react until the postproc updates the level. |
228 SetLevel(std::max(kClippedLevelMin, level_ - kClippedLevelStep)); | 228 SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep)); |
229 // Reset the AGC since the level has changed. | 229 // Reset the AGC since the level has changed. |
230 agc_->Reset(); | 230 agc_->Reset(); |
231 } | 231 } |
232 frames_since_clipped_ = 0; | 232 frames_since_clipped_ = 0; |
233 } | 233 } |
234 } | 234 } |
235 | 235 |
236 void AgcManagerDirect::Process(const int16_t* audio, | 236 void AgcManagerDirect::Process(const int16_t* audio, |
237 size_t length, | 237 size_t length, |
238 int sample_rate_hz) { | 238 int sample_rate_hz) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 } | 294 } |
295 | 295 |
296 volume_callbacks_->SetMicVolume(new_level); | 296 volume_callbacks_->SetMicVolume(new_level); |
297 LOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", " | 297 LOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", " |
298 << "level_=" << level_ << ", " | 298 << "level_=" << level_ << ", " |
299 << "new_level=" << new_level; | 299 << "new_level=" << new_level; |
300 level_ = new_level; | 300 level_ = new_level; |
301 } | 301 } |
302 | 302 |
303 void AgcManagerDirect::SetMaxLevel(int level) { | 303 void AgcManagerDirect::SetMaxLevel(int level) { |
304 RTC_DCHECK_GE(level, kClippedLevelMin); | 304 RTC_DCHECK_GE(level, clipped_level_min_); |
305 max_level_ = level; | 305 max_level_ = level; |
306 // Scale the |kSurplusCompressionGain| linearly across the restricted | 306 // Scale the |kSurplusCompressionGain| linearly across the restricted |
307 // level range. | 307 // level range. |
308 max_compression_gain_ = kMaxCompressionGain + std::floor( | 308 max_compression_gain_ = |
309 (1.f * kMaxMicLevel - max_level_) / (kMaxMicLevel - kClippedLevelMin) * | 309 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) / |
310 kSurplusCompressionGain + 0.5f); | 310 (kMaxMicLevel - clipped_level_min_) * |
| 311 kSurplusCompressionGain + |
| 312 0.5f); |
311 LOG(LS_INFO) << "[agc] max_level_=" << max_level_ | 313 LOG(LS_INFO) << "[agc] max_level_=" << max_level_ |
312 << ", max_compression_gain_=" << max_compression_gain_; | 314 << ", max_compression_gain_=" << max_compression_gain_; |
313 } | 315 } |
314 | 316 |
315 void AgcManagerDirect::SetCaptureMuted(bool muted) { | 317 void AgcManagerDirect::SetCaptureMuted(bool muted) { |
316 if (capture_muted_ == muted) { | 318 if (capture_muted_ == muted) { |
317 return; | 319 return; |
318 } | 320 } |
319 capture_muted_ = muted; | 321 capture_muted_ = muted; |
320 | 322 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 compression_ = new_compression; | 445 compression_ = new_compression; |
444 compression_accumulator_ = new_compression; | 446 compression_accumulator_ = new_compression; |
445 if (gctrl_->set_compression_gain_db(compression_) != 0) { | 447 if (gctrl_->set_compression_gain_db(compression_) != 0) { |
446 LOG(LS_ERROR) << "set_compression_gain_db(" << compression_ | 448 LOG(LS_ERROR) << "set_compression_gain_db(" << compression_ |
447 << ") failed."; | 449 << ") failed."; |
448 } | 450 } |
449 } | 451 } |
450 } | 452 } |
451 | 453 |
452 } // namespace webrtc | 454 } // namespace webrtc |
OLD | NEW |