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" | |
24 #include "webrtc/system_wrappers/include/metrics.h" | 23 #include "webrtc/system_wrappers/include/metrics.h" |
25 | 24 |
26 namespace webrtc { | 25 namespace webrtc { |
27 | 26 |
28 namespace { | 27 namespace { |
29 | 28 |
30 // Amount the microphone level is lowered with every clipping event. | 29 // Amount the microphone level is lowered with every clipping event. |
31 const int kClippedLevelStep = 15; | 30 const int kClippedLevelStep = 15; |
32 // Proportion of clipped samples required to declare a clipping event. | 31 // Proportion of clipped samples required to declare a clipping event. |
33 const float kClippedRatioThreshold = 0.1f; | 32 const float kClippedRatioThreshold = 0.1f; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 max_compression_gain_ = kMaxCompressionGain; | 162 max_compression_gain_ = kMaxCompressionGain; |
164 target_compression_ = kDefaultCompressionGain; | 163 target_compression_ = kDefaultCompressionGain; |
165 compression_ = target_compression_; | 164 compression_ = target_compression_; |
166 compression_accumulator_ = compression_; | 165 compression_accumulator_ = compression_; |
167 capture_muted_ = false; | 166 capture_muted_ = false; |
168 check_volume_on_next_process_ = true; | 167 check_volume_on_next_process_ = true; |
169 // TODO(bjornv): Investigate if we need to reset |startup_| as well. For | 168 // TODO(bjornv): Investigate if we need to reset |startup_| as well. For |
170 // example, what happens when we change devices. | 169 // example, what happens when we change devices. |
171 | 170 |
172 if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) { | 171 if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) { |
173 LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed."; | |
174 return -1; | 172 return -1; |
175 } | 173 } |
176 if (gctrl_->set_target_level_dbfs(2) != 0) { | 174 if (gctrl_->set_target_level_dbfs(2) != 0) { |
177 LOG(LS_ERROR) << "set_target_level_dbfs(2) failed."; | |
178 return -1; | 175 return -1; |
179 } | 176 } |
180 if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) { | 177 if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) { |
181 LOG(LS_ERROR) << "set_compression_gain_db(kDefaultCompressionGain) failed."; | |
182 return -1; | 178 return -1; |
183 } | 179 } |
184 if (gctrl_->enable_limiter(true) != 0) { | 180 if (gctrl_->enable_limiter(true) != 0) { |
185 LOG(LS_ERROR) << "enable_limiter(true) failed."; | |
186 return -1; | 181 return -1; |
187 } | 182 } |
188 return 0; | 183 return 0; |
189 } | 184 } |
190 | 185 |
191 void AgcManagerDirect::AnalyzePreProcess(int16_t* audio, | 186 void AgcManagerDirect::AnalyzePreProcess(int16_t* audio, |
192 int num_channels, | 187 int num_channels, |
193 size_t samples_per_channel) { | 188 size_t samples_per_channel) { |
194 size_t length = num_channels * samples_per_channel; | 189 size_t length = num_channels * samples_per_channel; |
195 if (capture_muted_) { | 190 if (capture_muted_) { |
(...skipping 11 matching lines...) Expand all Loading... |
207 // under clipping distortion. We do this in the preprocessing phase in order | 202 // under clipping distortion. We do this in the preprocessing phase in order |
208 // to catch clipped echo as well. | 203 // to catch clipped echo as well. |
209 // | 204 // |
210 // If we find a sufficiently clipped frame, drop the current microphone level | 205 // If we find a sufficiently clipped frame, drop the current microphone level |
211 // and enforce a new maximum level, dropped the same amount from the current | 206 // 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 | 207 // maximum. This harsh treatment is an effort to avoid repeated clipped echo |
213 // events. As compensation for this restriction, the maximum compression | 208 // events. As compensation for this restriction, the maximum compression |
214 // gain is increased, through SetMaxLevel(). | 209 // gain is increased, through SetMaxLevel(). |
215 float clipped_ratio = agc_->AnalyzePreproc(audio, length); | 210 float clipped_ratio = agc_->AnalyzePreproc(audio, length); |
216 if (clipped_ratio > kClippedRatioThreshold) { | 211 if (clipped_ratio > kClippedRatioThreshold) { |
217 LOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio=" | |
218 << clipped_ratio; | |
219 // Always decrease the maximum level, even if the current level is below | 212 // Always decrease the maximum level, even if the current level is below |
220 // threshold. | 213 // threshold. |
221 SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep)); | 214 SetMaxLevel(std::max(clipped_level_min_, max_level_ - kClippedLevelStep)); |
222 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", | 215 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.AgcClippingAdjustmentAllowed", |
223 level_ - kClippedLevelStep >= clipped_level_min_); | 216 level_ - kClippedLevelStep >= clipped_level_min_); |
224 if (level_ > clipped_level_min_) { | 217 if (level_ > clipped_level_min_) { |
225 // Don't try to adjust the level if we're already below the limit. As | 218 // 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 | 219 // a consequence, if the user has brought the level above the limit, we |
227 // will still not react until the postproc updates the level. | 220 // will still not react until the postproc updates the level. |
228 SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep)); | 221 SetLevel(std::max(clipped_level_min_, level_ - kClippedLevelStep)); |
(...skipping 12 matching lines...) Expand all Loading... |
241 } | 234 } |
242 | 235 |
243 if (check_volume_on_next_process_) { | 236 if (check_volume_on_next_process_) { |
244 check_volume_on_next_process_ = false; | 237 check_volume_on_next_process_ = false; |
245 // We have to wait until the first process call to check the volume, | 238 // We have to wait until the first process call to check the volume, |
246 // because Chromium doesn't guarantee it to be valid any earlier. | 239 // because Chromium doesn't guarantee it to be valid any earlier. |
247 CheckVolumeAndReset(); | 240 CheckVolumeAndReset(); |
248 } | 241 } |
249 | 242 |
250 if (agc_->Process(audio, length, sample_rate_hz) != 0) { | 243 if (agc_->Process(audio, length, sample_rate_hz) != 0) { |
251 LOG(LS_ERROR) << "Agc::Process failed"; | |
252 RTC_NOTREACHED(); | 244 RTC_NOTREACHED(); |
253 } | 245 } |
254 | 246 |
255 UpdateGain(); | 247 UpdateGain(); |
256 UpdateCompressor(); | 248 UpdateCompressor(); |
257 | 249 |
258 file_postproc_->Write(audio, length); | 250 file_postproc_->Write(audio, length); |
259 } | 251 } |
260 | 252 |
261 void AgcManagerDirect::SetLevel(int new_level) { | 253 void AgcManagerDirect::SetLevel(int new_level) { |
262 int voe_level = volume_callbacks_->GetMicVolume(); | 254 int voe_level = volume_callbacks_->GetMicVolume(); |
263 if (voe_level < 0) { | 255 if (voe_level < 0) { |
264 return; | 256 return; |
265 } | 257 } |
266 if (voe_level == 0) { | 258 if (voe_level == 0) { |
267 LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action."; | |
268 return; | 259 return; |
269 } | 260 } |
270 if (voe_level > kMaxMicLevel) { | 261 if (voe_level > kMaxMicLevel) { |
271 LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << voe_level; | |
272 return; | 262 return; |
273 } | 263 } |
274 | 264 |
275 if (voe_level > level_ + kLevelQuantizationSlack || | 265 if (voe_level > level_ + kLevelQuantizationSlack || |
276 voe_level < level_ - kLevelQuantizationSlack) { | 266 voe_level < level_ - kLevelQuantizationSlack) { |
277 LOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating " | |
278 << "stored level from " << level_ << " to " << voe_level; | |
279 level_ = voe_level; | 267 level_ = voe_level; |
280 // Always allow the user to increase the volume. | 268 // Always allow the user to increase the volume. |
281 if (level_ > max_level_) { | 269 if (level_ > max_level_) { |
282 SetMaxLevel(level_); | 270 SetMaxLevel(level_); |
283 } | 271 } |
284 // Take no action in this case, since we can't be sure when the volume | 272 // Take no action in this case, since we can't be sure when the volume |
285 // was manually adjusted. The compressor will still provide some of the | 273 // was manually adjusted. The compressor will still provide some of the |
286 // desired gain change. | 274 // desired gain change. |
287 agc_->Reset(); | 275 agc_->Reset(); |
288 return; | 276 return; |
289 } | 277 } |
290 | 278 |
291 new_level = std::min(new_level, max_level_); | 279 new_level = std::min(new_level, max_level_); |
292 if (new_level == level_) { | 280 if (new_level == level_) { |
293 return; | 281 return; |
294 } | 282 } |
295 | 283 |
296 volume_callbacks_->SetMicVolume(new_level); | 284 volume_callbacks_->SetMicVolume(new_level); |
297 LOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", " | |
298 << "level_=" << level_ << ", " | |
299 << "new_level=" << new_level; | |
300 level_ = new_level; | 285 level_ = new_level; |
301 } | 286 } |
302 | 287 |
303 void AgcManagerDirect::SetMaxLevel(int level) { | 288 void AgcManagerDirect::SetMaxLevel(int level) { |
304 RTC_DCHECK_GE(level, clipped_level_min_); | 289 RTC_DCHECK_GE(level, clipped_level_min_); |
305 max_level_ = level; | 290 max_level_ = level; |
306 // Scale the |kSurplusCompressionGain| linearly across the restricted | 291 // Scale the |kSurplusCompressionGain| linearly across the restricted |
307 // level range. | 292 // level range. |
308 max_compression_gain_ = | 293 max_compression_gain_ = |
309 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) / | 294 kMaxCompressionGain + std::floor((1.f * kMaxMicLevel - max_level_) / |
310 (kMaxMicLevel - clipped_level_min_) * | 295 (kMaxMicLevel - clipped_level_min_) * |
311 kSurplusCompressionGain + | 296 kSurplusCompressionGain + |
312 0.5f); | 297 0.5f); |
313 LOG(LS_INFO) << "[agc] max_level_=" << max_level_ | |
314 << ", max_compression_gain_=" << max_compression_gain_; | |
315 } | 298 } |
316 | 299 |
317 void AgcManagerDirect::SetCaptureMuted(bool muted) { | 300 void AgcManagerDirect::SetCaptureMuted(bool muted) { |
318 if (capture_muted_ == muted) { | 301 if (capture_muted_ == muted) { |
319 return; | 302 return; |
320 } | 303 } |
321 capture_muted_ = muted; | 304 capture_muted_ = muted; |
322 | 305 |
323 if (!muted) { | 306 if (!muted) { |
324 // When we unmute, we should reset things to be safe. | 307 // When we unmute, we should reset things to be safe. |
325 check_volume_on_next_process_ = true; | 308 check_volume_on_next_process_ = true; |
326 } | 309 } |
327 } | 310 } |
328 | 311 |
329 float AgcManagerDirect::voice_probability() { | 312 float AgcManagerDirect::voice_probability() { |
330 return agc_->voice_probability(); | 313 return agc_->voice_probability(); |
331 } | 314 } |
332 | 315 |
333 int AgcManagerDirect::CheckVolumeAndReset() { | 316 int AgcManagerDirect::CheckVolumeAndReset() { |
334 int level = volume_callbacks_->GetMicVolume(); | 317 int level = volume_callbacks_->GetMicVolume(); |
335 if (level < 0) { | 318 if (level < 0) { |
336 return -1; | 319 return -1; |
337 } | 320 } |
338 // Reasons for taking action at startup: | 321 // Reasons for taking action at startup: |
339 // 1) A person starting a call is expected to be heard. | 322 // 1) A person starting a call is expected to be heard. |
340 // 2) Independent of interpretation of |level| == 0 we should raise it so the | 323 // 2) Independent of interpretation of |level| == 0 we should raise it so the |
341 // AGC can do its job properly. | 324 // AGC can do its job properly. |
342 if (level == 0 && !startup_) { | 325 if (level == 0 && !startup_) { |
343 LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action."; | |
344 return 0; | 326 return 0; |
345 } | 327 } |
346 if (level > kMaxMicLevel) { | 328 if (level > kMaxMicLevel) { |
347 LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << level; | |
348 return -1; | 329 return -1; |
349 } | 330 } |
350 LOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level; | |
351 | 331 |
352 int minLevel = startup_ ? startup_min_level_ : kMinMicLevel; | 332 int minLevel = startup_ ? startup_min_level_ : kMinMicLevel; |
353 if (level < minLevel) { | 333 if (level < minLevel) { |
354 level = minLevel; | 334 level = minLevel; |
355 LOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level; | |
356 volume_callbacks_->SetMicVolume(level); | 335 volume_callbacks_->SetMicVolume(level); |
357 } | 336 } |
358 agc_->Reset(); | 337 agc_->Reset(); |
359 level_ = level; | 338 level_ = level; |
360 startup_ = false; | 339 startup_ = false; |
361 return 0; | 340 return 0; |
362 } | 341 } |
363 | 342 |
364 // Requests the RMS error from AGC and distributes the required gain change | 343 // Requests the RMS error from AGC and distributes the required gain change |
365 // between the digital compression stage and volume slider. We use the | 344 // between the digital compression stage and volume slider. We use the |
(...skipping 30 matching lines...) Expand all Loading... |
396 target_compression_ = (raw_compression - target_compression_) / 2 | 375 target_compression_ = (raw_compression - target_compression_) / 2 |
397 + target_compression_; | 376 + target_compression_; |
398 } | 377 } |
399 | 378 |
400 // Residual error will be handled by adjusting the volume slider. Use the | 379 // Residual error will be handled by adjusting the volume slider. Use the |
401 // raw rather than deemphasized compression here as we would otherwise | 380 // raw rather than deemphasized compression here as we would otherwise |
402 // shrink the amount of slack the compressor provides. | 381 // shrink the amount of slack the compressor provides. |
403 int residual_gain = rms_error - raw_compression; | 382 int residual_gain = rms_error - raw_compression; |
404 residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange), | 383 residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange), |
405 kMaxResidualGainChange); | 384 kMaxResidualGainChange); |
406 LOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", " | |
407 << "target_compression=" << target_compression_ << ", " | |
408 << "residual_gain=" << residual_gain; | |
409 if (residual_gain == 0) | 385 if (residual_gain == 0) |
410 return; | 386 return; |
411 | 387 |
412 int old_level = level_; | 388 int old_level = level_; |
413 SetLevel(LevelFromGainError(residual_gain, level_)); | 389 SetLevel(LevelFromGainError(residual_gain, level_)); |
414 if (old_level != level_) { | 390 if (old_level != level_) { |
415 // level_ was updated by SetLevel; log the new value. | 391 // level_ was updated by SetLevel; log the new value. |
416 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1, | 392 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1, |
417 kMaxMicLevel, 50); | 393 kMaxMicLevel, 50); |
418 } | 394 } |
(...skipping 20 matching lines...) Expand all Loading... |
439 if (std::fabs(compression_accumulator_ - nearest_neighbor) < | 415 if (std::fabs(compression_accumulator_ - nearest_neighbor) < |
440 kCompressionGainStep / 2) { | 416 kCompressionGainStep / 2) { |
441 new_compression = nearest_neighbor; | 417 new_compression = nearest_neighbor; |
442 } | 418 } |
443 | 419 |
444 // Set the new compression gain. | 420 // Set the new compression gain. |
445 if (new_compression != compression_) { | 421 if (new_compression != compression_) { |
446 compression_ = new_compression; | 422 compression_ = new_compression; |
447 compression_accumulator_ = new_compression; | 423 compression_accumulator_ = new_compression; |
448 if (gctrl_->set_compression_gain_db(compression_) != 0) { | 424 if (gctrl_->set_compression_gain_db(compression_) != 0) { |
449 LOG(LS_ERROR) << "set_compression_gain_db(" << compression_ | |
450 << ") failed."; | |
451 } | 425 } |
452 } | 426 } |
453 } | 427 } |
454 | 428 |
455 } // namespace webrtc | 429 } // namespace webrtc |
OLD | NEW |