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 <assert.h> 14 15 #include "webrtc/modules/audio_processing/audio_buffer.h" 16 #include "webrtc/modules/audio_processing/agc/include/gain_control.h" 17 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 18 19 namespace webrtc { 20 21 typedef void Handle; 22 23 namespace { 24 int16_t MapSetting(GainControl::Mode mode) { 25 switch (mode) { 26 case GainControl::kAdaptiveAnalog: 27 return kAgcModeAdaptiveAnalog; 28 case GainControl::kAdaptiveDigital: 29 return kAgcModeAdaptiveDigital; 30 case GainControl::kFixedDigital: 31 return kAgcModeFixedDigital; 32 } 33 assert(false); 34 return -1; 35 } 36 } // namespace 37 38 GainControlImpl::GainControlImpl(const AudioProcessing* apm, 39 CriticalSectionWrapper* crit) 40 : ProcessingComponent(), 41 apm_(apm), 42 crit_(crit), 43 mode_(kAdaptiveAnalog), 44 minimum_capture_level_(0), 45 maximum_capture_level_(255), 46 limiter_enabled_(true), 47 target_level_dbfs_(3), 48 compression_gain_db_(9), 49 analog_capture_level_(0), 50 was_analog_level_set_(false), 51 stream_is_saturated_(false) {} 52 53 GainControlImpl::~GainControlImpl() {} 54 55 int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { 56 if (!is_component_enabled()) { 57 return apm_->kNoError; 58 } 59 60 assert(audio->samples_per_split_channel() <= 160); 61 62 const int16_t* mixed_data = audio->low_pass_split_data(0); 63 if (audio->num_channels() > 1) { 64 audio->CopyAndMixLowPass(1); 65 mixed_data = audio->mixed_low_pass_data(0); 66 } 67 68 for (int i = 0; i < num_handles(); i++) { 69 Handle* my_handle = static_cast<Handle*>(handle(i)); 70 int err = WebRtcAgc_AddFarend( 71 my_handle, 72 mixed_data, 73 static_cast<int16_t>(audio->samples_per_split_channel())); 74 75 if (err != apm_->kNoError) { 76 return GetHandleError(my_handle); 77 } 78 } 79 80 return apm_->kNoError; 81 } 82 83 int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { 84 if (!is_component_enabled()) { 85 return apm_->kNoError; 86 } 87 88 assert(audio->samples_per_split_channel() <= 160); 89 assert(audio->num_channels() == num_handles()); 90 91 int err = apm_->kNoError; 92 93 if (mode_ == kAdaptiveAnalog) { 94 capture_levels_.assign(num_handles(), analog_capture_level_); 95 for (int i = 0; i < num_handles(); i++) { 96 Handle* my_handle = static_cast<Handle*>(handle(i)); 97 err = WebRtcAgc_AddMic( 98 my_handle, 99 audio->low_pass_split_data(i), 100 audio->high_pass_split_data(i), 101 static_cast<int16_t>(audio->samples_per_split_channel())); 102 103 if (err != apm_->kNoError) { 104 return GetHandleError(my_handle); 105 } 106 } 107 } else if (mode_ == kAdaptiveDigital) { 108 109 for (int i = 0; i < num_handles(); i++) { 110 Handle* my_handle = static_cast<Handle*>(handle(i)); 111 int32_t capture_level_out = 0; 112 113 err = WebRtcAgc_VirtualMic( 114 my_handle, 115 audio->low_pass_split_data(i), 116 audio->high_pass_split_data(i), 117 static_cast<int16_t>(audio->samples_per_split_channel()), 118 analog_capture_level_, 119 &capture_level_out); 120 121 capture_levels_[i] = capture_level_out; 122 123 if (err != apm_->kNoError) { 124 return GetHandleError(my_handle); 125 } 126 127 } 128 } 129 130 return apm_->kNoError; 131 } 132 133 int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { 134 if (!is_component_enabled()) { 135 return apm_->kNoError; 136 } 137 138 if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) { 139 return apm_->kStreamParameterNotSetError; 140 } 141 142 assert(audio->samples_per_split_channel() <= 160); 143 assert(audio->num_channels() == num_handles()); 144 145 stream_is_saturated_ = false; 146 for (int i = 0; i < num_handles(); i++) { 147 Handle* my_handle = static_cast<Handle*>(handle(i)); 148 int32_t capture_level_out = 0; 149 uint8_t saturation_warning = 0; 150 151 int err = WebRtcAgc_Process( 152 my_handle, 153 audio->low_pass_split_data(i), 154 audio->high_pass_split_data(i), 155 static_cast<int16_t>(audio->samples_per_split_channel()), 156 audio->low_pass_split_data(i), 157 audio->high_pass_split_data(i), 158 capture_levels_[i], 159 &capture_level_out, 160 apm_->echo_cancellation()->stream_has_echo(), 161 &saturation_warning); 162 163 if (err != apm_->kNoError) { 164 return GetHandleError(my_handle); 165 } 166 167 capture_levels_[i] = capture_level_out; 168 if (saturation_warning == 1) { 169 stream_is_saturated_ = true; 170 } 171 } 172 173 if (mode_ == kAdaptiveAnalog) { 174 // Take the analog level to be the average across the handles. 175 analog_capture_level_ = 0; 176 for (int i = 0; i < num_handles(); i++) { 177 analog_capture_level_ += capture_levels_[i]; 178 } 179 180 analog_capture_level_ /= num_handles(); 181 } 182 183 was_analog_level_set_ = false; 184 return apm_->kNoError; 185 } 186 187 // TODO(ajm): ensure this is called under kAdaptiveAnalog. 188 int GainControlImpl::set_stream_analog_level(int level) { 189 was_analog_level_set_ = true; 190 if (level < minimum_capture_level_ || level > maximum_capture_level_) { 191 return apm_->kBadParameterError; 192 } 193 analog_capture_level_ = level; 194 195 return apm_->kNoError; 196 } 197 198 int GainControlImpl::stream_analog_level() { 199 // TODO(ajm): enable this assertion? 200 //assert(mode_ == kAdaptiveAnalog); 201 202 return analog_capture_level_; 203 } 204 205 int GainControlImpl::Enable(bool enable) { 206 CriticalSectionScoped crit_scoped(crit_); 207 return EnableComponent(enable); 208 } 209 210 bool GainControlImpl::is_enabled() const { 211 return is_component_enabled(); 212 } 213 214 int GainControlImpl::set_mode(Mode mode) { 215 CriticalSectionScoped crit_scoped(crit_); 216 if (MapSetting(mode) == -1) { 217 return apm_->kBadParameterError; 218 } 219 220 mode_ = mode; 221 return Initialize(); 222 } 223 224 GainControl::Mode GainControlImpl::mode() const { 225 return mode_; 226 } 227 228 int GainControlImpl::set_analog_level_limits(int minimum, 229 int maximum) { 230 CriticalSectionScoped crit_scoped(crit_); 231 if (minimum < 0) { 232 return apm_->kBadParameterError; 233 } 234 235 if (maximum > 65535) { 236 return apm_->kBadParameterError; 237 } 238 239 if (maximum < minimum) { 240 return apm_->kBadParameterError; 241 } 242 243 minimum_capture_level_ = minimum; 244 maximum_capture_level_ = maximum; 245 246 return Initialize(); 247 } 248 249 int GainControlImpl::analog_level_minimum() const { 250 return minimum_capture_level_; 251 } 252 253 int GainControlImpl::analog_level_maximum() const { 254 return maximum_capture_level_; 255 } 256 257 bool GainControlImpl::stream_is_saturated() const { 258 return stream_is_saturated_; 259 } 260 261 int GainControlImpl::set_target_level_dbfs(int level) { 262 CriticalSectionScoped crit_scoped(crit_); 263 if (level > 31 || level < 0) { 264 return apm_->kBadParameterError; 265 } 266 267 target_level_dbfs_ = level; 268 return Configure(); 269 } 270 271 int GainControlImpl::target_level_dbfs() const { 272 return target_level_dbfs_; 273 } 274 275 int GainControlImpl::set_compression_gain_db(int gain) { 276 CriticalSectionScoped crit_scoped(crit_); 277 if (gain < 0 || gain > 90) { 278 return apm_->kBadParameterError; 279 } 280 281 compression_gain_db_ = gain; 282 return Configure(); 283 } 284 285 int GainControlImpl::compression_gain_db() const { 286 return compression_gain_db_; 287 } 288 289 int GainControlImpl::enable_limiter(bool enable) { 290 CriticalSectionScoped crit_scoped(crit_); 291 limiter_enabled_ = enable; 292 return Configure(); 293 } 294 295 bool GainControlImpl::is_limiter_enabled() const { 296 return limiter_enabled_; 297 } 298 299 int GainControlImpl::Initialize() { 300 int err = ProcessingComponent::Initialize(); 301 if (err != apm_->kNoError || !is_component_enabled()) { 302 return err; 303 } 304 305 capture_levels_.assign(num_handles(), analog_capture_level_); 306 return apm_->kNoError; 307 } 308 309 void* GainControlImpl::CreateHandle() const { 310 Handle* handle = NULL; 311 if (WebRtcAgc_Create(&handle) != apm_->kNoError) { 312 handle = NULL; 313 } else { 314 assert(handle != NULL); 315 } 316 317 return handle; 318 } 319 320 void GainControlImpl::DestroyHandle(void* handle) const { 321 WebRtcAgc_Free(static_cast<Handle*>(handle)); 322 } 323 324 int GainControlImpl::InitializeHandle(void* handle) const { 325 return WebRtcAgc_Init(static_cast<Handle*>(handle), 326 minimum_capture_level_, 327 maximum_capture_level_, 328 MapSetting(mode_), 329 apm_->proc_sample_rate_hz()); 330 } 331 332 int GainControlImpl::ConfigureHandle(void* handle) const { 333 WebRtcAgc_config_t config; 334 // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we 335 // change the interface. 336 //assert(target_level_dbfs_ <= 0); 337 //config.targetLevelDbfs = static_cast<int16_t>(-target_level_dbfs_); 338 config.targetLevelDbfs = static_cast<int16_t>(target_level_dbfs_); 339 config.compressionGaindB = 340 static_cast<int16_t>(compression_gain_db_); 341 config.limiterEnable = limiter_enabled_; 342 343 return WebRtcAgc_set_config(static_cast<Handle*>(handle), config); 344 } 345 346 int GainControlImpl::num_handles_required() const { 347 return apm_->num_output_channels(); 348 } 349 350 int GainControlImpl::GetHandleError(void* handle) const { 351 // The AGC has no get_error() function. 352 // (Despite listing errors in its interface...) 353 assert(handle != NULL); 354 return apm_->kUnspecifiedError; 355 } 356 } // namespace webrtc 357