Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 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/gain_control_impl.h" | 11 #include "webrtc/modules/audio_processing/gain_control_impl.h" |
| 12 | 12 |
| 13 #include <assert.h> | 13 #include <assert.h> |
| 14 | 14 |
| 15 #include "webrtc/base/criticalsection.h" | |
| 15 #include "webrtc/modules/audio_processing/audio_buffer.h" | 16 #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/agc/legacy/gain_control.h" |
| 17 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
| 18 | 18 |
| 19 namespace webrtc { | 19 namespace webrtc { |
| 20 | 20 |
| 21 typedef void Handle; | 21 typedef void Handle; |
| 22 | 22 |
| 23 namespace { | 23 namespace { |
| 24 int16_t MapSetting(GainControl::Mode mode) { | 24 int16_t MapSetting(GainControl::Mode mode) { |
| 25 switch (mode) { | 25 switch (mode) { |
| 26 case GainControl::kAdaptiveAnalog: | 26 case GainControl::kAdaptiveAnalog: |
| 27 return kAgcModeAdaptiveAnalog; | 27 return kAgcModeAdaptiveAnalog; |
| 28 case GainControl::kAdaptiveDigital: | 28 case GainControl::kAdaptiveDigital: |
| 29 return kAgcModeAdaptiveDigital; | 29 return kAgcModeAdaptiveDigital; |
| 30 case GainControl::kFixedDigital: | 30 case GainControl::kFixedDigital: |
| 31 return kAgcModeFixedDigital; | 31 return kAgcModeFixedDigital; |
| 32 } | 32 } |
| 33 assert(false); | 33 assert(false); |
| 34 return -1; | 34 return -1; |
| 35 } | 35 } |
| 36 } // namespace | 36 } // namespace |
| 37 | 37 |
| 38 const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame1; | 38 const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame1; |
| 39 const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame2; | 39 const size_t GainControlImpl::kAllowedValuesOfSamplesPerFrame2; |
| 40 | 40 |
| 41 GainControlImpl::GainControlImpl(const AudioProcessing* apm, | 41 GainControlImpl::GainControlImpl(const AudioProcessing* apm, |
| 42 CriticalSectionWrapper* crit, | 42 rtc::CriticalSection* crit_render, |
| 43 rtc::CriticalSection* crit_capture, | |
| 43 rtc::ThreadChecker* render_thread_checker, | 44 rtc::ThreadChecker* render_thread_checker, |
| 44 rtc::ThreadChecker* capture_thread_checker) | 45 rtc::ThreadChecker* capture_thread_checker) |
| 45 : ProcessingComponent(), | 46 : ProcessingComponent(), |
| 46 apm_(apm), | 47 apm_(apm), |
| 47 crit_(crit), | 48 crit_render_(crit_render), |
| 49 crit_capture_(crit_capture), | |
| 48 render_thread_checker_(render_thread_checker), | 50 render_thread_checker_(render_thread_checker), |
| 49 capture_thread_checker_(capture_thread_checker), | 51 capture_thread_checker_(capture_thread_checker), |
| 50 mode_(kAdaptiveAnalog), | 52 mode_(kAdaptiveAnalog), |
| 51 minimum_capture_level_(0), | 53 minimum_capture_level_(0), |
| 52 maximum_capture_level_(255), | 54 maximum_capture_level_(255), |
| 53 limiter_enabled_(true), | 55 limiter_enabled_(true), |
| 54 target_level_dbfs_(3), | 56 target_level_dbfs_(3), |
| 55 compression_gain_db_(9), | 57 compression_gain_db_(9), |
| 56 analog_capture_level_(0), | 58 analog_capture_level_(0), |
| 57 was_analog_level_set_(false), | 59 was_analog_level_set_(false), |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 78 | 80 |
| 79 if (err != apm_->kNoError) | 81 if (err != apm_->kNoError) |
| 80 return GetHandleError(my_handle); | 82 return GetHandleError(my_handle); |
| 81 | 83 |
| 82 // Buffer the samples in the render queue. | 84 // Buffer the samples in the render queue. |
| 83 render_queue_buffer_.insert( | 85 render_queue_buffer_.insert( |
| 84 render_queue_buffer_.end(), audio->mixed_low_pass_data(), | 86 render_queue_buffer_.end(), audio->mixed_low_pass_data(), |
| 85 (audio->mixed_low_pass_data() + audio->num_frames_per_band())); | 87 (audio->mixed_low_pass_data() + audio->num_frames_per_band())); |
| 86 } | 88 } |
| 87 | 89 |
| 88 // Check of success is temporarily disabled as it breaks a unit test. | 90 // Insert the samples into the queue. |
| 89 // TODO(peah): Will be fixed in the next CL. | 91 bool success = render_signal_queue_->Insert(&render_queue_buffer_); |
|
hlundin-webrtc
2015/11/05 16:11:22
if (!render_signal_queue_->Insert(&render_queue_bu
peah-webrtc
2015/11/06 09:54:32
Done.
| |
| 90 (void)render_signal_queue_->Insert(&render_queue_buffer_); | 92 if (!success) { |
| 93 // The data queue is full and needs to be emptied. | |
| 94 { | |
| 95 rtc::CritScope cs_capture(crit_capture_); | |
| 96 ReadQueuedRenderData(); | |
| 97 } | |
| 98 | |
| 99 // Retry the insert (should always work). | |
| 100 RTC_DCHECK_EQ(render_signal_queue_->Insert(&render_queue_buffer_), true); | |
| 101 } | |
| 91 | 102 |
| 92 return apm_->kNoError; | 103 return apm_->kNoError; |
| 93 } | 104 } |
| 94 | 105 |
| 95 // Read chunks of data that were received and queued on the render side from | 106 // Read chunks of data that were received and queued on the render side from |
| 96 // a queue. All the data chunks are buffered into the farend signal of the AGC. | 107 // a queue. All the data chunks are buffered into the farend signal of the AGC. |
| 97 void GainControlImpl::ReadQueuedRenderData() { | 108 void GainControlImpl::ReadQueuedRenderData() { |
| 98 if (!is_component_enabled()) { | 109 if (!is_component_enabled()) { |
| 99 return; | 110 return; |
| 100 } | 111 } |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 | 229 |
| 219 // TODO(ajm): ensure this is called under kAdaptiveAnalog. | 230 // TODO(ajm): ensure this is called under kAdaptiveAnalog. |
| 220 int GainControlImpl::set_stream_analog_level(int level) { | 231 int GainControlImpl::set_stream_analog_level(int level) { |
| 221 RTC_DCHECK(capture_thread_checker_->CalledOnValidThread()); | 232 RTC_DCHECK(capture_thread_checker_->CalledOnValidThread()); |
| 222 // TODO(peah): Verify that this is really needed to do the reading. | 233 // TODO(peah): Verify that this is really needed to do the reading. |
| 223 // here as well as in ProcessStream. It works since these functions | 234 // here as well as in ProcessStream. It works since these functions |
| 224 // are called from the same thread, but it is not nice to do it in two | 235 // are called from the same thread, but it is not nice to do it in two |
| 225 // places if not needed. | 236 // places if not needed. |
| 226 ReadQueuedRenderData(); | 237 ReadQueuedRenderData(); |
| 227 | 238 |
| 228 CriticalSectionScoped crit_scoped(crit_); | 239 rtc::CritScope cs(crit_capture_); |
| 229 was_analog_level_set_ = true; | 240 was_analog_level_set_ = true; |
| 230 if (level < minimum_capture_level_ || level > maximum_capture_level_) { | 241 if (level < minimum_capture_level_ || level > maximum_capture_level_) { |
| 231 return apm_->kBadParameterError; | 242 return apm_->kBadParameterError; |
| 232 } | 243 } |
| 233 analog_capture_level_ = level; | 244 analog_capture_level_ = level; |
| 234 | 245 |
| 235 return apm_->kNoError; | 246 return apm_->kNoError; |
| 236 } | 247 } |
| 237 | 248 |
| 238 int GainControlImpl::stream_analog_level() { | 249 int GainControlImpl::stream_analog_level() { |
| 250 rtc::CritScope cs(crit_capture_); | |
| 239 RTC_DCHECK(capture_thread_checker_->CalledOnValidThread()); | 251 RTC_DCHECK(capture_thread_checker_->CalledOnValidThread()); |
| 240 // TODO(ajm): enable this assertion? | 252 // TODO(ajm): enable this assertion? |
| 241 //assert(mode_ == kAdaptiveAnalog); | 253 //assert(mode_ == kAdaptiveAnalog); |
| 242 | 254 |
| 243 return analog_capture_level_; | 255 return analog_capture_level_; |
| 244 } | 256 } |
| 245 | 257 |
| 246 int GainControlImpl::Enable(bool enable) { | 258 int GainControlImpl::Enable(bool enable) { |
| 247 CriticalSectionScoped crit_scoped(crit_); | 259 rtc::CritScope cs_render(crit_render_); |
| 260 rtc::CritScope cs(crit_capture_); | |
| 248 return EnableComponent(enable); | 261 return EnableComponent(enable); |
| 249 } | 262 } |
| 250 | 263 |
| 251 bool GainControlImpl::is_enabled() const { | 264 bool GainControlImpl::is_enabled() const { |
| 265 rtc::CritScope cs(crit_capture_); | |
| 252 return is_component_enabled(); | 266 return is_component_enabled(); |
| 253 } | 267 } |
| 254 | 268 |
| 255 int GainControlImpl::set_mode(Mode mode) { | 269 int GainControlImpl::set_mode(Mode mode) { |
| 256 CriticalSectionScoped crit_scoped(crit_); | 270 rtc::CritScope cs_render(crit_render_); |
| 271 rtc::CritScope cs_capture(crit_capture_); | |
| 257 if (MapSetting(mode) == -1) { | 272 if (MapSetting(mode) == -1) { |
| 258 return apm_->kBadParameterError; | 273 return apm_->kBadParameterError; |
| 259 } | 274 } |
| 260 | 275 |
| 261 mode_ = mode; | 276 mode_ = mode; |
| 262 return Initialize(); | 277 return Initialize(); |
| 263 } | 278 } |
| 264 | 279 |
| 265 GainControl::Mode GainControlImpl::mode() const { | 280 GainControl::Mode GainControlImpl::mode() const { |
| 281 rtc::CritScope cs(crit_capture_); | |
| 266 return mode_; | 282 return mode_; |
| 267 } | 283 } |
| 268 | 284 |
| 269 int GainControlImpl::set_analog_level_limits(int minimum, | 285 int GainControlImpl::set_analog_level_limits(int minimum, |
| 270 int maximum) { | 286 int maximum) { |
| 271 CriticalSectionScoped crit_scoped(crit_); | 287 rtc::CritScope cs(crit_capture_); |
| 272 if (minimum < 0) { | 288 if (minimum < 0) { |
| 273 return apm_->kBadParameterError; | 289 return apm_->kBadParameterError; |
| 274 } | 290 } |
| 275 | 291 |
| 276 if (maximum > 65535) { | 292 if (maximum > 65535) { |
| 277 return apm_->kBadParameterError; | 293 return apm_->kBadParameterError; |
| 278 } | 294 } |
| 279 | 295 |
| 280 if (maximum < minimum) { | 296 if (maximum < minimum) { |
| 281 return apm_->kBadParameterError; | 297 return apm_->kBadParameterError; |
| 282 } | 298 } |
| 283 | 299 |
| 284 minimum_capture_level_ = minimum; | 300 minimum_capture_level_ = minimum; |
| 285 maximum_capture_level_ = maximum; | 301 maximum_capture_level_ = maximum; |
| 286 | 302 |
| 287 return Initialize(); | 303 return Initialize(); |
| 288 } | 304 } |
| 289 | 305 |
| 290 int GainControlImpl::analog_level_minimum() const { | 306 int GainControlImpl::analog_level_minimum() const { |
| 307 rtc::CritScope cs(crit_capture_); | |
| 291 return minimum_capture_level_; | 308 return minimum_capture_level_; |
| 292 } | 309 } |
| 293 | 310 |
| 294 int GainControlImpl::analog_level_maximum() const { | 311 int GainControlImpl::analog_level_maximum() const { |
| 312 rtc::CritScope cs(crit_capture_); | |
| 295 return maximum_capture_level_; | 313 return maximum_capture_level_; |
| 296 } | 314 } |
| 297 | 315 |
| 298 bool GainControlImpl::stream_is_saturated() const { | 316 bool GainControlImpl::stream_is_saturated() const { |
| 317 rtc::CritScope cs(crit_capture_); | |
| 299 return stream_is_saturated_; | 318 return stream_is_saturated_; |
| 300 } | 319 } |
| 301 | 320 |
| 302 int GainControlImpl::set_target_level_dbfs(int level) { | 321 int GainControlImpl::set_target_level_dbfs(int level) { |
| 303 CriticalSectionScoped crit_scoped(crit_); | 322 rtc::CritScope cs(crit_capture_); |
| 304 if (level > 31 || level < 0) { | 323 if (level > 31 || level < 0) { |
| 305 return apm_->kBadParameterError; | 324 return apm_->kBadParameterError; |
| 306 } | 325 } |
| 307 | 326 |
| 308 target_level_dbfs_ = level; | 327 target_level_dbfs_ = level; |
| 309 return Configure(); | 328 return Configure(); |
| 310 } | 329 } |
| 311 | 330 |
| 312 int GainControlImpl::target_level_dbfs() const { | 331 int GainControlImpl::target_level_dbfs() const { |
| 332 rtc::CritScope cs(crit_capture_); | |
| 313 return target_level_dbfs_; | 333 return target_level_dbfs_; |
| 314 } | 334 } |
| 315 | 335 |
| 316 int GainControlImpl::set_compression_gain_db(int gain) { | 336 int GainControlImpl::set_compression_gain_db(int gain) { |
| 317 CriticalSectionScoped crit_scoped(crit_); | 337 rtc::CritScope cs(crit_capture_); |
| 318 if (gain < 0 || gain > 90) { | 338 if (gain < 0 || gain > 90) { |
| 319 return apm_->kBadParameterError; | 339 return apm_->kBadParameterError; |
| 320 } | 340 } |
| 321 | 341 |
| 322 compression_gain_db_ = gain; | 342 compression_gain_db_ = gain; |
| 323 return Configure(); | 343 return Configure(); |
| 324 } | 344 } |
| 325 | 345 |
| 326 int GainControlImpl::compression_gain_db() const { | 346 int GainControlImpl::compression_gain_db() const { |
| 347 rtc::CritScope cs(crit_capture_); | |
| 327 return compression_gain_db_; | 348 return compression_gain_db_; |
| 328 } | 349 } |
| 329 | 350 |
| 330 int GainControlImpl::enable_limiter(bool enable) { | 351 int GainControlImpl::enable_limiter(bool enable) { |
| 331 CriticalSectionScoped crit_scoped(crit_); | 352 rtc::CritScope cs(crit_capture_); |
| 332 limiter_enabled_ = enable; | 353 limiter_enabled_ = enable; |
| 333 return Configure(); | 354 return Configure(); |
| 334 } | 355 } |
| 335 | 356 |
| 336 bool GainControlImpl::is_limiter_enabled() const { | 357 bool GainControlImpl::is_limiter_enabled() const { |
| 358 rtc::CritScope cs(crit_capture_); | |
| 337 return limiter_enabled_; | 359 return limiter_enabled_; |
| 338 } | 360 } |
| 339 | 361 |
| 340 int GainControlImpl::Initialize() { | 362 int GainControlImpl::Initialize() { |
| 341 int err = ProcessingComponent::Initialize(); | 363 int err = ProcessingComponent::Initialize(); |
| 342 if (err != apm_->kNoError || !is_component_enabled()) { | 364 if (err != apm_->kNoError || !is_component_enabled()) { |
| 343 return err; | 365 return err; |
| 344 } | 366 } |
| 345 | 367 |
| 346 AllocateRenderQueue(); | 368 AllocateRenderQueue(); |
| 347 | 369 |
| 348 capture_levels_.assign(num_handles(), analog_capture_level_); | 370 capture_levels_.assign(num_handles(), analog_capture_level_); |
| 349 return apm_->kNoError; | 371 return apm_->kNoError; |
| 350 } | 372 } |
| 351 | 373 |
| 352 void GainControlImpl::AllocateRenderQueue() { | 374 void GainControlImpl::AllocateRenderQueue() { |
| 375 // Only called from within APM, hence no locking is needed. | |
| 353 const size_t max_frame_size = std::max(kAllowedValuesOfSamplesPerFrame1, | 376 const size_t max_frame_size = std::max(kAllowedValuesOfSamplesPerFrame1, |
| 354 kAllowedValuesOfSamplesPerFrame2); | 377 kAllowedValuesOfSamplesPerFrame2); |
| 355 | 378 |
| 356 const size_t new_render_queue_element_max_size = | 379 const size_t new_render_queue_element_max_size = |
| 357 std::max(1UL, (max_frame_size * num_handles())); | 380 std::max(1UL, (max_frame_size * num_handles())); |
| 358 | 381 |
| 359 if (new_render_queue_element_max_size > render_queue_element_max_size_) { | 382 if (new_render_queue_element_max_size > render_queue_element_max_size_) { |
| 360 std::vector<int16_t> template_queue_element(render_queue_element_max_size_); | 383 std::vector<int16_t> template_queue_element(render_queue_element_max_size_); |
| 361 | 384 |
| 362 render_signal_queue_.reset( | 385 render_signal_queue_.reset( |
| 363 new SwapQueue<std::vector<int16_t>, AgcRenderQueueItemVerifier>( | 386 new SwapQueue<std::vector<int16_t>, AgcRenderQueueItemVerifier>( |
| 364 kMaxNumFramesToBuffer, | 387 kMaxNumFramesToBuffer, |
| 365 AgcRenderQueueItemVerifier(render_queue_element_max_size_), | 388 AgcRenderQueueItemVerifier(render_queue_element_max_size_), |
| 366 template_queue_element)); | 389 template_queue_element)); |
| 367 } else { | 390 } else { |
| 368 render_signal_queue_->Clear(); | 391 render_signal_queue_->Clear(); |
| 369 } | 392 } |
| 370 | 393 |
| 371 render_queue_buffer_.resize(new_render_queue_element_max_size); | 394 render_queue_buffer_.resize(new_render_queue_element_max_size); |
| 372 capture_queue_buffer_.resize(new_render_queue_element_max_size); | 395 capture_queue_buffer_.resize(new_render_queue_element_max_size); |
| 373 } | 396 } |
| 374 | 397 |
| 375 void* GainControlImpl::CreateHandle() const { | 398 void* GainControlImpl::CreateHandle() const { |
| 399 // Only called from within APM, hence no locking is needed. | |
| 376 return WebRtcAgc_Create(); | 400 return WebRtcAgc_Create(); |
| 377 } | 401 } |
| 378 | 402 |
| 379 void GainControlImpl::DestroyHandle(void* handle) const { | 403 void GainControlImpl::DestroyHandle(void* handle) const { |
| 404 // Only called from within APM, hence no locking is needed. | |
| 380 WebRtcAgc_Free(static_cast<Handle*>(handle)); | 405 WebRtcAgc_Free(static_cast<Handle*>(handle)); |
| 381 } | 406 } |
| 382 | 407 |
| 383 int GainControlImpl::InitializeHandle(void* handle) const { | 408 int GainControlImpl::InitializeHandle(void* handle) const { |
| 409 // Only called from within APM, hence no locking is needed. | |
| 384 return WebRtcAgc_Init(static_cast<Handle*>(handle), | 410 return WebRtcAgc_Init(static_cast<Handle*>(handle), |
| 385 minimum_capture_level_, | 411 minimum_capture_level_, |
| 386 maximum_capture_level_, | 412 maximum_capture_level_, |
| 387 MapSetting(mode_), | 413 MapSetting(mode_), |
| 388 apm_->proc_sample_rate_hz()); | 414 apm_->proc_sample_rate_hz()); |
| 389 } | 415 } |
| 390 | 416 |
| 391 int GainControlImpl::ConfigureHandle(void* handle) const { | 417 int GainControlImpl::ConfigureHandle(void* handle) const { |
| 418 // Only called from within APM, hence no locking is needed. | |
| 392 WebRtcAgcConfig config; | 419 WebRtcAgcConfig config; |
| 393 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we | 420 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we |
| 394 // change the interface. | 421 // change the interface. |
| 395 //assert(target_level_dbfs_ <= 0); | 422 //assert(target_level_dbfs_ <= 0); |
| 396 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_); | 423 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_); |
| 397 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_); | 424 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_); |
| 398 config.compressionGaindB = | 425 config.compressionGaindB = |
| 399 static_cast<int16_t>(compression_gain_db_); | 426 static_cast<int16_t>(compression_gain_db_); |
| 400 config.limiterEnable = limiter_enabled_; | 427 config.limiterEnable = limiter_enabled_; |
| 401 | 428 |
| 402 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config); | 429 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config); |
| 403 } | 430 } |
| 404 | 431 |
| 405 int GainControlImpl::num_handles_required() const { | 432 int GainControlImpl::num_handles_required() const { |
| 433 // Only called from within APM, hence no locking is needed. | |
| 406 return apm_->num_output_channels(); | 434 return apm_->num_output_channels(); |
| 407 } | 435 } |
| 408 | 436 |
| 409 int GainControlImpl::GetHandleError(void* handle) const { | 437 int GainControlImpl::GetHandleError(void* handle) const { |
| 438 // Only called from within APM, hence no locking is needed. | |
| 410 // The AGC has no get_error() function. | 439 // The AGC has no get_error() function. |
| 411 // (Despite listing errors in its interface...) | 440 // (Despite listing errors in its interface...) |
| 412 assert(handle != NULL); | 441 assert(handle != NULL); |
| 413 return apm_->kUnspecifiedError; | 442 return apm_->kUnspecifiedError; |
| 414 } | 443 } |
| 415 } // namespace webrtc | 444 } // namespace webrtc |
| OLD | NEW |